Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

135
Views
SynchronousOnlyOperation de la tarea de apio usando el grupo de ejecución de gevent

Dado el apio corriendo con estas opciones:

 celery -A openwisp2 worker -l info --pool=gevent --concurrency=15 -Ofair

Dada esta tarea de apio de openwisp-monitoring :

 @shared_task def perform_check(uuid): """ Retrieves check according to the passed UUID and calls ``check.perform_check()`` """ try: check = get_check_model().objects.get(pk=uuid) except ObjectDoesNotExist: logger.warning(f'The check with uuid {uuid} has been deleted') return result = check.perform_check() if settings.DEBUG: # pragma: nocover print(json.dumps(result, indent=4, sort_keys=True))

La mayoría de las veces la tarea funciona, pero algunas veces (generalmente con ráfagas), se genera la siguiente excepción:

 SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async.

Rastreo de pila completa:

 SynchronousOnlyOperation: You cannot call this from an async context - use a thread or sync_to_async. File "celery/app/trace.py", line 412, in trace_task R = retval = fun(*args, **kwargs) File "celery/app/trace.py", line 704, in __protected_call__ return self.run(*args, **kwargs) File "openwisp_monitoring/check/tasks.py", line 44, in perform_check check = get_check_model().objects.get(pk=uuid) File "django/db/models/manager.py", line 85, in manager_method return getattr(self.get_queryset(), name)(*args, **kwargs) File "django/db/models/query.py", line 425, in get num = len(clone) File "django/db/models/query.py", line 269, in __len__ self._fetch_all() File "django/db/models/query.py", line 1308, in _fetch_all self._result_cache = list(self._iterable_class(self)) File "django/db/models/query.py", line 53, in __iter__ results = compiler.execute_sql(chunked_fetch=self.chunked_fetch, chunk_size=self.chunk_size) File "django/db/models/sql/compiler.py", line 1154, in execute_sql cursor = self.connection.cursor() File "django/utils/asyncio.py", line 24, in inner raise SynchronousOnlyOperation(message)

No entiendo completamente por qué sucede esto.

Recapitulemos, corríjanme si me equivoco:

  1. con esta configuración, celery puede ejecutar tareas en paralelo, esta paralelización la realiza gevent usando un bucle de eventos asyncio
  2. gevent luego llama a cada tarea, usando el mismo hilo
  3. las tareas no están diseñadas para ser asincrónicas, usan código de sincronización simple, estas tareas realizan consultas de base de datos y solicitudes de red
  4. django tiene un decorador async_unsafe con el que se decoran las operaciones de la base de datos, este decorador comprueba si el bucle de eventos se está ejecutando y, en ese caso, genera una SynchronousOnlyOperation

Pero, ¿por qué esta excepción no se plantea en el 100% de los casos sino solo en una minoría de casos?

Esas tareas sí están funcionando, puedo verlo porque producen la recopilación de datos del gráfico que se muestra normalmente, o producen cambios de estado en el modelo del dispositivo (por ejemplo: ok a crítico).

¿Es un error en OpenWISP Monitoring, una mala configuración o un error en Django?

Parece que el bucle de eventos no se usa en Django, pero Django genera esta excepción a pesar de que no le concierne. Esto podría ser un error, pero me gustaría escuchar la opinión de expertos en el tema antes de presentar un informe de error.

Pensé que una posible solución rápida podría ser establecer la variable env DJANGO_ALLOW_ASYNC_UNSAFE pero solo en el proceso de apio.

Gracias por adelantado.

over 4 years ago · Santiago Trujillo
1 answers
Answer question

0

Resultó que mis suposiciones eran incorrectas y estaba usando un código que no era seguro con gevent.

Dado que reescribir el código para que sea seguro para greenlet por ahora no era una opción, cambié de nuevo a prefork.

over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!