В Сбер2B Онлайн-Продажи мы развиваем интеграцию интернет-магазинов с МоимСкладом. Обычно она работает незаметно для пользователя. Но если обмен данными нарушается, начинаются проблемы: заказы не попадают в МойСклад, товары перестают синхронизироваться, а данные расходятся между системами.
Со временем мы заметили закономерность. Большинство обращений были связаны не с ошибками в коде. Чаще всего причиной становились изменения в данных. Например, кто-то менял артикул или внешний код товара, тип цен, не сопоставлял статусы заказов или удалял товар в одной из систем. Для пользователя все эти ситуации выглядели одинаково — интеграция просто переставала работать, хотя причины каждый раз были разными.
Вот типичный пример из практики.
Клиент оформил заказ. На сайте он появился сразу, а в МоемСкладе нет. Поддержка начинает разбираться в ситуации. Через полчаса выясняется, что неделю назад кто-то переименовал один из статусов заказа. Из-за этого синхронизация перестала передавать новые заказы.
Самое неприятное в этой истории то, что никто не понимал, где именно искать ошибку. Для пользователя это выглядело как очередной необъяснимый сбой интеграции, хотя настоящая причина скрывалась в одном небольшом изменении настроек.
Для поддержки каждый такой случай превращался в ручную проверку: посмотреть настройки интеграции, изучить логи, найти этап, на котором остановился обмен, и только потом объяснить пользователю, что произошло.
Стало понятно, что главная проблема — отсутствие нормальной диагностики. Пользователь не понимал, почему интеграция перестала работать, а поддержка тратила время на поиск причины. Поэтому мы добавили в сервис диагностику, которая показывает, где именно возникла ошибка, почему она появилась и что нужно сделать, чтобы её исправить.
Что мы хотели получить
До появления диагностики и пользователь, и поддержка видели только результат: обмен выполнен или завершился ошибкой. Где именно возникла проблема, приходилось выяснять вручную — смотреть логи, проверять настройки интеграции и состояние данных в обеих системах.
Мы хотели решить сразу несколько задач:
● показать, на каком этапе остановился обмен;
● объяснить причину ошибки понятным языком, а не кодом ответа API;
● дать пользователю возможность самостоятельно исправить проблему, если это связано с настройками или данными.
Для этого диагностику разделили на три независимых раздела.
«Товары» помогают понять, корректно ли связаны сущности между интернет-магазином и МоимСкладом.
«Заказы» показывают, на каком этапе находится каждый заказ, дошёл ли он до учётной системы и почему выгрузка могла завершиться ошибкой.
«Обмены» содержат историю запусков синхронизации: когда выполнялся обмен, сколько объектов было обработано и какие ошибки возникли в процессе.
Такое разделение позволяет сразу локализовать проблему. Если товары связаны корректно, но новые заказы не выгружаются, искать причину в сопоставлении товаров уже не нужно. И наоборот — если обмен проходит успешно, а отдельные товары не синхронизируются, проблема, скорее всего, находится на уровне данных, а не механизма обмена.
Почему нельзя просто обращаться к API МоегоСклада
Первой задачей стала диагностика товаров. На первый взгляд решение кажется очевидным: при открытии страницы запросить данные через API МоегоСклада, сравнить их с магазином и показать результат. На практике такой подход быстро перестаёт работать.
Во-первых, существуют ограничения API. Во-вторых, запросы зависят от скорости сети. В-третьих, невозможно быстро выполнять сложные сопоставления между двумя разными системами. А если магазин работает с десятками или сотнями тысяч товаров, постоянные обращения к API становятся слишком дорогими.
Есть и ещё одна проблема. Между базой данных интернет-магазина и МоимСкладом нельзя выполнить привычное объединение таблиц (SQL JOIN), поэтому сравнение приходится строить иначе. Мы решили отказаться от постоянных запросов в пользу локальной проекции состояния МоегоСклада.
Вместо постоянных запросов — снимки состояния
Диагностика периодически создаёт снимок данных МоегоСклада и сохраняет только информацию, необходимую для проверки интеграции. В снимок попадают:
● Товары и Комплекты;
● Модификации;
При этом сохраняются только поля, которые действительно нужны для диагностики:
● Идентификаторы;
● Артикулы;
● Внешние коды;
● Названия;
● ссылки на связанные сущности.
Полная загрузка выполняется только один раз — при первом запуске. После этого система работает по инкрементальному принципу. Проще говоря, она получает только те записи, которые изменились после предыдущего обновления.
Интересно, что механизм снапшотов появился вовсе не для проверки данных. Изначально мы внедрили его, чтобы сократить количество обращений к API и повысить производительность. Но со временем стало понятно, что локальная проекция данных дает гораздо больше возможностей. Она позволяет выполнять сложные проверки и сравнения, которые в принципе невозможно реализовать, работая только с двумя REST API.
Для записи информации используются пакетные операции PostgreSQL через INSERT … ON CONFLICT. Вместо тысяч отдельных запросов вся страница данных обновляется одной операцией.
Сами обновления выполняются в фоне через Sidekiq. Для каждого магазина создаётся отдельная задача, а время запуска распределяется так, чтобы избежать пиковых нагрузок.
Как мы определяем, связан ли товар
После формирования снимка начинается основной этап — сопоставление товаров между двумя системами. Для пользователя вопрос всегда звучит просто: «Этот товар связан с МоимСкладом или нет?»
Но внутри интеграции вариантов гораздо больше. В зависимости от настроек связь может строиться:
● по внешнему коду;
● по артикулу;
● одновременно по двум полям.
Диагностика использует те же правила поиска, что и сама интеграция. После нахождения совпадения дополнительно проверяется идентификатор сущности, с которой фактически происходил обмен.
В результате каждый товар получает один из четырёх статусов.
Связан по внешнему коду
Самый надёжный вариант. Связь существует и полностью соответствует настройкам интеграции.
Связан по артикулу
Товар синхронизируется корректно, но такая связь менее устойчива. Если артикул изменится, интеграция может перестать находить соответствие.
Связь нарушена
Совпадение найдено, но идентификаторы расходятся. Чаще всего такую ситуацию можно исправить автоматически при следующей синхронизации.
Не связан
Товар отсутствует в одной из систем либо связь ещё не была создана. В этом случае пользователь сразу понимает, что необходимо проверить настройки или повторно выполнить синхронизацию.
Главное отличие нового подхода в том, что диагностика показывает не только наличие проблемы, но и объясняет её причину.
С заказами всё сложнее
Если товар либо связан, либо нет, то жизненный цикл заказа намного длиннее. Пользователю важно понимать:
● ушёл ли заказ в МойСклад;
● находится ли он ещё в очереди;
● завершилась ли выгрузка успешно;
● если нет — почему она остановилась.
Для этого мы реализовали несколько статусов:
● ожидает выгрузки;
● выгружен;
● ошибка.
Самым полезным изменением стало сохранение причины сбоя. Раньше пользователь видел только статус «Ошибка» и не понимал, что именно произошло. Теперь рядом отображается конкретное описание проблемы.
Чтобы диагностика оставалась быстрой даже в магазинах с сотнями тысяч заказов, используются индексированные фильтры, кэширование агрегированных данных и потоковый экспорт отчётов.
Интеграция как тоннель: история обменов помогает найти затор
Ещё одна часть диагностики показывает работу интеграции не на уровне отдельных товаров или заказов, а на уровне каждого запуска обмена. Здесь можно посмотреть:
● когда выполнялся обмен;
● сколько объектов было обработано;
● завершился ли процесс успешно;
● какие ошибки возникли во время выполнения.
При этом сохраняется не только последний запуск, а вся история обменов. Это помогает находить повторяющиеся проблемы, отслеживать стабильность интеграции и быстрее понимать, когда именно начали возникать ошибки.
От технических кодов — к понятным сообщениям
Во многих интеграциях сообщения об ошибках написаны так, словно их будет читать только разработчик. Пользователь видит что-то вроде: ValidationException или HTTP 422
Для инженера такая информация полезна. Для владельца интернет-магазина — почти бесполезна. Поэтому мы разделили технические детали и пользовательские сообщения.
Теперь каждая ошибка относится к понятной категории:
● товар не найден;
● не сопоставлены статусы заказов;
● превышен лимит товаров;
● API МоегоСклада временно недоступен;
● произошёл таймаут;
● нарушена связь между сущностями;
● обмен завершился с ошибкой.
Пользователь видит понятное описание проблемы, а подробная техническая информация продолжает сохраняться для разработчиков.
Для хранения этих данных используется тип jsonb в PostgreSQL. Он позволяет записывать дополнительные параметры ошибок без жёсткой структуры таблиц и при необходимости быстро расширять список диагностической информации.
Что изменилось после запуска диагностики
После появления нового инструмента пользователю больше не приходится гадать, что произошло с интеграцией. Теперь он может быстро ответить на три вопроса:
-
Работает ли интеграция сейчас?
-
Если нет — на каком этапе возникла проблема?
-
Можно ли исправить её самостоятельно или нужно обращаться в поддержку?
Количество обращений в поддержку из-за ошибок в настройках сократилось до нуля. Мы избавились от «белого шума»: теперь в поддержку попадают только реальные системные проблемы, которые действительно требуют доработки.
Инструмент диагностики изначально использовала только служба поддержки. Но со временем мы поняли, что он будет полезен и самим пользователям. Теперь достаточно один раз показать клиенту, где можно посмотреть ошибки, и после этого подобные обращения в поддержку, как правило, больше не возникают.
Разработчики получили меньше обращений, связанных с настройками или данными. Владельцы магазинов перестали воспринимать интеграцию как чёрный ящик, который иногда просто перестаёт работать без объяснения причин.
Вместо заключения
Полностью избавиться от ошибок в интеграциях невозможно. Слишком многое находится вне контроля разработчика: изменения данных, действия пользователей, настройки магазина, ограничения внешнего API и изменения бизнес-процессов. Поэтому мы решали другую задачу: не сделать интеграцию идеальной, а сделать её наблюдаемой и понятной.
Диагностика не гарантирует, что ошибки больше никогда не появятся. Зато она позволяет за несколько минут понять, где произошёл сбой, что стало его причиной и какие действия помогут восстановить обмен. Для любой интеграции это зачастую гораздо ценнее, чем попытка полностью исключить сами ошибки.
Самым важным результатом для нас стало даже не снижение нагрузки на поддержку.
Мы увидели, что пользователи начали самостоятельно находить и устранять причины большинства типовых проблем. Если раньше диагностика начиналась с обращения в поддержку, то теперь во многих случаях она заканчивается ещё до создания обращения. По сути, диагностика превратилась из внутреннего инструмента разработчиков в полноценный инструмент самообслуживания.
ссылка на оригинал статьи https://habr.com/ru/articles/1061266/