APScheduler выполняется несколько раз для количества рабочих gunicorn

У меня есть проект django со встроенным в него APScheduler. Сейчас я перешел к производственной среде, поэтому связал его с gunicorn и nginx в процессе работы. Gunicorn имеет 3 рабочих. Проблема в том, что gunicorn инициирует APScheduler для каждого рабочего и запускает запланированное задание 3 раза вместо того, чтобы запустить его только один раз.

Я видел подобные вопросы здесь, похоже, это распространенная проблема. Даже оригинальная документация APScheduler признает эту проблему и не говорит о способе ее устранения.

https://apscheduler.readthedocs.io/en/stable/faq.html#how-do-i-share-a-single-job-store-among-one-or-more-worker-processes

Я видел в других темах, что люди рекомендовали ставить --preconfig в настройках. Но я читал, что --preconfig инициирует работу с текущим кодом и не перезагружает его, если в коде произошли изменения. (См. "Когда не стоит перезагружать" в ссылке ниже)

https://www.joelsleppy.com/blog/gunicorn-application-preloading/

Я также видел, что кто-то рекомендовал привязать TCP сокет для APScheduler. Я не понял до конца, но в основном он пытался привязать сокет каждый раз, когда инициируется APScheduler, затем второй и третий рабочий попадает на этот привязанный сокет и выбрасывает ошибку сокета. Вроде того

try: 
    "bind socket somehow" 
except socketerror:
    print("socket already exists")"
else:
    "run apscheduler module"

конфигурация. Кто-нибудь знает, как это сделать или знает, будет ли это действительно работать?

Другой обходной путь, о котором я подумал, это просто удалить APScheduler и сделать это с помощью функции cron на сервере. Я использую Digital Ocean, поэтому я могу просто удалить APScheduler и запустить вместо него функцию cron, которая будет запускать модуль. Однако я не хочу идти таким путем, потому что это нарушит "единство" всего проекта и сделает его зависимым от сервера. Есть ли у кого-нибудь еще идеи?

Модуль расписания:

from apscheduler.schedulers.background import BackgroundScheduler
from RENDER.views import dailypuzzlefunc

def start():
    scheduler=BackgroundScheduler()
    scheduler.add_job(dailypuzzlefunc,'cron', day="*",max_instances=2,id='dailyscheduler')
    scheduler.start()

В приложении:

from django.apps import AppConfig

class DailypuzzleConfig(AppConfig):
    default_auto_field = "django.db.models.BigAutoField"
    name = "DAILYPUZZLE"

    def ready(self):
        from SCHEDULER import dailypuzzleschedule
        dailypuzzleschedule.start()
web: 
  python manage.py collectstatic --no-input; 
  gunicorn MasjidApp.wsgi --timeout 15 --preload

use --preload. 

Для меня это работает хорошо.

Вернуться на верх