Files
transcriber/docs/adr/ADR-2026-08-11-queue-as-pocketbase-collection.md
T
av df65eb5e32 docs: решено оставить очередь своей таблицей коллекцией PocketBase
- заведены записка разведки job-queue-choice и ADR: готовые библиотеки River и
  goqite отвергнуты, захват сворачивается в один запрос с RETURNING
- в architecture.md уточнён принцип «очередь таблицей» и закрыт открытый вопрос
  «Очередь», кроме холостого опроса
- задача pocketbase-storage забрала очередь себе: границы, счётчик попыток,
  состояние «мертва» и оракулы
2026-08-11 14:13:27 +03:00

67 lines
5.1 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Очередь остаётся своей таблицей, но коллекцией PocketBase
- **Дата:** 2026-08-11
- **Источник:** [../research/job-queue.md](../research/job-queue.md) — записка
разведки `job-queue-choice`
## Решение
Очередь задач остаётся своей таблицей и становится коллекцией PocketBase: захват
идёт одним запросом с `RETURNING`, число попыток лежит колонкой, нарастающая
пауза выражается существующим `delay_time`, а исчерпавшая попытки задача
переходит в состояние «мертва» вместо сегодняшнего `is_error = 1`. Готовую
библиотеку очереди не берём.
## Почему
Разведка искала готовую очередь и нашла, что для PocketBase её нет:
> Единственная очередь в списке — `pocketbase-queue`, написана на TypeScript и
> работает из JS-хуков; из Go её не подключить.
Отсюда разрез, который и решил дело:
> выбор идёт не между готовым и своим, а между **своим в коллекции PocketBase** и
> **чужой очередью, живущей рядом с PocketBase и мимо её панели**. River и goqite
> про PocketBase не знают.
Главный довод в пользу чужой библиотеки — транзакционный захват — снялся
замером:
> движок за `modernc.org/sqlite` v1.55.0 — версии 3.53.3, `RETURNING` в нём
> есть, и на трёх горутинах разом запись получила **ровно одна**. Это снимает
> главный довод в пользу чужой библиотеки: транзакционность захвата покупается
> одной строкой запроса, а не новой зависимостью.
Отвергнуты два кандидата, и оба с названной ценой:
> **River с драйвером SQLite** — покупает повторы, счётчик и мёртвых готовыми, но
> выносит очередь из панели PocketBase, ради которой хранилище и переезжает, и
> переписывает конвейер в цепочку задач.
>
> **goqite** — не отвечает ни на один из трёх вопросов задачи целиком, а его
> предел выдач молча теряет запись.
Запись попадает в журнал как **намеренный отказ от очевидного подхода**: взять
готовую библиотеку вместо своего кода — первое, что предлагают на такой вопрос, и
без записанной причины его предложат снова. Принцип «очередь таблицей» из
[../architecture.md](../architecture.md) этим решением подтверждён, а не
пересмотрен, поэтому парного статуса «заменено на» никакая запись не получает.
## Последствия
- `+` очередь видна и правится в панели администратора: мёртвая задача повторяется
снятием состояния, а не запросом в консоли сервера. Ровно за это и куплен
перевод хранилища на PocketBase
([ADR-2026-08-11-pocketbase-storage-with-admin-panel](ADR-2026-08-11-pocketbase-storage-with-admin-panel.md)).
- `+` ни одной новой зависимости: River добавил бы 46 пакетов в сборку, goqite — 3.
- `+` захват перестаёт быть двумя запросами без транзакции, и это перестаёт быть
местом, которое держится на том, что три воркера читают три разных состояния.
- `` повторы, счётчик попыток и очередь мёртвых пишем сами, и корректность
захвата наша. Проверяется это тестами задачи `pocketbase-storage`, а не
чужим набором проверок.
- `` захват идёт сырым запросом мимо записей PocketBase: хуки коллекции на нём
не срабатывают, и поле времени изменения проставляет наш код.
- `` приборной панели очереди — числа ждущих, упавших, среднего времени — не
появляется. Смотрим таблицу коллекции в панели PocketBase, отбирая фильтром.