- Очередью служит сама таблица: доставка ждёт свёртки в статусе `pending`, канал несёт только бит «есть работа». Переполнять нечего, падение процесса очередь не теряет, а подбор `pending` при старте — обычный проход воркера, а не отдельный код. Классификация исхода общая с пересборкой журнала. - Исход разбора начал отражать доставку, а не обстоятельства: отмена и занятость базы статус не меняют (иначе конкуренция за базу выводила бы доставку из очереди навсегда), паника свёртки больше не валит процесс, а учёт доставки идёт через транзакцию с повторами. - Длинный бюджет ответа выдан маршруту приёма, а не всему серверу: `write_timeout` в Go покрывает и чтение тела, и общий подъём снял бы защиту с остальных маршрутов.
21 lines
1.6 KiB
SQL
21 lines
1.6 KiB
SQL
-- +goose Up
|
|
-- Очередью свёртки служит сама таблица: доставка ждёт разбора в статусе
|
|
-- `pending`, а фоновый воркер выбирает такие строки в порядке журнала. Запрос
|
|
-- идёт чаще, чем раз в минуту, а `delivery` растёт примерно на 300 строк в
|
|
-- сутки — без индекса это скан всей таблицы с сортировкой на каждый проход.
|
|
--
|
|
-- Индекс ЧАСТИЧНЫЙ, и это не украшение: в установившемся режиме неразобранных
|
|
-- доставок ноль или одна, поэтому индекс держит ноль-одну строку. Полный
|
|
-- индекс по `parse_status` хранил бы всю историю (сто тысяч строк в год) ради
|
|
-- выборки из одной. SQLite применяет частичный индекс, когда условие запроса
|
|
-- следует из условия индекса — наш случай.
|
|
--
|
|
-- Порядок колонок = порядок журнала, тот же, в котором проигрывает пересборка.
|
|
-- Второй ключ обязателен: `received_at` хранится с секундной точностью, и
|
|
-- доставки одной секунды без него шли бы в неопределённом порядке.
|
|
CREATE INDEX delivery_pending ON delivery (received_at, id)
|
|
WHERE parse_status = 'pending';
|
|
|
|
-- +goose Down
|
|
DROP INDEX delivery_pending;
|