Интеграция Odoo и RabbitMQ
Создаем отказоустойчивые системы очередей
Проблематика очередей
Odoo - транзакционная система. В результате такого подхода при интеграции с другими системами могут наблюдаться сбои по части отправки данных в случае отката выполняемой транзакции.
Также имеется проблема зависания рабочего процесса (worker) до момента получения ответа от удаленной системы. А если его и вовсе не последует?
Пример
Имеются инвойсы (account.move). Имеется планировщик, который должен отменить выставленные, но не оплаченные инвойсы, в определенное время.
Каждая отмена инвойса сопровождается отправкой уведомления клиенту через SMS или Телеграм. Это элемент бизнес-логики.
Предположим, что планировщик в цикле обрабатывает все такие инвойсы. Предположим, что в процессе работы планировщика произошел сбой (таймаут, ошибка, рестарт сервера).
В результате во внешнюю систему уйдут SMS, т.к. в процессе будет сделан POST запрос к API шлюза, а «отмена инвойсов» отменится. В Odoo всё останется так, как было до запуска планировщика.
Решение
Для того, чтобы сообщения во внешнюю систему уходили после коммита транзакции, следует вместо прямого взаимодействия из функций классов с внешней системой использовать буферную модель
Если в процессе выполнения задания, транзакция откатится, то и записи, сделанные в буфер, удалятся.
Остается обработать буфер независимым планировщиком.
И вот что мы сделали.
1. Вместо непосредственной отправки SMS или сообщения Телеграм, они помещаются в буфер заданий.
2. Примерно раз в минуту планировщик проверяет буфер на предмет новых заданий. И если они есть, помещает их в брокер очередей RabbitMQ
3. Примерно раз в минуту исполнитель заданий проверяет очереди в брокере RabbitMQ и исполняет.
4. Сообщения в буфере помечаются как исполненные.
Таким образом у вас теперь есть система, которая позволит асинхронно общаться с другими системами не вызывая нагрузки и сбоев.
Если сбой внутри Odoo и откат, то сообщение не попадет в буфер.
Если ляжет брокер, то все задания исполнятся как только брокер поднимется.
Если лягут планировщики, то все задания будут исполнены как только планировщики поднимутся.
Если ляжет внешняя система, то исполнитель сможет исполнить все ошибочные задания после подъема.
"А как же модуль queue_job?" - заметит внимательный и искушенный оппонент. У него есть свои ограничения, и нам показалось правильным использовать профессиональный внешний брокер.