2026-10-09 16:22:07 +04:00

68 lines
7.6 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.

## MODIFIED Requirements
### Requirement: Передача файла в ИС Сканирование через горячие папки
После подтверждения сервис SHALL прочитать исходник из S3 (`s3.bucket/s3.key`) и записать его во входящий каталог как
`<job_id>.<ext>`, где `<ext>` — расширение `original_name` запроса в нижнем регистре; запрос без расширения SHALL
завершаться конвертом `RECOGNITION_FAILED` без записи в горячую папку. Файл SHALL записываться сразу во входящий каталог
открытием на запись с усечением, как в старом АРМ (решение владельца 09.10.2026): временных файлов, служебного каталога
и переименования нет; если `<Input>/<job_id>.<ext>` уже существует, он SHALL быть перезаписан содержимым объекта S3.
Затем сервис SHALL опрашивать исходящий каталог `<SCAN_OUTPUT_DIR>/<job_id>/` каждые `SCAN_POLL_SECONDS` до
`min(reply_deadline, старт + SCAN_TIMEOUT_SECONDS)` (`SCAN_TIMEOUT_SECONDS` по умолчанию 1200). ИС кладёт в этот каталог
все распознанные документы задания — по одному `*.json` на документ, набор появляется целиком и больше не меняется;
пустой или отсутствующий каталог означает ожидание. Ответ SHALL считаться готовым, когда в каталоге есть хотя бы один
`*.json`, а набор имён и размеров `*.json` не менялся `SCAN_SETTLE_SECONDS` (по умолчанию 2); готовый набор SHALL
включать **все** `*.json` каталога по возрастанию имени, остальные файлы игнорируются.
#### Scenario: Файл положен во входящий каталог
- **WHEN** получен запрос для `aep_5.PDF` с `job_id = 3f1c…`
- **THEN** во входящем каталоге появляется `3f1c….pdf`, байт в байт равный объекту S3; каталог `Tmp/` не создаётся, временных файлов нет
#### Scenario: Назначение уже существует
- **WHEN** запрос для `aep_5.pdf` с `job_id = 3f1c…` обрабатывается, а `Input/3f1c….pdf` уже лежит с другим содержимым (задание повторено ядром после потери ack в другом процессе)
- **THEN** `Input/3f1c….pdf` перезаписан и байт в байт равен объекту S3, задание продолжается опросом `Output/3f1c…/`, конверт `RECOGNITION_FAILED` не публикуется
#### Scenario: Запрос без расширения
- **WHEN** получен запрос с `original_name = "scan"` без точки
- **THEN** опубликован конверт `error`, `error.code = RECOGNITION_FAILED`, сообщение о расширении; во входящем каталоге файла нет
#### Scenario: Ответ из одного файла
- **WHEN** в `Output/3f1c…/` появляется один `*.json` и набор не меняется `SCAN_SETTLE_SECONDS`
- **THEN** опрос прекращается не позднее чем через `SCAN_SETTLE_SECONDS` + `SCAN_POLL_SECONDS` после первого опроса, увидевшего окончательный набор (отсчёт стабилизации — от этого опроса, а не от времени изменения файла), ответ из одного файла передаётся дальше по конвейеру
#### Scenario: Ответ из нескольких файлов
- **WHEN** в `Output/3f1c…/` лежат `3f1c….json` и `3f1c…_ofr.json`, посторонний файл `readme.txt`, и набор не меняется `SCAN_SETTLE_SECONDS`
- **THEN** дальше по конвейеру передаются оба `*.json` по возрастанию имени, `readme.txt` игнорируется
#### Scenario: Набор ещё пишется
- **WHEN** размер файла или число файлов в `Output/3f1c…/` менялось менее `SCAN_SETTLE_SECONDS` назад
- **THEN** ответ не считается готовым, опрос продолжается до дедлайна
#### Scenario: Ошибка посреди записи
- **WHEN** запись `Input/3f1c….pdf` прервалась ошибкой ввода-вывода
- **THEN** опубликован конверт `RECOGNITION_FAILED`; недописанный файл удалён только при `SCAN_CLEANUP=true`, при `false` остаётся на месте
### Requirement: Очистка горячей папки под флагом
При `SCAN_CLEANUP=true` после того, как готовый набор ответа прочитан и склеен в `raw/{job_id}.json` (независимо от
исхода нормализации), сервис SHALL удалить всё содержимое `<SCAN_OUTPUT_DIR>/<job_id>/` (json-файлы ответа и любые
прочие) и сам каталог `<job_id>`, входящий файл `<Input>/<job_id>.<ext>` и его вариант `<Input>/<job_id>.<ext>.done`,
если они существуют. При `SCAN_CLEANUP=false` (по умолчанию) сервис MUST NOT удалять ничего, включая недописанный при
ошибке записи входящий файл. При `TIMEOUT`, `FILE_READ_ERROR`, `RECOGNITION_FAILED` записи очистка MUST NOT выполняться
(при ошибке записи и `SCAN_CLEANUP=true` снимается только недописанный входящий файл). Ошибка удаления SHALL быть
записана в лог одной строкой на задание и MUST NOT менять конверт, `metrics.warnings` и `/healthcheck`.
#### Scenario: Очистка включена
- **WHEN** `SCAN_CLEANUP=true`, ответ на `3f1c….pdf` прочитан из `Output/3f1c…/`
- **THEN** после публикации конверта в горячей папке нет `Output/3f1c…/`, `Input/3f1c….pdf` и `Input/3f1c….pdf.done`
#### Scenario: Очистка выключена
- **WHEN** `SCAN_CLEANUP=false`, ответ прочитан
- **THEN** все файлы остаются на месте, сервис ничего не удаляет и не пишет в лог о очистке (решение №27)
#### Scenario: Нет прав на удаление
- **WHEN** `SCAN_CLEANUP=true`, удаление `Output/3f1c…/3f1c….json` завершается `PermissionError`
- **THEN** конверт опубликован с тем же статусом, что и без очистки; в логе одна строка об ошибке удаления; `/healthcheck.hotfolder = ok`
#### Scenario: Таймаут не чистит
- **WHEN** `SCAN_CLEANUP=true`, ответ не появился до дедлайна
- **THEN** опубликован `TIMEOUT`, входящий файл и каталог `Output/<job_id>/` (если есть) не тронуты