внутренняя модель перестроена вокруг аудиозаписи
- audiorecords вместо transcribe_jobs: приложения (texts, structures, recognitions, record_events, topics) живут своими коллекциями, ссылки на исходник и на приведённую копию перестали переставляться - рубеж называет достигнутое, отказ стал признаком остановки с причиной, а сторожей стало двое: число отказов и время в рубеже - воркеры потеряли специализацию, их число задаётся [pipeline] workers, шаг выбирается по рубежу, а захват отдаёт идентификатор и признак захвата
This commit is contained in:
@@ -0,0 +1,83 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/prometheus/client_golang/prometheus"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"git.vakhrushev.me/av/transcriber/internal/entity"
|
||||
)
|
||||
|
||||
// Счёт работы конвейера живёт в шаге, а не в воркере: только шаг знает рубеж, с
|
||||
// которого взята запись, а воркеры пула одинаковы и именем ничего не говорят.
|
||||
|
||||
// stageCount читает счётчик работы из общего реестра процесса. Судит реестр, а
|
||||
// не переменную пакета: метка, потерянная в точке употребления, переменную не
|
||||
// ломает, а на странице метрик видна.
|
||||
func stageCount(t *testing.T, stage, errLabel string) float64 {
|
||||
t.Helper()
|
||||
|
||||
families, err := prometheus.DefaultGatherer.Gather()
|
||||
require.NoError(t, err)
|
||||
|
||||
for _, mf := range families {
|
||||
if mf.GetName() != "transcriber_worker_job_count" {
|
||||
continue
|
||||
}
|
||||
for _, m := range mf.GetMetric() {
|
||||
var gotStage, gotErr string
|
||||
for _, label := range m.GetLabel() {
|
||||
switch label.GetName() {
|
||||
case "stage":
|
||||
gotStage = label.GetValue()
|
||||
case "error":
|
||||
gotErr = label.GetValue()
|
||||
}
|
||||
}
|
||||
if gotStage == stage && gotErr == errLabel {
|
||||
return m.GetCounter().GetValue()
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// Критерий приёмки 11. Отказ виден с разрезом по шагу: счётчик отказов —
|
||||
// единственный сигнал, по которому владелец сервиса замечает поломку, и без
|
||||
// метки рубежа «падает приведение» и «падает распознавание» стали бы
|
||||
// неразличимы.
|
||||
func TestFailureIsCountedWithStageLabel(t *testing.T) {
|
||||
env := newPipelineEnv(t, &okMetaViewer{}, &okConverter{})
|
||||
|
||||
beforeOk := stageCount(t, entity.StateUploaded, "false")
|
||||
|
||||
record := newTelegramRecord(t, env)
|
||||
require.NoError(t, env.service.RunStep(t.Context()))
|
||||
require.Equal(t, entity.StateNormalized, readRecord(t, env, record.Id).State)
|
||||
|
||||
assert.InDelta(t, beforeOk+1, stageCount(t, entity.StateUploaded, "false"), 0,
|
||||
"успешный шаг засчитан с меткой своего рубежа")
|
||||
|
||||
// Теперь тот же рубеж, но с отказом.
|
||||
failing := newPipelineEnv(t, &okMetaViewer{}, &failingStepConverter{})
|
||||
beforeErr := stageCount(t, entity.StateUploaded, "true")
|
||||
|
||||
newTelegramRecord(t, failing)
|
||||
require.Error(t, failing.service.RunStep(t.Context()))
|
||||
|
||||
assert.InDelta(t, beforeErr+1, stageCount(t, entity.StateUploaded, "true"), 0,
|
||||
"отказ засчитан с меткой того же рубежа")
|
||||
}
|
||||
|
||||
// failingStepConverter отказывает **отказом шага**, а не приговором записи:
|
||||
// приговор счётчик отказов не растит, потому что шаг при нём отрабатывает.
|
||||
type failingStepConverter struct{}
|
||||
|
||||
func (c *failingStepConverter) Convert(_ context.Context, _, dest string) error {
|
||||
// Файл результата не создаётся вовсе — шаг отказывает на измерении копии.
|
||||
return os.Remove(dest)
|
||||
}
|
||||
Reference in New Issue
Block a user