- род метрики выводится сверкой минутного слоя с часовым: часовое значение сходится с суммой минутных — накопительная, со средним — мгновенная, иначе `unknown` и свёртка не предлагается вовсе. На живом архиве (123 доставки, 31 метрика) 7 накопительных, 9 мгновенных, противоречащих часов ноль - `GET /api/v1/metrics` под токеном чтения отдаёт единицы, слои с границами и род вместе с основанием измерения; род нигде не хранится — он функция витрины, а витрина функция журнала, устаревать в нём нечему - миграция 00009: покрывающий индекс, чтобы каталог отвечал по учётным колонкам, не разжимая содержимое объектов
11 KiB
11 KiB
1. Схема
- 1.1 Миграция
00009_bucket_catalog.sql— покрывающий индексbucket(metric, layer, hour_utc, first_ts, last_ts, points, units) - 1.2 Обновить
docs/database.md: индекс и зачем он
2. Хранилище
- 2.1
store.ReadCatalog(ctx, store.CatalogWindow)— весь вход каталога одной транзакцией чтения: разрезы всех метрик, общие часы пары слоёв по каждой метрике, объекты окна обоих слоёв - 2.2 Разрезы — одним запросом
metric, layer, units, min(first_ts), max(last_ts), sum(points), группировка вместе с единицами (расхождение видно, а не выбирается молча) - 2.3 Общие часы — самые свежие часы с объектами обоих слоёв, от свежих к
старым, не больше
window - 2.4 Объекты окна — пакетом, один запрос на метрику на оба слоя
(
hour_utc IN (…)), а не по объекту за раз - 2.5 Тест: разрезы и общие часы отвечают по индексу (
EXPLAIN QUERY PLANне содержит обхода таблицы) - 2.6 Тест: число обращений к базе на метрику не зависит от размера окна
- 2.7 Тест:
CommonHoursотдаёт не большеwindowи именно свежие часы
3. Значение точки
- 3.1
hae.PointValue(raw)— число точки:qty, при его отсутствииAvg; разбор через*json.Number, ноль — значение, отсутствие ключа иnull— нет значения, нечисловое и не влезающее вfloat64(ErrRange,±Inf) — нет значения - 3.2 В док-комментарии сказать, что словарь пустоты
canonсюда не применяется, и почему - 3.3 Тесты на реальных формах точки из
testdata:heart_rateсMin/Avg/Maxбезqty,{"qty":0}, точка без числового поля,1e400
4. Измерение рода
- 4.1 Пакет
internal/catalog: тип рода (cumulative/instant/unknown, пустое значение невыразимо) и основание измерения (hours/compared/agreeing/conflicting/границы окна) - 4.2 Именованная константа допуска
1e-9с измеренной ценой в комментарии и один предикатclose(a, b), которым выражены все три сравнения - 4.3 Пригодность часа: ровно одна точка со значением у часового объекта, её метка совпадает с началом часа, ≥2 точек со значением у минутного, сумма отличима от среднего
- 4.4 Сумма минутных значений считается в порядке возрастания метки
- 4.5 Правило метрики: ≥3 согласных и 0 противоречащих, иначе
unknown - 4.6 Окно 48 самых свежих общих часов
- 4.7 Сборка каталога: разрезы из снимка + род из измерения; строки слоя, разошедшиеся единицами, схлопываются в один элемент, множество единиц метрики отсортировано
- 4.8 Чекпоинт
WARNприconflicting > 0: имя метрики и числа основания, без значений точек - 4.9 Тесты: накопительная, мгновенная, нулевой час, двухточечный часовой
объект, одноточечный минутный, невыровненная часовая метка, противоречие,
единственный слой, только слой
day, история длиннее окна, разошедшиеся единицы, идемпотентность двух вызовов
5. HTTP
- 5.1 Проверка токена одна на оба контура, параметризованная списком;
схема строгая (
Bearer), пустой список = выключено - 5.2 Предупреждение на старте о выключенной проверке чтения
- 5.3 Редакция сохраняемых заголовков доставки чистит токены обоих контуров
- 5.4
GET /api/v1/metrics— форма ответа из дизайна:style,hours,compared,agreeing,conflicting,first_hour,last_hour; срезы пустые, а не nil; границы окна — указатели; порядок детерминирован - 5.5 Тесты: 401 без токена, 401 с токеном приёма, 401 с голым значением без схемы, отдача при выключенной проверке, пустая витрина — сравнением байтов ответа с литералом
- 5.6
config.example.tomlиconfig.docker.toml:read_tokensперестал быть заделом на будущее, цена пустого списка названа комментарием
6. Проверка на живом архиве
- 6.1 Прогон измерения в
internal/replay/archive_test.go: свойства, а не числа — конфликтующих свидетельств ноль; накопительные и мгновенные метрики разошлись по родам; ни одна метрика не измерена по слоюraw - 6.2 Печать измеренного рода по метрикам и стоимости каталога в
t.Logf - 6.3
task verify:archiveзелёный, отпечаток витрины не изменился
7. Документация и беклог
- 7.1
docs/architecture.md: метод измерения, окно, порог, допуск, почему род не хранится, почему родов два, а не четыре, где нуженxFilesFactorи какой у него подвох с полярностью - 7.2
docs/architecture.md: форма каталога приведена к реализованной - 7.3
docs/local-research.md: находка с результатом измерения на живом корпусе - 7.4 Блокер «тай-брейк при равной полноте точек» в беклог, с вариантами, ценой и рекомендацией
- 7.5 Пометка в
docs/backlog/read-api-tochki.md: порог неполного ведра, его полярность и предел размера ответа решаются там - 7.6 Пометка в
docs/backlog/upravlenie-sekretami.md: контуров теперь два - 7.7 Убрать задачу из беклога, обновить индекс
8. Дозакрыто по ревью кода
- 8.0 Горизонт окна: часы позже
now + часв сверку не входят, данные из будущего пишутсяWARN - 8.0 Единицы обеих сторон обязаны совпасть — иначе уверенный ложный род
- 8.0 Содержимое разжимается только у часов, прошедших отбор по учётным колонкам
- 8.0 Имя метрики в логе обрезано, множество единиц ограничено потолком
- 8.0 Метрика с пустым именем показывается, а не выбрасывается сентинелом
- 8.0 Отмена снаружи не пишется как сбой сервиса
- 8.0 Байтовый тест непустого ответа и повтора запроса
9. Приёмочные критерии (рубрика ревью предложения)
- 9.1 Вердикт — чистая функция состояния витрины и окна: не зависит от порядка строк SQL, порядка точек в объекте и момента вызова
- 9.2 Допуск назван величиной, один предикат на все сравнения, поведение около нуля объявлено
- 9.3 Вырожденные свидетельства исключены явно, кворум назван числом, ниже
кворума исход —
unknown, а не умолчание - 9.4
unknown— исход первого класса, и его причины различимы клиентом без второго запроса - 9.5 Измерение ничего не пишет и не кешируется скрытно
- 9.6 Стоимость ответа ограничена сверху и по числу запросов, и по числу прочитанных страниц; не растёт вместе с историей
- 9.7 HTTP-контракт полон: только
GET, пустая витрина — 200 с пустым списком, авторизация до работы, токены и значения здоровья не в логах вышеDEBUG - 9.8 Ответ самоописателен: словарь слоёв тот же, что везде; границы объявляют, что метят; расхождение единиц показано, а не выбрано молча
- 9.9 Каталог отдаёт наблюдаемое, а не досчитанное; деталь хранения наружу не протекает
- 9.10 Нижний слой в сверке не участвует;
sourceв измерение не входит - 9.11 Смена вердикта наблюдаема чекпоинтом
- 9.12 Правило часа и правило метрики тестируются без БД; на живом архиве проверяются свойства, а не числа