Что делать, если сервис, выдающий IP, упал до того, как положил данные в очередь
Что проверяют
Понимаете ли вы, что изменение состояния и публикация в очередь это две разные системы без общей транзакции. Ждут не рассуждений про мониторинг, а конкретной схемы, которая переживает падение процесса в самый неудобный момент.
Как отвечать
Назовите проблему по имени: это двойная запись. Сервис выдал адрес и изменил своё состояние, а сообщение отправить не успел, и теперь два хранилища расходятся навсегда. Повторы внутри упавшего процесса не помогают: процесса уже нет.
Рабочая схема это исходящий журнал. В той же транзакции, что и выдача адреса, пишем строку в таблицу сообщений. Отдельный воркер читает неотправленные, публикует в очередь и отмечает результат.
tx, err := db.BeginTx(ctx, nil)
// выдача адреса и запись события идут одной транзакцией
tx.ExecContext(ctx, "insert into leases(ip, owner) values($1, $2)", ip, owner)
tx.ExecContext(ctx, "insert into outbox(payload) values($1)", payload)
err = tx.Commit()Дальше обязательны две вещи. Первая: потребитель идемпотентен, потому что журнал даёт доставку не менее одного раза, и после падения публикатора сообщение придёт повторно. Ключ для отсева берём из данных, например сам адрес вместе с идентификатором аренды. Вторая: сверка. Периодическая задача сравнивает выданное с обработанным и дотягивает расхождения.
Если базы нет, роль журнала играет чтение изменений из журнала репликации либо запись в саму очередь как в источник истины, а состояние уже строится из неё.
Где спотыкаются
Кладут отправку в defer или в горутину после ответа. Ни то ни другое не выполнится при SIGKILL, нехватке памяти или отказе узла, а именно эти случаи и обсуждаются.
Второе: обещают ровно одну доставку. Между публикацией и подтверждением всегда есть окно, поэтому надёжно достижимо только не менее одного раза плюс идемпотентность на приёме.
Третье: буфер в памяти. Канал с запасом или пул горутин выглядит как очередь, но теряет содержимое вместе с процессом, то есть повторяет исходную проблему на новом уровне.