- разведка storage-without-pocketbase: шесть ролей библиотеки в этом коде, отпавший довод перевода, шесть модулей достижимы только через неё - ADR-2026-08-22-storage-without-pocketbase заменяет три записи: перевод в PocketBase, очередь коллекцией, файл за защищённым полем - задача storage-without-pocketbase встала первой строкой плана стройки
5.2 KiB
Очередь остаётся своей таблицей, но коллекцией PocketBase
- Дата: 2026-08-11
- Источник: ../research/job-queue.md — записка
разведки
job-queue-choice - Статус: заменено на ADR-2026-08-22-storage-without-pocketbase
Решение
Очередь задач остаётся своей таблицей и становится коллекцией PocketBase: захват
идёт одним запросом с RETURNING, число попыток лежит колонкой, нарастающая
пауза выражается существующим delay_time, а исчерпавшая попытки задача
переходит в состояние «мертва» вместо сегодняшнего is_error = 1. Готовую
библиотеку очереди не берём.
Почему
Разведка искала готовую очередь и нашла, что для PocketBase её нет:
Единственная очередь в списке —
pocketbase-queue, написана на TypeScript и работает из JS-хуков; из Go её не подключить.
Отсюда разрез, который и решил дело:
выбор идёт не между готовым и своим, а между своим в коллекции PocketBase и чужой очередью, живущей рядом с PocketBase и мимо её панели. River и goqite про PocketBase не знают.
Главный довод в пользу чужой библиотеки — транзакционный захват — снялся замером:
движок за
modernc.org/sqlitev1.55.0 — версии 3.53.3,RETURNINGв нём есть, и на трёх горутинах разом запись получила ровно одна. Это снимает главный довод в пользу чужой библиотеки: транзакционность захвата покупается одной строкой запроса, а не новой зависимостью.
Отвергнуты два кандидата, и оба с названной ценой:
River с драйвером SQLite — покупает повторы, счётчик и мёртвых готовыми, но выносит очередь из панели PocketBase, ради которой хранилище и переезжает, и переписывает конвейер в цепочку задач.
goqite — не отвечает ни на один из трёх вопросов задачи целиком, а его предел выдач молча теряет запись.
Запись попадает в журнал как намеренный отказ от очевидного подхода: взять готовую библиотеку вместо своего кода — первое, что предлагают на такой вопрос, и без записанной причины его предложат снова. Принцип «очередь таблицей» из ../architecture.md этим решением подтверждён, а не пересмотрен, поэтому парного статуса «заменено на» никакая запись не получает.
Последствия
+очередь видна и правится в панели администратора: мёртвая задача повторяется снятием состояния, а не запросом в консоли сервера. Ровно за это и куплен перевод хранилища на PocketBase (ADR-2026-08-11-pocketbase-storage-with-admin-panel).+ни одной новой зависимости: River добавил бы 46 пакетов в сборку, goqite — 3.+захват перестаёт быть двумя запросами без транзакции, и это перестаёт быть местом, которое держится на том, что три воркера читают три разных состояния.−повторы, счётчик попыток и очередь мёртвых пишем сами, и корректность захвата наша. Проверяется это тестами задачиpocketbase-storage, а не чужим набором проверок.−захват идёт сырым запросом мимо записей PocketBase: хуки коллекции на нём не срабатывают, и поле времени изменения проставляет наш код.−приборной панели очереди — числа ждущих, упавших, среднего времени — не появляется. Смотрим таблицу коллекции в панели PocketBase, отбирая фильтром.