- признаки «работы нет» и «задача не найдена» узнаются по смыслу, а не приведением типа: обёртка `%w` на пути больше не превращает пустой прогон воркера в отказ раз в секунду - отказ закрытия соединения с распознавателем доходит до вызывающего (`errors.Join`) либо до журнала; у `errcheck` включён `check-blank`, иначе критерий принимал реализацию, выбрасывающую отказ в пустоту - заведены первые тесты пакета worker и capability `pipeline`; долг из четырёх замечаний линтера закрыт, гейт зелёный целиком
42 lines
3.1 KiB
Markdown
42 lines
3.1 KiB
Markdown
# gRPC-клиент SpeechKit: когда закрытие вообще может отказать
|
||
|
||
Отвечает на вопрос, возникший по ходу задачи `errors-as-instead-of-typecast`: что
|
||
означает отказ `Close` у клиента SpeechKit и стоит ли писать его в журнал.
|
||
Наблюдение понадобилось потому, что первая редакция кода и обоснования описывала
|
||
этот отказ неверно — как признак недоступности Yandex.
|
||
|
||
## Как снималось
|
||
|
||
Не замером, а **чтением исходников** зависимости, зафиксированной в `go.mod`:
|
||
`google.golang.org/grpc` версии **v1.74.2**. Смотрел два места в
|
||
`clientconn.go` — конструктор клиента и метод `Close`. К Yandex ни разу не
|
||
обратился: ни на живых ключах, ни на тестовых.
|
||
|
||
## Что выяснилось
|
||
|
||
- **`grpc.NewClient` соединения не открывает.** Клиент создаётся в состоянии
|
||
ожидания, сеть трогается при первом вызове (`clientconn.go:145`). То есть на
|
||
пути отказа конструктора — когда первый клиент создан, а второй нет — закрывать
|
||
ещё нечего.
|
||
- **`(*ClientConn).Close` возвращает ровно два исхода** (`clientconn.go:1142-1156`):
|
||
`nil` либо `ErrClientConnClosing` — `codes.Canceled`, «grpc: the client
|
||
connection is closing» (`clientconn.go:67`). Второй наступает **только при
|
||
повторном закрытии** уже закрытого клиента.
|
||
|
||
## Что из этого следует для нас
|
||
|
||
Отказ `Close` в этом проекте означает **нашу ошибку — закрыли дважды**, а не сбой
|
||
или недоступность Yandex. Поэтому запись в журнале при остановке процесса
|
||
адресует владельца к нашему коду; так она и сформулирована.
|
||
|
||
Обработка отказа при этом оставлена в обоих местах, хотя сегодня он практически
|
||
недостижим: она стоит одну строку и переживёт смену клиента, а её отсутствие
|
||
пришлось бы обосновывать заново каждому читателю. Решение и его цена —
|
||
[ADR](../adr/ADR-2026-08-11-errcheck-check-blank.md), обоснование целиком — в
|
||
архивном
|
||
[design.md](../../openspec/changes/archive/2026-08-11-errors-as-instead-of-typecast/design.md),
|
||
Решение 2.
|
||
|
||
**Наблюдение привязано к версии.** Сменится мажорная версия `grpc` — перечень
|
||
исходов `Close` надо перечитать, а не считать его прежним.
|