# 🧹 Задать таймауты обращениям к внешним сервисам

- **Тип:** chore
- **Категория:** Очередь — Молчащий внешний сервис держит шаг до истечения часового захвата — правится под свежими тестами конвейера.
- **Зачем:** Ни у Telegram, ни у Object Storage, ни у SpeechKit нет таймаута: молчащий собеседник держит шаг конвейера до истечения часового захвата.

Все обращения наружу идут с `context.Background()` либо через `http.Get` без
клиента со своим таймаутом. Отказ такого рода в
[architecture.md](../../docs/architecture.md) назван условием: собеседник,
который «отвечает медленно», сегодня останавливает воркер целиком, и заметить
это можно только по тому, что задачи перестали двигаться.

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

## Затрагивает

- `internal/adapter/recognizer/yandex/s3.go` — заливка объекта;
- `internal/adapter/recognizer/yandex/speechkit.go` — запуск распознавания,
  чтение потока, опрос операции;
- `internal/controller/tg/tg.go` — скачивание файла через `http.Get`;
- `internal/adapter/telegram/sender.go` — отправка сообщения;
- `internal/contract/contract.go` — интерфейсам нужен `context.Context` первым
  аргументом;
- `internal/controller/worker/worker.go` и `internal/service/transcribe.go` —
  протаскивание контекста в шаг;
- `config.example.toml` и `internal/config` — числа таймаутов;
- `docs/database.md`, таблица настроек с числовым значением.

## Критерии приёмки

- У каждого обращения наружу есть таймаут, и его значение задаётся конфигом.
  Оракул — тест на подставном сервере, который не отвечает: вызов
  возвращается с ошибкой за назначенное время, а не висит.
- Прерванная по таймауту задача достаётся повторно и доходит до текста. Оракул
  — тест на повторный прогон шага после отказа по таймауту.
- Числа таймаутов записаны в `docs/database.md`. Оракул — `task gate`.

## Рамки

Повторов с нарастающей паузой не заводим — это отдельная работа; здесь только
таймаут. Прерывание шага отменённым контекстом сюда не входит: методы записи
хранилища контекста не принимают вовсе, и этим занимается следующая задача
`context-cancel-in-pipeline`. Контекст первым аргументом интерфейсов эта задача
всё же протаскивает — без него таймаут некуда передать.
