Каталог разрезов и измеренный род агрегации

- род метрики выводится сверкой минутного слоя с часовым: часовое значение
  сходится с суммой минутных — накопительная, со средним — мгновенная, иначе
  `unknown` и свёртка не предлагается вовсе. На живом архиве (123 доставки,
  31 метрика) 7 накопительных, 9 мгновенных, противоречащих часов ноль
- `GET /api/v1/metrics` под токеном чтения отдаёт единицы, слои с границами и
  род вместе с основанием измерения; род нигде не хранится — он функция витрины,
  а витрина функция журнала, устаревать в нём нечему
- миграция 00009: покрывающий индекс, чтобы каталог отвечал по учётным колонкам,
  не разжимая содержимое объектов
This commit is contained in:
av
2026-08-02 19:23:59 +03:00
parent 98e0772ec5
commit 03edf1087d
39 changed files with 4744 additions and 58 deletions
+10
View File
@@ -13,6 +13,7 @@ import (
"time"
"git.vakhrushev.me/av/healthlog/internal/archive"
"git.vakhrushev.me/av/healthlog/internal/catalog"
"git.vakhrushev.me/av/healthlog/internal/config"
"git.vakhrushev.me/av/healthlog/internal/fold"
"git.vakhrushev.me/av/healthlog/internal/httpapi"
@@ -78,6 +79,13 @@ func serve(ctx context.Context, cfg *config.Config, log *slog.Logger, ready func
if len(cfg.Auth.WriteTokens) == 0 {
log.Warn("write auth disabled", "reason", "auth.write_tokens пуст")
}
// Цена у двух контуров разная, и это сказано вслух: открытый приём означает
// мусор во входе, открытое чтение — выгрузку истории здоровья любому, кто
// нашёл порт. Пока сервис живёт в доверенной сети, это осознанный выбор;
// перед выкладкой наружу список обязан быть непуст.
if len(cfg.Auth.ReadTokens) == 0 {
log.Warn("read auth disabled", "reason", "auth.read_tokens пуст")
}
// Воркер и приём делят одну свёртку: приём её только будит, сворачивает
// воркер — и в порядке журнала, чего синхронная свёртка внутри обработчика
@@ -87,8 +95,10 @@ func serve(ctx context.Context, cfg *config.Config, log *slog.Logger, ready func
srv := &http.Server{
Handler: httpapi.New(httpapi.Options{
Ingest: ingest.New(arch, st, worker.Notify, log),
Catalog: catalog.New(st, log),
Log: log,
WriteTokens: cfg.Auth.WriteTokens,
ReadTokens: cfg.Auth.ReadTokens,
MaxBodyMB: cfg.Ingest.MaxBodyMB,
// Бюджет ответа маршрута приёма: `WriteTimeout` сервера ставится ДО
// вызова обработчика и потому покрывает чтение тела, обрывая