Andrey Epifancev 5ae8ff8a81 nats: subject'ы как в старом АРМ — files.*_uploaded, files.tabular_parsed (#77)
Решение владельца 08.10.2026: recognition.tabular.request → files.tabular_uploaded,
recognition.image.request → files.img_uploaded, recognition.result →
files.tabular_parsed (общий subject ack и результатов; files.img_parsed не
используется). Тела сообщений, Nats-Msg-Id, queue group'ы и schema_version не
меняются. Константы api/src/contract/subjects.py, докстринги, тесты, README,
CLAUDE.md; копии схем api/contracts/ из docs/contracts/ побайтно; change
nats-files-subjects с дельтой спеки. Сквозной change — RSHB/arm-ka-docs#74.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012vJkmBGKKqMoEMzvsXG3y2
2026-10-08 23:46:18 +04:00

4.1 KiB
Raw Blame History

MODIFIED Requirements

Requirement: Outbox публикует задания из queued

Фоновый публикатор SHALL с периодом OUTBOX_POLL_SECONDS (по умолчанию 5) выбирать задания status = queued (с блокировкой FOR UPDATE SKIP LOCKED), формировать сообщение по recognition-request.schema.json v1.0 из recognition_job ⋈ stored_file ⋈ s3_object и публиковать в subject по pipeline с заголовком Nats-Msg-Id = <job_id>:<attempt>. После успешной публикации задание SHALL получить status = published, published_at, request_msg_id, request_subject; при ошибке публикации задание SHALL остаться queued.

Scenario: Публикация запроса парсеру

  • WHEN в recognition_job вставлена строка queued с pipeline = tabular, связанная со stored_file (XLSX) и его s3_object
  • THEN в течение 10 с в files.tabular_uploaded появляется сообщение, проходящее схему запроса, с job_id, file_id, s3.key исходника, reply_deadline, attempt = 1, а строка переходит в published с заполненным request_msg_id

Scenario: NATS недоступен

  • WHEN публикация завершается ошибкой соединения
  • THEN задание остаётся queued, ошибка залогирована, следующий цикл повторяет публикацию

Requirement: Ack сервиса переводит задание в processing

Получив в files.tabular_parsed конверт со status = processing для задания в published, ядро SHALL установить status = processing, started_at, service_name, service_version и перевести файл задания в stored_file.status = PROCESSING, если current_recognition_job_id файла равен этому заданию. Повторный ack для задания в processing SHALL игнорироваться; ack для задания в другом статусе SHALL логироваться и не менять задание.

Scenario: Сервис подтвердил

  • WHEN сервис опубликовал конверт processing с job_id опубликованного задания
  • THEN задание имеет status = processing, started_at заполнен, service_name = tabular-parser, файл — PROCESSING

Requirement: Соединение с NATS по шаблону, без JetStream

Ядро SHALL подключаться к NATS с nkeys-seed и JWT, если заданы OPENBAO__NATS__NATS_SEED/NATS_JWT, и без учётных данных, если они пусты; подписываться на files.tabular_parsed в queue group arm-core; переподключаться автоматически. Stream'ы и consumer'ы JetStream MUST NOT требоваться. Фоновые задачи SHALL запускаться при NATS_ENABLED=true.

Scenario: Dev-окружение compose

  • WHEN ядро стартует с DEBUG=true, NATS_ENABLED=true и пустыми учётными данными против NATS без JetStream
  • THEN подписка активна, /healthcheck отдаёт nats = ok, в логах нет ошибок подключения

Scenario: Два инстанса ядра

  • WHEN запущены два инстанса с NATS_ENABLED=true и опубликован один результат
  • THEN результат обработан ровно одним инстансом (queue group), строка задания изменена один раз

Scenario: NATS выключен

  • WHEN NATS_ENABLED=false
  • THEN приложение стартует, фоновые задачи не запускаются, /healthcheck отвечает 200 с nats = off