Событие публикуется с задержкой после изменения состояния. Как контракт должен различать время бизнес-факта и время доставки события?
Контракт должен явно разделять время возникновения бизнес-факта и время публикации или доставки события. Поле времени бизнес-факта должно фиксироваться в момент подтверждения изменения состояния и оставаться неизменным при задержках, повторах и повторной публикации.
В распределённых системах изменение состояния и доставка события обычно происходят не одновременно. Очереди, повторные попытки, временная недоступность потребителя и пакетная публикация создают задержку между этими моментами.
Если контракт содержит только одно неясно названное поле времени, разные потребители начинают трактовать его по-разному. Разделение времён появилось как способ сохранить смысл бизнес-события независимо от особенностей транспорта.
Предположим, заказ был оплачен в 10:00, но событие стало доступно потребителю в 10:03. Если поле времени отражает момент публикации, аналитика может ошибочно считать оплату совершённой в 10:03, а правила обработки просроченных операций — принять неверное решение.
Повторная доставка усугубляет проблему: время получения будет различаться у каждой попытки, хотя бизнес-факт произошёл один раз. Интеграционный тест должен отличать задержку доставки от изменения времени самого события.
Контракт должен определить обязательное поле, например occurredAt, со смыслом: момент, когда произошёл бизнес-факт. Нужно также зафиксировать точную точку его измерения — например, успешную фиксацию изменения состояния в системе-источнике. Это значение не должно пересчитываться при публикации, маршрутизации или повторной доставке.
Если потребителю действительно нужен момент отправки, его следует описать отдельным полем, например publishedAt. Эти поля должны иметь однозначный формат, обычно абсолютный момент времени с указанием временной зоны или в формате UTC; нельзя полагаться на локальное время сервера.
Проверка должна создать или инициировать бизнес-факт в известный момент, искусственно задержать публикацию и убедиться, что occurredAt сохраняет время факта. При повторной доставке значение также должно оставаться прежним. Проверка точного времени публикации требует управляемых часов или допуска по времени, поскольку сетевые задержки делают сравнение до миллисекунды хрупким.
Наличие времени факта не заменяет гарантии порядка событий. Если потребителю нужен порядок, контракт должен отдельно определить правило упорядочивания: версию агрегата, последовательный номер или другой явно заданный признак. Одно только сравнение временных меток не всегда надёжно из-за рассинхронизации часов и одновременных операций.
Минимальный пример содержимого события:
Здесь occurredAt используется для бизнес-логики и аналитики, а publishedAt — для анализа задержки доставки. Если публикация произошла сразу и отдельное поле не нужно, это должно быть явно закреплено контрактом, а не оставлено на усмотрение потребителей.
Сервис заказов публиковал событие оплаты через очередь. Во время нагрузки очередь задерживала сообщения на несколько минут, и сервис рассрочки использовал единственную временную метку события для расчёта срока оплаты. В результате часть заказов считалась оплаченной позже фактического момента.
Рассматривались три варианта. Можно было использовать время получения сообщения, но оно зависело от нагрузки и повторных доставок. Можно было заставить каждый потребитель самостоятельно восстанавливать время по журналам, однако это создавало разные трактовки и сильную связанность с внутренними данными поставщика. Третий вариант — передавать в событии неизменяемое время бизнес-факта и отдельно, при необходимости, время публикации.
Выбрали третий вариант: источник записывал occurredAt при фиксации оплаты, а издатель добавлял publishedAt непосредственно перед отправкой. Интеграционный тест моделировал задержку и повторную доставку и проверял неизменность времени факта. Это устранило ошибки расчёта и одновременно позволило измерять задержку очереди.
Нет, если поле участвует в бизнес-правилах, аналитике или аудите. Даже небольшая обычно наблюдаемая задержка не является контрактной гарантией: нагрузка, повторная отправка или временный сбой могут изменить её на минуты или часы. Время публикации допустимо использовать только для задач транспорта, например мониторинга задержки.
Нет. Формат устраняет неоднозначность представления, но не гарантирует порядок бизнес-операций. Часы разных узлов могут быть рассинхронизированы, а два события могут иметь одинаковое или почти одинаковое время. Для строгого порядка нужен отдельный контрактный признак, например монотонная версия состояния конкретного агрегата.
Он должен проверить, что повторная доставка не меняет occurredAt и идентификатор бизнес-события, если такой идентификатор предусмотрен контрактом. Также полезно проверить, что время получения или публикации не подменяет исходное время факта. При этом идемпотентность обработки — отдельное требование: наличие корректной временной метки само по себе не делает потребителя устойчивым к повторам.