ADR-014. Фоновая очередь обработки пакетов и шесть состояний

ADR Версия: 0.1 proposed

Обработку пакета (нормализация orthocover + опознание вида) запускает не оператор кнопкой, а фоновый воркер — автоматически при постановке пакета в очередь. Очередь — процессная, in-memory (канал идентификаторов + hosted-воркер с ограничением параллелизма); персистентность обеспечивает состояние пакета в БД, а не сам канал. К четырём состояниям ADR-008 добавляются два машинных: «обрабатывается» и «готов к проверке» — они снимают двойную роль «в очереди». Ручной повтор и восстановление недоделанных пакетов при рестарте сохраняются.

⟨/⟩ Исходник

1. Контекст

ADR-008 «Четыре состояния пакета и две вкладки проверки» зафиксировал у пакета четыре хранимых состояния и упразднил пять подтверждаемых этапов. Но машинную половину жизненного цикла он оставил неявной, и по мере реализации это стало мешать.

Обработка запускается вручную. По ADR_SRV_005_ImageNormalizationOrthocover нормализация кадров (и, вместе с ней, опознание вида — ADR-015 «Опознание формы и страницы кадра») выполняется синхронно по кнопке «Обработать заново». Оператор обязан помнить, что после сдачи пакета его надо ещё и запустить; до нажатия пакет лежит нетронутым.

Состояние «в очереди» перегружено. Одним значением обозначены и «ждёт, пока его возьмут в обработку», и «обработан, ждёт, пока его возьмёт оператор». Отличить их можно только по наличию нормализованных кадров — скрытый признак, из-за которого индикатор очереди (FR-009 «Очередь обработки», «чья очередь ходить») неоднозначен.

После рестарта ничего не возобновляется. Синхронная обработка живёт в рамках запроса; прерванный пакет остаётся полуобработанным без механизма подхвата.

Родственный сервис оцифровки biblioservice-dispatcher решает это иначе: пакет после отправки автоматически ставится в фоновую очередь (in-memory семафор + фоновые задачи), воркер его обрабатывает под ограничением параллелизма, а при старте приложения недоделанные пакеты (в статусах «в очереди» / «обрабатывается») переочередиваются. Переносим этот подход, адаптировав под .NET-конвейер ICD.

2. Решение

Обработка запускается автоматически. При постановке пакета в очередь (отправка из ввода) он попадает в фоновую очередь и обрабатывается воркером без действия оператора. Оператор вступает в работу уже с готовым результатом. Ручной повтор («Обработать заново») сохраняется как явная команда — для пересъёмки, правки состава кадров и отклонения вида ИК; в этих случаях пакет возвращается в очередь по команде пользователя (как требует FR-009 «Очередь обработки»), а не автоматически на каждое движение кадра.

Очередь — процессная, in-memory. Канал идентификаторов пакетов + hosted-воркер, ограниченный параллелизмом (настройка, по умолчанию 1). Сам канал не персистентен — источник истины о том, что пакет ждёт обработки, это его состояние в БД; канал лишь будит воркер. Постановка в канал выполняется после фиксации пакета в БД; воркер обрабатывает пакет в собственной единице работы, а не в контексте запроса-отправителя.

Состояний становится шесть. К прежним — в очереди, проверка, завершён, ошибка — добавляются два машинных:

Состояние Когда наступает
Обрабатывается воркер прогоняет нормализацию и опознание вида
Готов к проверке система закончила обработку, пакет ждёт оператора

Это снимает двойную роль «в очереди»: теперь «в очереди» = «ждёт воркера», «готов к проверке» = «ждёт оператора». Оба новых состояния машинные — пользователь их не подтверждает, переход происходит сам. Поэтому тезис ADR-008 «Четыре состояния пакета и две вкладки проверки» — «нет пяти подтверждаемых этапов» — сохраняется: мы делаем наблюдаемой системную половину жизненного цикла, а не возвращаем подтверждения.

Машина состояний:

в очереди ──► обрабатывается ──┬─(успех)─► готов к проверке ──► проверка ──► завершён
     ▲                          └─(вид не опознан)─► ошибка          │
     └──── ручной повтор / отклонение вида / правка состава ◄────────┘

Восстановление при старте. Пакеты в состояниях «в очереди» и «обрабатывается» переочередиваются (ставятся в канал заново); «готов к проверке» не трогаются — они уже обработаны. Управляется настройкой (локально можно отключить, чтобы не перезапускать зависшие пакеты при отладке).

3. Обоснование

Автоматический запуск убирает лишний шаг и класс ошибок «забыл обработать»: сдача пакета и есть запрос на обработку. Ручной повтор остаётся не как основной путь, а как явное действие там, где исходные данные изменились и прежний разбор недействителен, — это ровно тот случай, для которого FR-009 требует постановки в очередь командой пользователя.

Отдельные машинные состояния стоят одного дополнительного перечислимого значения на каждое, зато делают очередь честной: индикатор «чья очередь ходить» отвечает однозначно, а скрытый признак «есть ли нормализованные кадры» перестаёт нести смысл состояния. Цена — та же, что принял ADR-008: состояний по-прежнему наперечёт, переходы явные.

Очередь в памяти процесса выбрана намеренно простой. biblioservice-dispatcher показывает, что для одного инстанса связки «канал + воркер + семафор + восстановление при старте» достаточно; вводить брокер или таблицу-очередь означало бы платить за мультиинстанс, которого пока нет.

4. Следствия

Перечисление состояний расширяется до шести (PacketState): добавляются «обрабатывается» и «готов к проверке». Обновляются доменная сущность InputPacket (таблица состояний, инварианты переходов) и требование FR-009 «Очередь обработки» (индикатор и отбор — по шести состояниям).

Запуск нормализации по ADR_SRV_005_ImageNormalizationOrthocover уточняется: основной запуск — автоматический (воркер при постановке в очередь), ручной остаётся повтором. Абстракция IImageNormalizer не меняется.

Появляется инфраструктурный артефакт очереди — канал + hosted-воркер + ограничение параллелизма и хук восстановления при старте (backend-спека / инфраструктура). Хендлер отправки пакета после фиксации ставит идентификатор в канал; воркер работает в собственной единице работы.

UI очереди (FR-009 «Очередь обработки» / страница очереди) показывает новые состояния и не требует от оператора ручного запуска обработки для штатного пути.

Компромисс — один процесс. Очередь в памяти не переживает мультиинстанс: у каждого инстанса своя. Как и локальный кэш контекста в ADR_011_AbacAuthorization, вынос в общий брокер/таблицу оставлен точкой расширения на случай горизонтального масштабирования.

5. Рассмотренные альтернативы

Оставить запуск ручным (ничего не менять). Отвергнуто: сохраняется шаг «не забудь обработать» и перегруженное «в очереди»; наблюдаемости и восстановления нет.

Не вводить машинные состояния, отличать по наличию нормализованных кадров. Одно «в очереди» на оба смысла. Отвергнуто: состояние очереди становится скрытым и выводимым, а индикатор «чья очередь ходить» — неоднозначным; оператор не видит, обрабатывается пакет или уже готов.

Брокер (Redis/RabbitMQ) или таблица-очередь в БД. Отвергнуто на текущем этапе: один инстанс, in-memory + восстановление при старте достаточно (подтверждено biblioservice-dispatcher). Оставлено точкой расширения при мультиинстансе — аддитивно, без слома модели состояний.

Автозапуск без ручного повтора. Отвергнуто: пересъёмка, правка состава и отклонение вида требуют явной команды пользователя (FR-009, «Повторная обработка») — иначе каждое движение кадра запускало бы обработку заново.

Связанные артефакты

Документы

Перечисления