Cómo evitar que el método AppConfig.ready () se ejecute dos veces en Django

Quiero ejecutar un código al inicio del servidor Django pero quiero que se ejecute solo una vez. Actualmente cuando inicio el servidor se ejecuta dos veces. La documentación dice que esto podría suceder y:

debe colocar un indicador en sus clases de AppConfig para evitar que se vuelva a ejecutar el código, que debe ejecutarse exactamente una vez.

¿Alguna idea de cómo lograr esto? La statement de impresión a continuación todavía se ejecuta dos veces.

from django.apps import AppConfig import app.mqtt from apscheduler.schedulers.background import BackgroundScheduler class MyAppConfig(AppConfig): name = 'app' verbose_name = "HomeIoT" run_already = False def ready(self): if MyAppConfig.run_already: return MyAppConfig.run_already = True print("Hello") 

Cuando usa python manage.py runserver, Django inicia dos procesos, uno para el servidor de desarrollo real y otro para recargar su aplicación cuando cambia el código.

También puede iniciar el servidor sin la opción de recarga, y verá que solo un proceso en ejecución se ejecutará solo una vez:

 python manage.py runserver --noreload 

Puedes ver estos enlaces, resuelve ese método ready () ejecutándose dos veces en Django

Como lo mencionó Roberto, necesitará implementar el locking para hacer esto cuando ejecute su servidor a través del comando runserver, si desea usar la funcionalidad predeterminada de carga automática.

Django implementa su auto_reload mediante subprocesos y, por lo tanto, importa AppConfig en dos subprocesos separados, el subproceso principal de ‘comando / observación’ y el subproceso ‘recargar’ que ejecuta el servidor. Agregue una statement de impresión al módulo y verá esto en acción. El subproceso ‘principal’ carga los archivos AppConfig como parte de su ejecución BaseCommand, y el subproceso ‘recargar’ luego los vuelve a cargar durante el inicio del servidor.

Si tiene un código que no se puede ejecutar en estos dos subprocesos, entonces sus opciones son algo limitadas. Puede implementar un locking de subprocesos para que el subproceso ‘recargar’ no se ejecute ready (); puede pasar a un entorno de producción para ejecutar su servidor (por ejemplo, Gunicorn es muy rápido de configurar, incluso para pruebas); o puede llamar a su método de otra manera en lugar de usar ready ().

Le aconsejaría que se traslade a un entorno adecuado, pero la mejor opción realmente depende del método que se supone que debe hacer exactamente.

Es necesario implementar el locking. No es un problema simple y la solución no será natural ya que está tratando con procesos y subprocesos. Tenga en cuenta que hay muchas respuestas al problema del locking, algunos enfoques más simples:

Un locking de archivos: asegure una instancia única de una aplicación en Linux (tenga en cuenta que los subprocesos comparten el locking de archivos de forma predeterminada, por lo que esta respuesta debe ampliarse para tener en cuenta los subprocesos).

También existe esta respuesta que utiliza un paquete de Python llamado tendo que encapsula la implementación de un locking de archivo: https://stackoverflow.com/a/1265445/181907

El propio Django proporciona una utilidad de locking de archivos portátil abstracta en django.core.files.locks .

Si no quieres usar --noreload puedes:

reemplace la línea en el __init__.py su aplicación que usa para especificar la configuración:

 default_app_config = 'mydjangoapp.apps.MydjangoappConfig' 

por esto:

 import os if os.environ.get('RUN_MAIN', None) != 'true': default_app_config = 'mydjangoapp.apps.MydjangoappConfig' 

Intente usar una variable de instancia, en lugar de una variable de clase. Por ejemplo:

 class MyAppConfig(AppConfig): run_already = False def ready(self): if not self.run_already: print('Hello, world!') self.run_already = True