docs: решено оставить очередь своей таблицей коллекцией PocketBase

- заведены записка разведки job-queue-choice и ADR: готовые библиотеки River и
  goqite отвергнуты, захват сворачивается в один запрос с RETURNING
- в architecture.md уточнён принцип «очередь таблицей» и закрыт открытый вопрос
  «Очередь», кроме холостого опроса
- задача pocketbase-storage забрала очередь себе: границы, счётчик попыток,
  состояние «мертва» и оракулы
This commit is contained in:
av
2026-08-11 14:13:27 +03:00
parent 6c996209b7
commit df65eb5e32
7 changed files with 248 additions and 20 deletions
+24 -9
View File
@@ -2,7 +2,7 @@
- **Тип:** chore
- **Категория:** Очередь
- **Зачем:** Записи, метаданные и файлы лежат порознь, и владелец не видит их ничем, кроме консоли на сервере: панель PocketBase покажет и то и другое, только если они переедут к ней.
- **Зачем:** Записи, метаданные и файлы лежат порознь, и владелец не видит их ничем, кроме консоли на сервере: панель PocketBase покажет их, только если они переедут к ней. Заодно переписывается захват задачи: сегодня это два запроса без транзакции, а падающая всегда задача падает вечно.
PocketBase встраивается библиотекой в тот же бинарник и приносит хранилище,
учётные записи и панель администратора разом. Конвейер и оба входа работают
@@ -20,12 +20,22 @@ PocketBase встраивается библиотекой в тот же бин
Данные не переносим — база заводится с чистого листа, и это решение принято
сознательно.
**Очередь переписывается тем же заходом.** Разведка `job-queue-choice` 2026-08-11
[отвергла готовые библиотеки](../../docs/adr/ADR-2026-08-11-queue-as-pocketbase-collection.md):
очередь остаётся своей таблицей, но становится коллекцией PocketBase. Захват
сворачивается в один запрос с `RETURNING`, число попыток ложится колонкой,
нарастающая пауза выражается существующим `delay_time`, а исчерпавшая попытки
задача переходит в состояние «мертва» вместо `is_error = 1`. Сравнение
кандидатов — [docs/research/job-queue.md](../../docs/research/job-queue.md).
## Затрагивает
- таблицы `files` и `transcribe_jobs`, каталог `migrations/` и весь механизм
goose;
- `internal/adapter/repo/sqlite` целиком, включая захват задачи через
`FindAndAcquire`;
- состав колонок очереди: прибавляется число попыток, а `is_error` уступает
место состоянию «мертва» в перечне состояний задачи;
- `internal/contract`, интерфейсы `FileRepository` и `TranscriptJobRepository`;
- ключ конфигурации `[database] path`, ключ `[storage] path` и раскладка
каталога `data/`;
@@ -47,14 +57,19 @@ PocketBase встраивается библиотекой в тот же бин
- Сервис поднимается на чистом каталоге данных, накатывает свою схему сам и
принимает запись обоими входами. Оракул — запуск на пустом `data/` и прогон
записи из Telegram и через `POST /api/audio` до состояния `done`.
- Захват задачи воркером не выдаёт одну запись двум вызывающим. Оракул — тест
на трёх параллельных вызовах захвата по одному состоянию: ровно один
получает запись.
- Задача, брошенная на середине, достаётся снова по истечении срока захвата.
Оракул — тест с проставленным задним числом `acquire_time`.
- Принятая запись видна в панели строкой и скачивается из неё файлом. Оракул —
прогон записи через `POST /api/audio` на пустом каталоге, затем запрос
`/api/files/...` за тем же файлом: длина совпадает с загруженной.
- Захват задачи воркером идёт одним запросом и не выдаёт одну запись двум
вызывающим. Оракул — тест на трёх параллельных вызовах захвата по одному
состоянию: ровно один получает запись.
- Задача, брошенная на середине, достаётся снова по истечении срока захвата, а
падающая всегда — уходит в «мертва» и из выборки исчезает. Оракулы — тест с
проставленным задним числом `acquire_time` и тест с шагом, падающим на каждой
попытке: после заданного их числа задача не выдаётся, а её состояние видно
отбором.
- Принятая запись видна в панели строкой и скачивается по ссылке
`/api/files/...` тем же файлом. Оракулы — прогон записи через
`POST /api/audio` на пустом каталоге, затем поиск её строки в коллекции задач
на `/_/` по идентификатору и запрос `/api/files/...` за тем же файлом: длина
совпадает с загруженной.
- `docs/database.md` описывает новую схему, а старые упоминания goose и goqu из
документов канона убраны. Оракул — `task gate`, шаг `docs.py check`.