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()
в каждом из процессов и перенести любые импорты моделей в код, который будет выполняться после этого выполнения.