Время читается единой точкой, а конец потока узнаётся не по тексту

- заведён internal/clock: Now даёт метку в UTC, Start — начало измерения
  длительности с монотонными часами; девять мест рабочего кода и запрос захвата
  переведены на него, долг «время time.Now() по месту» закрыт
- клиент SpeechKit узнавал конец потока сравнением err.Error() == "EOF": отказ
  с тем же текстом вернул бы усечённую расшифровку как готовую, теперь
  errors.Is(err, io.EOF)
- починены находки новых линтеров: две опечатки, два slog.DiscardHandler,
  четыре неэкранированные подстановки в docker/entrypoint.sh
This commit is contained in:
av
2026-08-13 09:01:36 +03:00
parent 6c7f006e75
commit 1d243ad2f6
9 changed files with 69 additions and 20 deletions
+32
View File
@@ -0,0 +1,32 @@
// Package clock — единая точка чтения времени.
//
// Прежде время брали `time.Now()` по месту вызова, и конвенция
// [docs/conventions/database.md] числила это долгом: метка времени в локальной
// зоне, а хранилище сравнивает времена **строками** побайтово. Долг закрыт
// заведением этого пакета; правило держит `forbidigo` в `.golangci.yml` —
// `time.Now` вне этого пакета запрещён.
//
// Метка времени и измерение длительности читаются по-разному, и потому здесь две
// функции, а не одна.
package clock
import "time"
// Now — метка времени: UTC, как её пишет и сравнивает хранилище.
//
// Приведение к UTC снимает монотонные часы, и для метки это верно: её кладут в
// колонку и сравнивают с чужими значениями, а не с собственным прошлым
// показанием.
func Now() time.Time {
return time.Now().UTC()
}
// Start — начало измерения длительности: время **с монотонными часами**.
//
// Зоны у него нет намеренно: значение не выходит наружу и годится только на
// вход `time.Since`. Монотонные часы здесь и нужны — иначе перевод стрелок или
// поправка ntp посреди конвертации дала бы отрицательную или скачущую
// длительность в журнале и в метрике.
func Start() time.Time {
return time.Now()
}