Как мы заменили управляемую очередь на 200 строк Postgres
Любая система фоновых задач начинается одинаково: нужно, чтобы работа произошла позже и где-то ещё, и интернет советует купить очередь. Мы купили, прожили с ней два года и вынули.
Что управляемая очередь давала на самом деле
Три вещи, и важной была только одна.
- Гарантии доставки, которые пишутся за вечер своими руками.
- Дашборд, который никто не открывал после первого месяца.
- Вторую систему в эксплуатации — со своими падениями, своим SDK и своим счётом.
Что пришло на замену
Одна таблица, один индекс и колонка locked_until вместо продления блокировки:
SELECT * FROM job_queue
WHERE queue = $1 AND status = 'queued' AND run_at <= now()
ORDER BY run_at
FOR UPDATE SKIP LOCKED
LIMIT 1;Весь фокус в FOR UPDATE SKIP LOCKED. Postgres выдаёт каждому воркеру свою строку и никогда не ставит одного в очередь за другим. LISTEN/NOTIFY будит простаивающих, поэтому никто не опрашивает базу в цикле.
Безопасной эту замену сделал не SQL. Её сделали 30 поведенческих тестов, написанных сначала против старой очереди, — а потом новая проходила ровно те же тесты.
Во что это обошлось
Две недели вечеров, большая часть — на тесты, а не на очередь. Взамен: минус один вендор, минус один счёт и система, где упавшая задача — это строка, которую можно прочитать глазами.
Не всякий управляемый сервис заслуживает такого обращения. Этот заслужил: та часть, которой мы реально пользовались, была меньше клиентской библиотеки, которую ради неё импортировали.