Пользовательская очистка приложения Django для перезагрузки кода

#django

#django

Вопрос:

в моем проекте Django есть приложение, которое переопределяет его AppConfig.ready() метод. В готовом методе я запускаю отдельный multiprocessing.Process для обработки потребления из внешней очереди сообщений, это, похоже, вызывает проблемы с автоматической загрузкой при изменениях кода.

 def infinite_loop():
    while True:
        time.sleep(10)


class BrokerConfig(AppConfig):
    name = 'backend.broker'
    has_started = False

    def ready(self):
        if not os.environ.get("RUN_MAIN"):
            # Avoid running for reloader
            return

        if BrokerConfig.has_started:
            return
        BrokerConfig.has_started = True

        proc = Process(target=infinite_loop)
        proc.start()
 

По какой-либо причине это приводит к прерыванию автоматической перезагрузки кода. Кажется, что перезагрузчик не может очистить запущенные процессы. Перезагрузчик печатает это, а затем застревает:

 .../backend/broker/apps.py changed, reloading.
 

Способ обойти это — сделать запущенный процесс демоном, но в случае, если такая настройка невозможна, мне все еще интересно, как вы могли бы обойти это.

Я ищу какой-нибудь способ добавить пользовательскую очистку при перезагрузке, но, похоже, я не могу найти способ сделать это. Есть ли какой-либо перехват или сигнал, на который вы можете подписаться, чтобы узнать, была ли запущена перезагрузка?

Ответ №1:

Мне удалось сделать это наоборот, поэтому вместо прослушивания или подключения к какому-либо сигналу Django, чтобы указать «входящая перезагрузка кода», я добавил слушателя в свой запущенный процесс для SIGTERM. Когда происходит перезагрузка, перезагрузка кода приведет к завершению демонических процессов и, таким образом, получению сигнала SIGTERM. Я не нашел способа сделать это с не-демоническими процессами.

Конечное решение

 def infinite_loop():
    stop = False

    def stop():
        nonlocal stop
        stop = True

    signal.signal(signal.SIGTERM, stop)

    while True:
        if stop:
           break
        time.sleep(10)

class BrokerConfig(AppConfig):
    name = 'backend.broker'
    has_started = False

    def ready(self):
        if not os.environ.get("RUN_MAIN"):
            # Avoid running for reloader
            return

        if BrokerConfig.has_started:
            return
        BrokerConfig.has_started = True

        proc = Process(target=infinite_loop, daemon=True)
        proc.start()
 

Итак, в конце концов, я все-таки выбрал демона, и очистка, которую я хотел, была помещена в область запущенного процесса (как обработчик SIGTERM).