59 lines
5.7 KiB
Markdown
59 lines
5.7 KiB
Markdown
## Context
|
||
|
||
Запись входящего файла сейчас — двухфазная: `Tmp/.<имя>.part`, затем rename (SMB) / жёсткая ссылка (local) в `Input`
|
||
без замены (решения №17, №26, №32, №35 Среза 3a). Старый АРМ писал файл прямо в `Input` и в контуре работал. Владелец
|
||
09.10.2026 выбрал повторить старый АРМ и перезаписывать существующий файл.
|
||
|
||
## Goals / Non-Goals
|
||
|
||
**Goals:** прямая запись в `Input` в обоих режимах; меньше требований к правам на шаре; срок ожидания ответа 20 мин.
|
||
|
||
**Non-Goals:** см. proposal.
|
||
|
||
## Decisions
|
||
|
||
### D-1. Прямая запись с усечением (решение владельца 09.10.2026)
|
||
|
||
`SmbHotFolder.put`: `smbclient.open_file(<Input>\<имя>, mode="wb", **credentials)` и `write`. `LocalHotFolder.put`:
|
||
`open(<input>/<имя>, "wb")` (`Path.write_bytes`). Существующий файл перезаписывается. Повторная запись в рамках одного
|
||
процесса по-прежнему исключена дедупликацией по `job_id` в воркере (требование «Подтверждение запроса до обработки»);
|
||
перезапись возможна только при повторе задания ядром в другом процессе.
|
||
|
||
### D-2. Каталог `Input` создаётся, как раньше
|
||
|
||
Перед записью `Input` создаётся без родителей, «уже есть» и отказ в правах при существующем каталоге — не ошибка
|
||
(`_ensure_dir` в `smb`, `mkdir(exist_ok=True)` в `local`); корень не создаётся. Старый АРМ каталог не создавал, но
|
||
терпимое создание поведения в контуре не меняет, а dev-режим и тесты на нём держатся.
|
||
|
||
### D-3. `Tmp` остаётся только у эмулятора
|
||
|
||
`SCAN_TMP_DIR` удаляется из настроек шлюза (`Settings`, `extra="ignore"` — старое значение в `.env` не ломает старт).
|
||
Эмулятор читает свою переменную `SCAN_TMP_DIR` (`EmulatorSettings`) и собирает набор ответа через
|
||
`LocalHotFolder.tmp_dir`, поэтому параметр `tmp_dir` у `LocalHotFolder` остаётся, но `put` его не использует.
|
||
|
||
### D-4. Срок ожидания 20 мин
|
||
|
||
`SCAN_TIMEOUT_SECONDS` по умолчанию 1200. Эффективный дедлайн — `min(reply_deadline, старт + SCAN_TIMEOUT_SECONDS)`,
|
||
поэтому arm-core поднимает срок ответа OCR до 20 мин отдельным PR (RSHB/arm-core#87).
|
||
|
||
### D-5. Ошибка записи
|
||
|
||
При исключении во время открытия/записи `put` снимает недописанный `<Input>/<имя>` только при включённой очистке
|
||
(ошибка снятия подавляется, исходное исключение поднимается) — R-3.
|
||
|
||
## Risks / Trade-offs
|
||
|
||
- ИС может увидеть недописанный файл (OQ-79) → смягчение: монопольное открытие `smbclient` на время записи; так же
|
||
работал старый АРМ. Откат — вернуть двухфазную запись из истории ветки.
|
||
- Ошибка посреди записи оставляет обрезанный файл в `Input` → удаляется только при `SCAN_CLEANUP=true` (как `.part`
|
||
раньше, D-5); иначе остаётся, конверт `RECOGNITION_FAILED`.
|
||
|
||
## Decisions made without discussion
|
||
|
||
| # | Дата | Решение | Обоснование | Цена ошибки |
|
||
|---|---|---|---|---|
|
||
| R-1 | 2026-10-09 | Режим `local` тоже пишет прямо в `Input` (не только `smb`) | Одинаковая семантика режимов, один набор тестов; эмулятор пишет/читает локально мгновенно | Эмулятор может прочитать недописанный файл — на локальной ФС практически невозможно; откат — вернуть `.part` в `local` |
|
||
| R-2 | 2026-10-09 | `Input` по-прежнему создаётся перед записью (D-2), хотя старый АРМ этого не делал | Отказ в правах на `mkdir` при существующем каталоге уже не ошибка; dev и тесты на этом держатся | Лишний вызов `mkdir` на шаре на каждое задание |
|
||
| R-3 | 2026-10-09 | Ошибка записи: недописанный файл в `Input` удаляется только при `SCAN_CLEANUP=true` (D-5) | Требование «при `SCAN_CLEANUP=false` ничего не удалять» (OQ-144) сохраняется | Обрезанный файл остаётся в `Input`, ИС может его распознать с ошибкой; ядро получит `RECOGNITION_FAILED` от шлюза раньше |
|
||
| R-4 | 2026-10-09 | `SCAN_TMP_DIR` удаляется из шлюза, у эмулятора остаётся (D-3) | Шлюзу каталог больше не нужен; эмулятору нужен для атомарной сборки ответа | Нет: `extra="ignore"` — старые `.env` стартуют |
|