Отмена доходит до внешнего собеседника, а токен не покидает единой точки
- контекст проложен от воркера и обоих входов до внешних вызовов: ffmpeg и ffprobe заводятся через exec.CommandContext, SpeechKit и Object Storage принимают ctx вместо context.Background, скачивание записи идёт запросом с контекстом. Прежде остановка сервиса не доходила до чужой работы вовсе - прерванный шаг приговора не выносит: убитый по контексту ffmpeg отдаёт «signal: killed», от настоящего отказа неотличимо ни типом, ни errors.Is, и различает их только ctx.Err(). Задача остаётся на повтор, попытку не тратит и отправителю о несуществующем сбое не сообщает; воркер не считает остановку отказом, а задача не забирается вовсе, если нас уже остановили - клиента Bot API заводит единая точка internal/adapter/telegram: токен стоит в пути каждого обращения, а http.Client кладёт адрес в *url.Error целиком. Чистка на месте употребления закрывала один вызов из пяти — теперь свой Do чистит отказ, подменённый логгер вычищает токен из строк самой библиотеки, а транспорт бота токена не получает вовсе - принятие операции распознавания защищено от отмены своим пределом: SpeechKit мог её принять и начать считать деньги, а потерянный идентификатор заставил бы повтор оплатить ту же запись второй раз - приём по HTTP доводит запись до задачи независимо от отправителя: на контексте запроса один обрыв соединения терял полностью загруженную запись - ответ Telegram с не-2xx кодом больше не становится записью: прежде тело отказа доезжало до хранилища и умирало на ffprobe, уводя диагностику
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
@@ -32,7 +33,7 @@ type scriptedRecognizer struct {
|
||||
lastObjectKey string
|
||||
}
|
||||
|
||||
func (r *scriptedRecognizer) Recognize(file io.Reader, fileName string) (string, error) {
|
||||
func (r *scriptedRecognizer) Recognize(_ context.Context, file io.Reader, fileName string) (string, error) {
|
||||
r.recognizeCalls++
|
||||
r.lastObjectKey = fileName
|
||||
if r.recognizeErr != nil {
|
||||
@@ -45,11 +46,11 @@ func (r *scriptedRecognizer) Recognize(file io.Reader, fileName string) (string,
|
||||
return "operation-id", nil
|
||||
}
|
||||
|
||||
func (r *scriptedRecognizer) GetRecognitionText(string) (string, error) {
|
||||
func (r *scriptedRecognizer) GetRecognitionText(context.Context, string) (string, error) {
|
||||
return r.text, nil
|
||||
}
|
||||
|
||||
func (r *scriptedRecognizer) CheckRecognitionStatus(string) (*entity.RecognitionResult, error) {
|
||||
func (r *scriptedRecognizer) CheckRecognitionStatus(context.Context, string) (*entity.RecognitionResult, error) {
|
||||
return r.result, nil
|
||||
}
|
||||
|
||||
@@ -92,7 +93,7 @@ func TestTranscribeJobHandsRecordOverAndMovesOn(t *testing.T) {
|
||||
rec := &scriptedRecognizer{result: entity.NewInProgressResult()}
|
||||
svc := withRecognizer(env, rec)
|
||||
|
||||
require.NoError(t, svc.FindAndRunTranscribeJob())
|
||||
require.NoError(t, svc.FindAndRunTranscribeJob(t.Context()))
|
||||
|
||||
assert.Equal(t, 1, rec.recognizeCalls, "содержимое отдано распознавателю")
|
||||
assert.NotEmpty(t, rec.lastObjectKey, "ключ объекта назван")
|
||||
@@ -119,7 +120,7 @@ func TestTranscribeJobKeepsJobRetryableOnRecognizerFailure(t *testing.T) {
|
||||
rec := &scriptedRecognizer{recognizeErr: errors.New("распознаватель недоступен")}
|
||||
svc := withRecognizer(env, rec)
|
||||
|
||||
require.Error(t, svc.FindAndRunTranscribeJob())
|
||||
require.Error(t, svc.FindAndRunTranscribeJob(t.Context()))
|
||||
|
||||
after, err := env.jobRepo.GetByID(job.Id)
|
||||
require.NoError(t, err)
|
||||
@@ -134,7 +135,7 @@ func transcribingJob(t *testing.T, env *pipelineEnv, rec contract.AudioRecognize
|
||||
t.Helper()
|
||||
|
||||
job := convertedJob(t, env)
|
||||
require.NoError(t, withRecognizer(env, rec).FindAndRunTranscribeJob())
|
||||
require.NoError(t, withRecognizer(env, rec).FindAndRunTranscribeJob(t.Context()))
|
||||
|
||||
clearDelay(t, env, job.Id)
|
||||
return job
|
||||
@@ -150,7 +151,7 @@ func TestCheckJobWaitsWithoutSpendingAttempts(t *testing.T) {
|
||||
svc := withRecognizer(env, rec)
|
||||
|
||||
for i := 0; i < 3; i++ {
|
||||
require.NoError(t, svc.FindAndRunTranscribeCheckJob())
|
||||
require.NoError(t, svc.FindAndRunTranscribeCheckJob(t.Context()))
|
||||
|
||||
after, err := env.jobRepo.GetByID(job.Id)
|
||||
require.NoError(t, err)
|
||||
@@ -174,7 +175,7 @@ func TestCheckJobFailsJobAndTellsSender(t *testing.T) {
|
||||
rec.result = entity.NewFailedResult("операция отклонена")
|
||||
svc := withRecognizer(env, rec)
|
||||
|
||||
require.NoError(t, svc.FindAndRunTranscribeCheckJob())
|
||||
require.NoError(t, svc.FindAndRunTranscribeCheckJob(t.Context()))
|
||||
|
||||
after, err := env.jobRepo.GetByID(job.Id)
|
||||
require.NoError(t, err)
|
||||
@@ -196,7 +197,7 @@ func TestCheckJobCompletesAndAnswersOnce(t *testing.T) {
|
||||
rec.text = "расшифровка записи"
|
||||
svc := withRecognizer(env, rec)
|
||||
|
||||
require.NoError(t, svc.FindAndRunTranscribeCheckJob())
|
||||
require.NoError(t, svc.FindAndRunTranscribeCheckJob(t.Context()))
|
||||
|
||||
after, err := env.jobRepo.GetByID(job.Id)
|
||||
require.NoError(t, err)
|
||||
@@ -224,7 +225,7 @@ func TestCheckJobCompletesEmptyTextWithExplanation(t *testing.T) {
|
||||
rec.text = ""
|
||||
svc := withRecognizer(env, rec)
|
||||
|
||||
require.NoError(t, svc.FindAndRunTranscribeCheckJob())
|
||||
require.NoError(t, svc.FindAndRunTranscribeCheckJob(t.Context()))
|
||||
|
||||
after, err := env.jobRepo.GetByID(job.Id)
|
||||
require.NoError(t, err)
|
||||
@@ -255,7 +256,7 @@ func TestCheckJobWritesNothingWhenAcquisitionLost(t *testing.T) {
|
||||
require.NoError(t, env.app.Save(record))
|
||||
|
||||
svc := withRecognizer(env, rec)
|
||||
err = svc.checkTranscribeJob(acquired, "mine")
|
||||
err = svc.checkTranscribeJob(t.Context(), acquired, "mine")
|
||||
|
||||
var lost *contract.LostAcquisitionError
|
||||
require.ErrorAs(t, err, &lost)
|
||||
|
||||
Reference in New Issue
Block a user