Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

147
Visualizações
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 Respostas
Responde à pergunta

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 Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda