Руководство · how-to

Как синхронизировать две системы, не испортив ни одну

Две копии одной записи рано или поздно разойдутся, и расхождение почти всегда молчаливое. Кому принадлежит каждое поле, как разорвать эхо между системами, как переносить удаления и почему сверка должна быть регулярной, а не посмертной.

Автор stackzen-desk · Editorial reviews deskОбновлено 3 сентября 2026 г.

Проблема не в одном соединении, а в двух копиях

Связать две системы — работа на утро. Удерживать их в согласии год — другая работа, и она и есть тема этого материала. Как только один и тот же клиент, заказ или контакт существует в двух местах, разница между ними становится вашей и растёт тихо: ошибок нет, обе системы выглядят здоровыми, и одна из них неправа.

Речь не о том, что вторая сторона меняет API у вас под ногами, — это отдельная задача, — и не о выборе инструмента автоматизации. Считайте, что соединение работает, а точки стоят на месте. Вопрос здесь в том, что происходит с данными.

Решите, кому принадлежит поле, а не запись

Владение на уровне записи — первый ответ, к которому тянутся команды, и он редко переживает встречу с бизнесом. На практике маркетинговая система владеет согласием на рассылку, биллинг — тарифом, поддержка — последним обращением, и все три хранят копию адреса почты. Пропишите владение по полям, потому что спорить об этом становится только тяжелее по мере того, как данные копятся с обеих сторон.

Там, где у поля действительно два автора, выберите правило и произнесите его вслух. «Побеждает последняя запись» — законный выбор, но именно выбор: он опирается на часы, которыми вы не управляете, и молча выбрасывает одну из двух правок. Альтернатива, которую рассматривают реже, чем стоило бы, — отказаться решать: сохранить оба значения и показать конфликт человеку. Настоящих конфликтов почти всегда меньше, чем боятся команды, и горстка помеченных строк в неделю дешевле порчи, которую неверное автоматическое правило успевает натворить за ту же неделю.

Одно направление — конвейер, два — петля

Односторонняя синхронизация ведёт себя как конвейер. Двусторонняя добавляет опасность, не принадлежащую ни одной из систем по отдельности: изменение, записанное вами во вторую систему, порождает от неё уведомление, коннектор послушно пишет его обратно в первую, та уведомляет, и круг замыкается. Иногда это затухает. Иногда крутится, пока не упрётся в ограничение частоты, и журналы обеих систем заполняются обновлениями раз в несколько секунд, сделанными никем.

Петлю разрывают механизмом, а не аккуратностью. Помечайте записи, которые делает ваш коннектор, и игнорируйте порождённые ими уведомления — через отдельного интеграционного пользователя, чьи изменения вы пропускаете, или через отметку только что выполненной записи. Сравнивайте перед записью и пропускайте, если значение уже такое, каким вы собирались его сделать: одна эта проверка дёшево снимает большую часть эха. И примите, что двусторонняя синхронизация стоит дороже двух односторонних, — хороший повод спросить, нужно ли второе направление вообще.

Ломается всё на удалениях

Большинство синхронизаций строят и проверяют на создании и обновлении, а с удалениями они знакомятся в продакшене. Сложность в том, что отсутствие неоднозначно. Записи нет в сегодняшнем ответе — её могли удалить или заархивировать, она могла выйти за границы вашего фильтра, скрыться из-за изменившихся прав или отсутствовать потому, что не загрузилась страница результатов. Считать всё это командой на удаление — так синхронизация и опустошает таблицу.

Предпочитайте явный сигнал выведенному отсутствию: событие удаления, поле статуса, надгробную запись, которую поставщик какое-то время хранит. Если выводить приходится, делайте это медленно: требуйте, чтобы записи не было более чем в одном полном проходе, никогда не действуйте по неполной или ошибочной выборке и ставьте потолок на число удалений за один прогон, потому что прогон, предлагающий убрать половину таблицы, — это ошибка, а не удачный день.

Отдельно решите, что удаление на одной стороне означает на другой. Чаще всего это не «удалить»: отписка контакта в одной системе редко значит стереть его в системе учёта. Удаляйте мягко у себя, храните то, что обязаны хранить, и помните: единственный случай, где распространение должно быть настоящим и быстрым, — это запрос на удаление персональных данных, а он юридическая обязанность, а не предпочтение в настройках.

Инкрементальная синхронизация уплывает, поэтому сверяйтесь по расписанию

Любая инкрементальная синхронизация что-то теряет. Вебхук не доставлен, задача умерла между чтением и записью, запись отредактировали ровно в тот момент, когда мимо шёл ваш курсор, обновление пришло с меткой времени чуть раньше сохранённой границы. Каждое по отдельности редкость. За месяцы и на объёме случается всё, и ничего из этого о себе не сообщает.

Лекарство — полное сравнение по расписанию, а не то, что запускают после того, как кто-то заметил. Начните с дешёвого: количества с обеих сторон, затем количества по срезам, затем контрольная сумма по важным полям, и только расхождения тянуть подробно. Отчитывайтесь о расхождении как о числе, за которым вы наблюдаете во времени, а не как об инциденте, который объявляют: небольшая устойчивая величина — нормальное состояние работающей синхронизации, и полезная тревога это изменение её формы, а не сам факт различия. Чините автоматически только в сторону поля с ясным владельцем: починка поля с двумя авторами тем же правилом, которое породило расхождение, превращает несоответствие в петлю.

Первичная заливка ведёт себя иначе, чем обычный режим

Первая загрузка — это не та же синхронизация, только быстрее. Обычно она идёт через другие точки с другими лимитами, приходит без осмысленного порядка и работает часами рядом с живым потоком изменений по тем же записям, поэтому интересна как раз коллизия: заливка записывает старую версию поверх более свежего изменения, пришедшего во время её работы, и данные будто тихо едут назад. Делайте каждую запись идемпотентной, с ключом по идентификатору источника, а не по порядку прибытия, отказывайтесь перезаписывать запись версией старее той, что у вас есть, отмечайте прогресс, чтобы прерванный прогон продолжался, а не начинался заново, и первую заливку делайте на копии: ошибки этого этапа делаются сразу в объёме.

Показывайте расхождение вместо того, чтобы решать его незаметно

Худший исход — не упавшая синхронизация, а та, что успешно делает неправильное, пока все панели зелёные. Всё, что коннектор не смог применить — отклонённая запись, конфликт, нераспознанное значение, пропущенная строка, — должно попадать туда, куда человек заглянет, с контекстом, достаточным для действия, и с возможностью повторить после устранения причины. Очередь недоставленного, которую никто не открывает, — это авария с лучшими манерами.

Состояние синхронизации делают читаемым два числа: насколько она отстаёт прямо сейчас и сколько записей сейчас расходится. Показывайте их там, где их увидит владелец данных, а не только в инженерной панели: человек, способный сказать, какое значение верное, редко тот же, кто смотрит на глубину очереди.

Ещё гайды