Раздел 37 · Redis с нуля

Очереди задач на списках

junior~15 мин

без входаВойди, чтобы отмечать прогресс, вести заметки и решать задачи в редакторе. войти

В прошлом уроке Pub/Sub терял сообщения, если подписчика не было на месте. Для письма «ваш заказ принят» так нельзя: письмо должно уйти, даже если сервис рассылки перезапускался. В уроке про списки мы уже собрали простую очередь писем на RPUSH и LPOP. Сегодня доводим её до рабочего состояния: работник ждёт задачи, не тратя запросы впустую, и не теряет их, если упал.

Чеки на кухне

Представь кухню ресторана. Официант пишет заказ на чеке и вешает его на планку. Повар снимает чек с другого края, готовит блюдо и выбрасывает чек. Если заказов нет, повар не бегает к планке каждую секунду, он просто ждёт, пока зазвенит звонок. Поваров может быть несколько, и каждый чек достаётся ровно одному из них.

А теперь повар снял чек и ушёл домой посреди готовки. Чек у него в кармане, блюдо никто не приготовит. Хорошие кухни делают иначе: снятый чек повар кладёт на свою полочку «готовлю», а выбрасывает его, только когда блюдо отдано. Если повар пропал, старший смотрит на его полочку и возвращает чеки на планку.

Это и есть очередь задач. Официант это производитель, повар это потребитель, планка это список в Redis.

Производитель и работник

Магазин оформил заказ и кладёт задачу «отправить письмо» в голову списка:

127.0.0.1:6379> LPUSH queue:emails order:15
(integer) 1

Работник забирает задачи с хвоста. Кладём слева, забираем справа: первой уйдёт самая старая задача, как в очереди в кассу.

В уроке 7 работник спрашивал RPOP и на пустой очереди получал (nil). Чтобы не спрашивать снова и снова, есть блокирующая версия BRPOP. Посмотрим на настоящем Redis с двумя терминалами. Работник в первом запускает ожидание на 10 секунд, очередь пуста:

127.0.0.1:6379> BRPOP queue:emails 10

Ответа нет, redis-cli висит. Через две секунды магазин во втором терминале кладёт задачу:

127.0.0.1:6379> LPUSH queue:emails order:15
(integer) 1

И работник в первом терминале тут же получает её:

1) "queue:emails"
2) "order:15"
(2.02s)

BRPOP возвращает пару: из какого списка взята задача и сама задача. Список приходит в ответе, потому что ждать можно сразу на нескольких: BRPOP queue:urgent queue:emails 10 сначала проверит срочную очередь. (2.02s) дописал redis-cli: столько длилось ожидание.

Если работников несколько и все ждут на BRPOP, каждая задача достанется одному из них. В этом главное отличие от Pub/Sub, где сообщение получает каждый подписчик.

Работник упал: задача пропала

У схемы с BRPOP есть дыра. Работник забрал задачу, и в этот момент её больше нет в Redis, она только в памяти процесса. Если процесс упал, не успев отправить письмо, задача потеряна навсегда. Как чек в кармане ушедшего повара.

урок из курса

Урок из курса «Redis с нуля». Курс покупается один раз и остаётся навсегда: 500 ₽.

Оплата пока не подключена: премиум и курсы открываются промокодом.