Apio auto recarga en CUALQUIER cambio.

Podría hacer que el apio se vuelva a cargar automáticamente cuando haya cambios en los módulos en CELERY_IMPORTS en settings.py .

Intenté dar módulos de la madre para detectar cambios incluso en módulos secundarios, pero no detectó cambios en los módulos secundarios. Eso me hace entender que la detección no se hace recursivamente por el apio. Lo busqué en la documentación pero no encontré ninguna respuesta para mi problema.

Realmente me molesta agregar todo lo relacionado con la parte de apio de mi proyecto a CELERY_IMPORTS para detectar cambios.

¿Hay una manera de decirle al apio que “se recarga automáticamente cuando hay algún cambio en cualquier parte del proyecto”.

¡Gracias!

Puede incluir manualmente módulos adicionales con -I|--include . Combínelo con las herramientas de GNU como find y awk y podrá encontrar todos los archivos .py e incluirlos.

 $ celery -A app worker --autoreload --include=$(find . -name "*.py" -type f | awk '{sub("\./",""); gsub("/", "."); sub(".py",""); print}' ORS=',' | sed 's/.$//') 

Vamos a explicarlo:

 find . -name "*.py" -type f 

find búsquedas recursivamente para todos los archivos que contienen .py . La salida se ve algo como esto:

 ./app.py ./some_package/foopy ./some_package/bar.py 

Entonces:

 awk '{sub("\./",""); gsub("/", "."); sub(".py",""); print}' ORS=',' 

Esta línea toma la salida de find como entrada y elimina todas las apariciones de ./ . Entonces reemplaza todo / con a . . El último sub() elimina reemplaza .py por una cadena vacía. ORS reemplaza todas las nuevas líneas con,. Esto produce:

 app,some_package.foo,some_package.bar, 

El último comando, sed elimina el último sed

Entonces el comando que se está ejecutando se ve como:

 $ celery -A app worker --autoreload --include=app,some_package.foo,some_package.bar 

Si tiene un virtualenv dentro de su fuente, puede excluirlo agregando -path .path_to_your_env -prune -o :

 $ celery -A app worker --autoreload --include=$(find . -path .path_to_your_env -prune -o -name "*.py" -type f | awk '{sub("\./",""); gsub("/", "."); sub(".py",""); print}' ORS=',' | sed 's/.$//') 

El apio --autoreload no funciona y está en desuso .

Ya que está usando django, puede escribir un comando de administración para eso. Django tiene la utilidad de carga automática que utiliza runerver para reiniciar el servidor WSGI cuando cambia el código.

La misma funcionalidad se puede utilizar para recargar los trabajadores de apio. Crear un comando de gestión por separado llamado apio. Escribe una función para matar al trabajador existente y comenzar un nuevo trabajador. Ahora enganche esta función para cargar automáticamente de la siguiente manera.

 import shlex import subprocess from django.core.management.base import BaseCommand from django.utils import autoreload def restart_celery(): cmd = 'pkill celery' subprocess.call(shlex.split(cmd)) cmd = 'celery worker -l info -A foo' subprocess.call(shlex.split(cmd)) class Command(BaseCommand): def handle(self, *args, **options): print('Starting celery worker with autoreload...') autoreload.main(restart_celery) 

Ahora puede ejecutar python manage.py celery worker con python manage.py celery que se cargará automáticamente cuando cambie la base de código.

Esto es solo para propósitos de desarrollo y no lo use en producción. Código tomado de mi otra respuesta aquí .

La solución de OrangeTux no funcionó para mí, así que escribí un pequeño script de Python para lograr más o menos lo mismo. Supervisa los cambios de archivos utilizando inotify y activa un reinicio de apio si detecta un IN_MODIFY , IN_ATTRIB o IN_DELETE .

 #!/usr/bin/env python """Runs a celery worker, and reloads on a file change. Run as ./run_celery [directory]. If directory is not given, default to cwd.""" import os import sys import signal import time import multiprocessing import subprocess import threading import inotify.adapters CELERY_CMD = tuple("celery -A amcat.amcatcelery worker -l info -Q amcat".split()) CHANGE_EVENTS = ("IN_MODIFY", "IN_ATTRIB", "IN_DELETE") WATCH_EXTENSIONS = (".py",) def watch_tree(stop, path, event): """ @type stop: multiprocessing.Event @type event: multiprocessing.Event """ path = os.path.abspath(path) for e in inotify.adapters.InotifyTree(path).event_gen(): if stop.is_set(): break if e is not None: _, attrs, path, filename = e if filename is None: continue if any(filename.endswith(ename) for ename in WATCH_EXTENSIONS): continue if any(ename in attrs for ename in CHANGE_EVENTS): event.set() class Watcher(threading.Thread): def __init__(self, path): super(Watcher, self).__init__() self.celery = subprocess.Popen(CELERY_CMD) self.stop_event_wtree = multiprocessing.Event() self.event_triggered_wtree = multiprocessing.Event() self.wtree = multiprocessing.Process(target=watch_tree, args=(self.stop_event_wtree, path, self.event_triggered_wtree)) self.wtree.start() self.running = True def run(self): while self.running: if self.event_triggered_wtree.is_set(): self.event_triggered_wtree.clear() self.restart_celery() time.sleep(1) def join(self, timeout=None): self.running = False self.stop_event_wtree.set() self.celery.terminate() self.wtree.join() self.celery.wait() super(Watcher, self).join(timeout=timeout) def restart_celery(self): self.celery.terminate() self.celery.wait() self.celery = subprocess.Popen(CELERY_CMD) if __name__ == '__main__': watcher = Watcher(sys.argv[1] if len(sys.argv) > 1 else ".") watcher.start() signal.signal(signal.SIGINT, lambda signal, frame: watcher.join()) signal.pause() 

Probablemente debería cambiar CELERY_CMD , o cualquier otra variable global.