Una vez cada cientos de miles de solicitudes veo una de estas:
ImportError at / cannot import name 'Config' from partially initialized module 'constance.base' (most likely due to a circular import) (/usr/local/lib/python3.9/site-packages/constance/base.py) No puedo identificar ninguna rima o razón. No se corresponde con el acceso al administrador de constance , solo ocurre al azar. Mi mejor suposición es que tiene algo que ver con el LazyObject en constance's __init__.py , y tal vez condiciones de carrera aleatorias al reiniciar trabajadores de gunicorn caducados o algo así.
Estoy usando:
django-constance = {extras = ["database"],version = "==2.8.*"}"constance" y "constance.backends.database" en INSTALLED_APPS (en la parte superior)CONSTANCE_BACKEND = "constance.backends.database.DatabaseBackend""constance.context_processors.config" en TEMPLATES[0]["OPTIONS"]["context_processors"] Todo lo que hace mi código es from constance import config y acceder a los atributos de config de la manera estándar en el código de python y las plantillas de Django.
Por lo que vale, hemos estado usando django-constance en este sitio durante años, pero nunca vimos este error hasta que actualizamos a 2.8.0 (desde 2.6.0 ). Estábamos usando Django 3.1 cuando apareció por primera vez, pero también ha ocurrido desde que actualizamos a 3.2.
No puedo encontrar ningún informe de error similar en https://github.com/jazzband/django-constance/
¿Alguna idea de qué podría estar causando esto y cómo resolverlo?
Este fue un error en la constancia que se resolvió en esta solicitud de extracción.
La raíz del problema es que antes de esta solicitud de extracción, constance testsuite no ejecutó pruebas en Django 3.2, que se solucionó y los cambios que causaron su error también se descartaron y arreglaron.
Eso significa que en constance's __init__.py , ahora hay una cláusula if que separa el manejo actual de la importación en Django 3.2 de las versiones anteriores de Django.
Bien, logré reproducir el problema y localizar la causa probable.
Logré activarlo una vez usando el servidor de ejecución de runserver , en la primera solicitud manejada, pero en cientos de reinicios/intentos posteriores no pude hacer que se repitiera.
Luego, en su lugar, ejecuté un par de subprocesos de trabajo de gunicorn locales con un umbral bajo de solicitudes por trabajador, y envié spam al puerto local con solicitudes rápidas, y efectivamente, el ImportError ocurre de vez en cuando.
El problema parece ser este:
constance.__init__ usa un django.utils.functional.LazyObject que, una vez evaluado perezosamente, importa constance.base e instancia una Config de ese módulo.
constance.base.Config.__init__ usa constance.utils.import_module_attr para importar el backend especificado en la configuración del proyecto, que a su vez usa importlib.import_module para importar, en mi caso, constance.backends.database.DatabaseBackend .
constance.backends.database.__init__ también importa la config de ... ( constance ), lo que podría crear un bucle de importación.
Parece que hay una condición de carrera rara en la que LazyConfig._setup intenta importar constance.base.Config mientras que constance.base no se ha inicializado por completo. Inyecté algunas declaraciones de depuración para demostrar, y la secuencia con errores se ve así:
[2021-09-15 09:35:10 +1000] [13504] [INFO] Booting worker with pid: 13504 BEGIN constance.__init__.LazyConfig._setup() vars(self): {'_wrapped': <object object at 0x108da8340>} BEGIN constance.__init__.LazyConfig._setup() vars(self): {'_wrapped': <object object at 0x108da8340>} constance.base imported constance.base.Config.__init__: importing constance.backends.database.DatabaseBackend ImportError at / cannot import name 'Config' from partially initialized module 'constance.base' (most likely due to a circular import) (/usr/local/lib/python3.9/site-packages/constance/base.py) EXIT constance.__init__.LazyConfig._setup() vars(self): {'_wrapped': <constance.base.Config object at 0x10fa7ea30>} Parece que solo sucede cuando se llama a _setup dos veces seguidas, antes de importar constance.base , entonces los dos subprocesos parecen correr desde ese punto.
Supongo que abriré un problema de GitHub en el repositorio django-constance para resolver el problema.