- пять из урожая change 2026-08-11-fix-http-handler-tests, тег review-2026-08-11; утечка имени файла в журнал поставлена первой строкой очереди - опечатка transcibe дописана в json-api-for-spa: текст ошибки — часть необратимого контракта, и в одиночку он не правится
62 lines
4.2 KiB
Markdown
62 lines
4.2 KiB
Markdown
# 🐞 Убирать записанный файл, когда приём отказал на середине
|
||
|
||
- **Тип:** fix
|
||
- **Категория:** Очередь
|
||
- **Зачем:** Отказ чтения метаданных и отказ записи на диск оставляют файл в каталоге хранения без задачи и без учёта: сопоставить его не с чем, удалять приходится руками.
|
||
- **Теги:** review-2026-08-11
|
||
|
||
Приём пишет файл на диск, потом спрашивает у источника метаданных длительность,
|
||
потом заводит запись в учёте и задачу. Уборка при отказе есть **только на
|
||
последнем шаге**: отказ `fileRepo.Create` зовёт `os.Remove`, а отказы записи на
|
||
диск и чтения метаданных возвращают ошибку, оставляя файл лежать.
|
||
|
||
Сопоставить такой файл не с чем: записи в `files` под него нет, задачи нет,
|
||
имя — случайный идентификатор. На сервере это `data/files`, где лежат голосовые
|
||
сообщения живых людей, а проект по паспорту «не хранит записи как архив».
|
||
|
||
Найдено проходом `review-specs` ревью дизайна change
|
||
`2026-08-11-fix-http-handler-tests`; отчёт триажа —
|
||
`openspec/changes/archive/2026-08-11-fix-http-handler-tests/review/triage.md`.
|
||
Вынесено сюда решением человека на контрольной точке.
|
||
|
||
## Воспроизведение
|
||
|
||
Асимметрия видна в самом коде:
|
||
|
||
```
|
||
sed -n '110,160p' internal/service/transcribe.go
|
||
```
|
||
|
||
Ветка `fileRepo.Create` (строки 152–157) содержит `os.Remove(storageFilePath)` с
|
||
комментарием «Удаляем файл если не удалось создать запись в БД». Ветки
|
||
`io.Copy`, `dst.Close` и `metaviewer.GetInfo` (строки 116–133) возвращают ошибку
|
||
без уборки, хотя файл к этому моменту уже создан.
|
||
|
||
Прогоном: `TestCreateTranscribeJob_MetaViewerFailure` в
|
||
`internal/controller/http/transcribe_test.go` доводит приём до этой ветки —
|
||
после него в каталоге хранения лежит файл, а `countJobs` равен нулю.
|
||
|
||
## Затрагивает
|
||
|
||
- `internal/service/transcribe.go`, функция `createTranscribeJob` — три ветки
|
||
отказа между созданием файла и заведением записи в учёте;
|
||
- `internal/controller/http/transcribe_test.go` — случай отказа метаданных
|
||
получает проверку на отсутствие файла;
|
||
- раскладка `data/files` не меняется: имена и формат прежние.
|
||
|
||
## Критерии приёмки
|
||
|
||
- Отказ чтения метаданных не оставляет файла в каталоге хранения. Оракул — тест
|
||
на подставном источнике, возвращающем ошибку: каталог пуст после запроса.
|
||
- Отказ записи на диск на середине не оставляет частично записанного файла.
|
||
Оракул — тест с источником данных, обрывающимся на середине чтения.
|
||
- Уборка сама не заслоняет исходную ошибку: отправитель по-прежнему получает
|
||
отказ, а причина уезжает в журнал. Оракул — тот же тест, код ответа и запись в
|
||
перехваченном журнале.
|
||
|
||
## Рамки
|
||
|
||
Уборка файлов, осиротевших **до** этой правки, сюда не входит: их надо найти
|
||
сверкой каталога с учётом, и это отдельная работа с боевыми данными.
|
||
|