Django, порождение рабочего процесса при запуске порождает django.core.exceptions.AppRegistryNotReady: Приложения еще не загружены

Фон:

У меня есть приложение, которое просматривает ресурсы нашей ИТ-инфраструктуры (vCenter, хранилища и объекты резервного копирования), чтобы собрать все в центральную опись для быстрого поиска. Каждая коллекция вращается в собственном потоке, и я принял меры по реализации настройки производитель/потребитель для лучшего масштабирования наших ресурсов. Я заметил, что когда у меня есть коллекции, запущенные из нескольких типов (например, vCenter и хранилище), веб-интерфейс работает нестабильно. Я подумал, что это происходит потому, что у меня есть тонна потоков, запущенных из нескольких источников, и GIL заставляет все ставить в очередь под одним главным потоком. Поэтому я подумал, что можно было бы запустить основную модель производитель/потребитель как процессы вместо потоков, поскольку они достаточно независимы друг от друга.

Что не так:

Когда я переключил код с потоков на процессы, рабочий процесс пытается загрузить модели, которые он должен, но это не удается, потому что подпроцесс является отдельным, и приложения не загружены. Он выбрасывает django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.

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

Что мне нужно:

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

Чтобы уточнить, эти процессы не порождаются из представления, а взаимодействуют друг с другом только через мультипроцессинг Queue. Я не посылаю данные туда и обратно между порожденными процессами, но они запрашивают базу данных и записывают в нее данные.

Из того, что я нашел, единственная вещь, которая отдаленно близка к этому, это Celery, но в моем кратком исследовании это кажется немного больше, чем я хочу вовлечь. Похоже, что мне нужно сделать так, чтобы каждый из этих порожденных процессов был установлен как приложение в настройках Django, но это не кажется мне правильным.

Примеры кодов:

Stacktrace:

  File "C:\Program Files\Python310\lib\multiprocessing\spawn.py", line 116, in spawn_main
    exitcode = _main(fd, parent_sentinel)
  File "C:\Program Files\Python310\lib\multiprocessing\spawn.py", line 126, in _main
    self = reduction.pickle.load(from_parent)
  File "C:\Users\jfort\PycharmProjects\VmInventory\VMwareInventory\Processes\Vcenter.py", line 5, in <module>
    from VMwareInventory.VMwareRest.VMwareRest import RESTVCenter
  File "C:\Users\jfort\PycharmProjects\VmInventory\VMwareInventory\VMwareRest\VMwareRest.py", line 19, in <module>
    from VMwareInventory.models import *
  File "C:\Users\jfort\PycharmProjects\VmInventory\VMwareInventory\models\__init__.py", line 2, in <module>
    from .Base.cost import Cost
  File "C:\Users\jfort\PycharmProjects\VmInventory\VMwareInventory\models\Base\cost.py", line 2, in <module>
    from .base import BaseModel
  File "C:\Users\jfort\PycharmProjects\VmInventory\VMwareInventory\models\Base\base.py", line 4, in <module>
    class BaseModel(models.Model):
  File "C:\Program Files\Python310\lib\site-packages\django\db\models\base.py", line 127, in __new__
    app_config = apps.get_containing_app_config(module)
  File "C:\Program Files\Python310\lib\site-packages\django\apps\registry.py", line 260, in get_containing_app_config
    self.check_apps_ready()
  File "C:\Program Files\Python310\lib\site-packages\django\apps\registry.py", line 138, in check_apps_ready
    raise AppRegistryNotReady("Apps aren't loaded yet.")
django.core.exceptions.AppRegistryNotReady: Apps aren't loaded yet.

apps.py:

from django.apps import AppConfig
from VMwareInventory.settings_local import environment
from VMwareInventory.threading.initial_settings import set_default_database_items


class VmwareinventoryConfig(AppConfig):
    name = 'VMwareInventory'

    def ready(self):
        set_default_database_items()
        if environment == "prod":
            from .threading.scraping import TimerScrape
            TimerScrape()

threading\scraping.py (Где живет функция TimerScrape()):

Processes\Vcenter.py

# Python imports:
from multiprocessing import Process

# Local imports:
from VMwareInventory.VMwareRest.VMwareRest import RESTVCenter


class VcenterWorker(Process):
    def __init__(self, queue, vcenter_list):
        Process.__init__(self)
        self.queue = queue
        self.list = vcenter_list
        self.name = "vCenter_worker_process"
        self.start()

    def run(self):
        while True:
            vcenter = self.queue.get()
            self.list.remove(vcenter)
            self.vcscrape(vcenter.name, vcenter.user, vcenter.password)
            self.queue.task_done()

    @staticmethod
    def vcscrape(name, user, pwd):
        vc_scrape = RESTVCenter(name, user, pwd)
        vc_scrape.join()
        return

OK, после размещения этого сообщения непосредственно на форумах Django, я получил некоторые рекомендации. По сути, мне пришлось разделить эти процессы как "отдельные" процессы Django, чтобы предоставить им доступ к Django ORM.

Мне пришлось установить настройки и выполнить django.setup() в каждом из процессов и перенести любые импорты моделей в код, который будет выполняться после этого выполнения.

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