Доменные события
Что такое доменное событие
Заголовок раздела «Что такое доменное событие»Доменные события — это механизм развязки, который позволяет модулям общаться без прямых зависимостей. Вместо того чтобы модуль A вызывал модуль B, модуль A публикует событие, а модуль B на него подписывается.
DomainEventBus — это внутрипроцессная широковещательная шина публикации и
подписки. Издатели вызывают publish(event); подписчики получают типизированный
поток on<T>(). Каждое событие реализует DomainEvent и несёт occurredAt.
Шина работает внутри cc_server. Там живёт каждый издатель и каждый живой
подписчик. Ни один клиент эту шину не видит. Клиент видит лишь отобранное
подмножество, которое сервер повторно отправляет в виде кадров notifications/*
JSON-RPC.
Зачем вообще нужна шина
Заголовок раздела «Зачем вообще нужна шина»Без событий любая реакция одного модуля на другой — это импорт. Путь уведомлений должен был бы импортировать модуль агентов, модуль pull request, тикеты и встречи только для того, чтобы знать, когда показать всплывающее уведомление, — и каждому из них, в свою очередь, пришлось бы знать, что уведомления существуют. Тикеты импортировали бы конвейеры, чтобы завершённый тикет мог продвинуть запуск. Граф зависимостей затягивается в узел, и общее ядро перестаёт быть общим.
Публикация события разрывает этот узел. Путь уведомлений подписывается на двадцать один класс событий и не импортирует ни одного из модулей, которые их порождают. Диспетчер триггеров конвейеров подписывается на всю шину и ничего не знает о pull request, тикетах или встречах. Наблюдаемость агрегирует результаты запусков, не заглядывая в диспетчеризацию.
Плата за это привычна: издатель не может узнать, слушает ли его кто-нибудь, а
слушатель, который так и не был создан, молча бездействует.
TicketRemoteSyncHandler — постоянный пример: он объявлен, покрыт тестами и
никогда не подключается в продакшене.
Чего в шине нет
Заголовок раздела «Чего в шине нет»Стоит точно обозначить одну вещь, которой шина не владеет.
Журнал аудита — не проекция потока событий. Каждая изменяющая операция RPC
по умолчанию проходит аудит — RepoOp.audited по умолчанию имеет значение true,
и операция отказывается от аудита, только объявив audited: false, что является
осознанным действием, видимым в самой операции. Диспетчер добавляет строку «кто
что сделал и откуда» сразу после успешного вызова. Никакого
DomainEventAuditBridge нет. ActivityLogPersister записывает строки
activity_log из событий ActivityLogged; это отдельный поток, не связанный с
аудитом RPC.
Шина событий является транспортом для уведомлений и для автоматизации. Но она не система учёта, хранящая эталонные записи.
Что шина всё-таки приводит в движение
Заголовок раздела «Что шина всё-таки приводит в движение»- Уведомления. Сервер превращает двадцать один класс событий в кадры
notifications/*, записывает их в долговечную ленту каждого рабочего пространства и транслирует подключённым сессиям. Кадр, в чьёмworkspace_idуказано рабочее пространство, участником которого пользователь сессии не является, отбрасывается на сервере; затем клиент фильтрует оставшиеся кадры по тому рабочему пространству, которое просматривает. - Автоматизация по событиям. Триггеры конвейеров подписываются на шину и автоматически запускают подходящие конвейеры (см. ниже).
- Реакции жизненного цикла. Создание рабочего пространства заводит агентов CEO и специалистов, встроенные шаблоны конвейеров и стартовые сьюиты eval. Завершённый запуск агента возобновляет приостановленный шаг конвейера, закрывает задачу, питает супервизор целей, может разбудить именованного проверяющего и может заново запустить лидера команды. Смерженный PR или удалённое пространство запускает сборку мусора рабочих деревьев.
- Синхронизация между вендорами. Локальные изменения тикетов отправляются настроенным вендорам координатором, который слушает пять событий тикетов.
Категории событий
Заголовок раздела «Категории событий»События охватывают всю поверхность продукта. В общих чертах:
- Рабочие пространства, агенты и репозитории — создание рабочего пространства, завершение запуска, регистрация репозитория, обновления навыков
- Pull requests — публикация, изменения статуса, слияния, запросы на проверку, упоминания, отслеживание созданных вами PR, обнаруженные извне PR
- Сообщения — сообщения, пространства и ход подготовки пространств
- Тикеты — создание, назначение, переназначение, детали, статус и три терминальных исхода
- Задачи — упорядоченные кадры жизненного цикла одного запуска, чтобы клиенты могли их упорядочивать и устранять дубликаты
- Конвейеры — только терминальные события запусков (завершён, отменён, не выполнен)
- Наблюдаемость — записи журнала активности и пороги бюджета
- Идентичность и членство — участник добавлен, удалён, роль изменена
- Календарь и встречи — истечение авторизации, начало встреч и завершение записей
- Rigs — перехват, сбор и неожиданное закрытие
Память, оркестрация, документы планов, артефакты, согласования, приём синхронизации тикетов, обновление календаря, слияния рабочих деревьев, создание пользователей, приглашения и отзыв устройств не являются доменными событиями; см. справку.
Полный каталог — все 53 конкретных класса событий, их полезные нагрузки и 24 подписчика, которые их потребляют, — см. в справочнике по доменным событиям. Та страница — инвентарь, эта — модель.
Контроль доступа в реальном времени опирается на два разных механизма
Заголовок раздела «Контроль доступа в реальном времени опирается на два разных механизма»События членства и события устройств выглядят симметрично, но таковыми не являются, и это важно, если вы рассуждаете о том, как быстро отзыв вступает в силу.
Отзыв устройства действительно завершает его сессии. Сервер следит за таблицей привязанных устройств и в течение нескольких секунд отключает любую активную сессию, устройство которой покинуло активный набор.
Удаление участника не закрывает сокет. Событие WorkspaceMemberRemoved
обрабатывается: LocalRpcServer и RemoteRelayHost снимают подписки этого
пользователя на рабочее пространство, а RemoteEventForwarder инвалидирует свой
кеш членства, чтобы дальнейшие кадры для этого рабочего пространства не
отправлялись. Следующий вызов RPC отклоняет по-прежнему ролевой шлюз, который
заново определяет членство при каждом вызове, — поэтому их следующий запрос
отклоняется с сообщением «Not a member of this workspace». Эффект наступает
немедленно для всего, что они попытаются сделать; просто он достигается не
разрывом их соединения.
Триггеры конвейеров
Заголовок раздела «Триггеры конвейеров»Триггеры конвейеров подписываются на доменные события и автоматически запускают
подходящие конвейеры. PipelineTriggerDispatcher слушает всю шину, а затем:
- Завершается досрочно, если тип события не относится к тем, которые он умеет преобразовывать в полезную нагрузку
- Ищет включённые триггеры, соответствующие этому типу события, по всем рабочим пространствам
- Отбирает каждый по его собственному рабочему пространству и применяет его фильтр совпадения полезной нагрузки
- Стартует запуск для каждого триггера, который прошёл отбор
Важное ограничение — шаг 1. Шина несёт 53 типа событий; список выбора при
добавлении триггера позволяет запускать конвейер только для этих четырнадцати
(EventPayloadMapper, ветки полезной нагрузки):
ExternalPrDetected, PullRequestPublished, PullRequestStatusChanged,
PrMerged, MessageReceived, TicketAssigned,
TicketCompleted, TicketFailed, TicketCancelled,
BudgetThresholdCrossed, RepoAdded, MeetingRecordingStopped, SkillUpdated
и SpaceDeleted. Больше ничего не может запустить конвейер.
Как клиент всё это видит
Заголовок раздела «Как клиент всё это видит»RemoteEventForwarder преобразует события класса уведомлений в кадры и
отправляет их по RPC подключённым сессиям, где преобразователь кадров
превращает их в уведомления внутри приложения. Таким образом, тонкий клиент
видит проекцию потока событий сервера, не выполняя ничего сам, — в этом и смысл
разделения с тонким клиентом.
Однако не каждый отправленный кадр — уведомление. Поток жизненного цикла задач и переназначение тикетов передаются в реальном времени для управления интерфейсом, но они не записываются в ленту уведомлений и не показывают всплывающих уведомлений.
См. также
Заголовок раздела «См. также»- Конвейеры и автоматизация: что запускает триггер
- Тикеты и делегирование: назначение агенту или команде
- Архитектура: как события вписываются в правило зависимостей
- Справочник по доменным событиям: полный каталог и его подписчики
- Настроить триггеры конвейера
- Настроить уведомления