rockspec_format = '3.0' package = 'tnt-outbox' version = 'scm-1' source = { url = 'git+https://github.com/tnt-skein/tnt-outbox.git', branch = 'main', } description = { summary = 'Ящик исходящих для Tarantool: событие одной транзакцией с данными, отправка отдельно', detailed = [[ «Сохранили и отправили» двумя действиями теряет событие при обрыве между ними, и потеря тихая: данные есть, события нет, и узнать об этом неоткуда. Ящик делает два действия одним: outbox.write кладёт событие строкой спейса в той же транзакции, что и данные, откат уносит обоих, фиксация оставляет обоих. Отдельный вывоз на узле для записи отправляет строки по порядку ключа назначенным отправителем — таблицей с send(name, body, opts), которая приходит аргументом настройки, — и удаляет отправленные. Отправляется только зафиксированное: отметку ставит box.on_commit записи, а лежавшее до запуска открывает барьер поколения, поэтому строку транзакции, которая ещё ждёт записи или кворума, вывоз не отправит. Опознаватель ULID и заголовки контекста ставит запись, и повторная отправка несёт те же. Повторяемый отказ оставляет строку на месте и откладывает вывоз растущим отступом, неповторяемый уводит её в outbox_dead, откуда outbox.kick после починки отправителя возвращает её в хвост ящика с тем же опознавателем. Гарантия — хотя бы раз. Повтор отсекает получатель модулем tnt.outbox.inbox: inbox.claim ставит отметку «получатель, id сообщения» в транзакции обработчика и отвечает false на повтор; откат снимает отметку вместе с записью обработчика. Отметки старше срока хранения — по умолчанию неделя — стирает уборка на узле для записи, кусками с уступкой. Ящик виден в выкладке метрик своими рядами: outbox_depth — сколько строк ждёт вывоза и сколько зарыто, outbox_oldest_seconds — сколько ждёт голова, главный ряд тревоги, outbox_sent_total и outbox_dead_total по назначению. Зависит от tnt-message (проверка настроек записи и тела, заголовки контекста — общие для очередей договора), tnt-must (проверки аргументов), tnt-clock (время записи, отметки и планировщика), tnt-id (опознаватель), tnt-log (журнал), tnt-loop (такты вывоза и уборки), tnt-retry (отступ после отказа), tnt-metrics (ряды) и tnt-external (подмена транзакции, спейсов и часов в проверках). Покрытие строк и убитых мутантов — 100 %. ]], homepage = 'https://github.com/tnt-skein/tnt-outbox', issues_url = 'https://github.com/tnt-skein/tnt-outbox/issues', maintainer = 'tnt-skein', license = 'MIT', labels = { 'tarantool', 'outbox', 'transactional-outbox', 'messaging', 'events', 'at-least-once' }, } dependencies = { 'lua >= 5.1', -- Настройки записи и тело по договору очереди, заголовки контекста, -- которые запись кладёт в строку. 'tnt-message', -- Проверки настроек ящика и отметок, имён назначения и получателя -- и числа зарытых на строке вызывающего. 'tnt-must', -- Стенное время записи и отметки, время планировщика для отступа. 'tnt-clock', -- Опознаватель ULID сообщения. 'tnt-id', -- Записи о зарытом, отложенном вывозе и сорвавшемся такте. 'tnt-log', -- Такт вывоза и такт уборки отметок получателя. 'tnt-loop', -- Отступ после повторяемого отказа отправителя. 'tnt-retry', -- Ряды ящика в реестре встроенного metrics. 'tnt-metrics', -- Подмена транзакции, спейсов, часов и режима узла в проверках. 'tnt-external', } build = { type = 'builtin', modules = { ['tnt.outbox'] = 'tnt/outbox.lua', ['tnt.outbox.commit'] = 'tnt/outbox/commit.lua', ['tnt.outbox.inbox'] = 'tnt/outbox/inbox.lua', ['tnt.outbox.message'] = 'tnt/outbox/message.lua', ['tnt.outbox.series'] = 'tnt/outbox/series.lua', ['tnt.outbox.shipper'] = 'tnt/outbox/shipper.lua', ['tnt.outbox.space'] = 'tnt/outbox/space.lua', }, }