Разработчики часто недооценивают, насколько коварными могут быть очереди задач (job queues). На первый взгляд кажется, что всё просто: кинул задачу, она выполнилась. Но реальность, как всегда, сложнее.
Автор разбирает конкретный пример с фоновой упаковкой «репозиториев-эталонов» (reference repos) на работе. Есть два варианта: дорогая полная перепаковка (7 часов, но итоговый архив на 50–60% меньше) и дешёвая инкрементальная (2 часа, архив больше, но свежее). Пользователи активнее в будни, поэтому логично предложить: в будни делать быструю инкрементальную упаковку раз в 3 часа, а на выходных — запускать одну долгую полную.
Проблема в том, что типичная job queue не даёт прямого доступа к управляющему циклу. Ты просто выставляешь интервал планирования и лимит одновременных задач (concurrency limit). Если интервал (3 часа) меньше времени выполнения (7 часов), а лимит — 1, то при запуске новой задачи старая ещё не завершилась. Тут в игру вступают четыре возможные семантики поведения очереди: 1. Parallel Spawn — запустить новую параллельно (требует лимита >1). 2. Prefer New (отменить старую) — убить J1 и стартовать J2. 3. Wait — поставить J2 в очередь и ждать завершения J1. 4. Prefer Old (отменить новую) — отменить J2, дав J1 закончить.
Интуитивно кажется, что Prefer Old — странный выбор. Но расчёты показывают обратное. Если на weekend поставить интервал 3 часа при 7-часовой задаче: - Prefer New: каждые 3 часа задача будет убиваться и запускаться заново. За выходные сгорит 48 часов процессорного времени впустую, ни одна задача не завершится. - Wait: накопится гигантская очередь с отставанием на несколько дней. - Prefer Old: за выходные почти завершатся 7 задач, отменится 9 лишних. В понедельник останется всего час недоделанной работы.
Вывод: семантика Prefer Old идеально подходит для сценария, где время задачи гарантированно превышает интервал. Она исходит из пессимистичного предположения: новая задача тоже не уложится в срок, так что лучше не мешать текущей.
Автор подчёркивает: проектируя системы, нужно явно оговаривать модели отказов (fault models), лимиты (limits) и поведение очередей. Если этого не сделать, любая гибкая конфигурация (JSON/YAML) может привести к скрытым проблемам — например, к бесконтрольному росту очереди, который кто-то будет вручную чистить DELETE-запросами. Лучше заранее, на бумаге, промоделировать разные сценарии, как в этом примере.