Si j'ai une fonction définie comme suit:
def add(x,y):
return x+y
Existe-t-il un moyen d'ajouter dynamiquement cette fonction en tant que Celer PeriodicTask et de la lancer au moment de l'exécution? J'aimerais pouvoir faire quelque chose comme (pseudocode):
some_unique_task_id = celery.beat.schedule_task(add, run_every=crontab(minute="*/30"))
celery.beat.start(some_unique_task_id)
Je voudrais également arrêter ou supprimer cette tâche dynamiquement avec quelque chose comme (pseudocode):
celery.beat.remove_task(some_unique_task_id)
ou
celery.beat.stop(some_unique_task_id)
Pour info je n'utilise pas djcelery, qui vous permet de gérer des tâches périodiques via l'administrateur Django.
Non, je suis désolé, ce n'est pas possible avec le céleri régulier.
Mais il est facilement extensible pour faire ce que vous voulez, par exemple le planificateur Django-céleri n'est qu'une sous-classe qui lit et écrit le calendrier dans la base de données (avec quelques optimisations en haut).
Vous pouvez également utiliser le planificateur Django-céleri même pour des projets non-Django.
Quelque chose comme ça:
Installer Django + Django-céleri:
$ pip install -U Django django-celery
Ajoutez les paramètres suivants à votre celeryconfig:
DATABASES = {
'default': {
'NAME': 'celerybeat.db',
'ENGINE': 'Django.db.backends.sqlite3',
},
}
INSTALLED_APPS = ('djcelery', )
Créez les tables de base de données:
$ PYTHONPATH=. Django-admin.py syncdb --settings=celeryconfig
Démarrez celerybeat avec le planificateur de base de données:
$ PYTHONPATH=. Django-admin.py celerybeat --settings=celeryconfig \
-S djcelery.schedulers.DatabaseScheduler
Il y a aussi la commande djcelerymon
qui peut être utilisée pour les projets non-Django pour démarrer celerycam et un Django Admin webserver dans le même processus, vous pouvez l'utiliser pour éditer également votre périodique tâches dans une belle interface web:
$ djcelerymon
(Notez que pour une raison quelconque, djcelerymon ne peut pas être arrêté en utilisant Ctrl + C, vous devez utiliser Ctrl + Z + tuer% 1)
Cette question a reçu une réponse le google groups .
JE NE SUIS PAS L'AUTEUR, tout le mérite revient à Jean Mark
Voici une solution appropriée pour cela. Fonctionnement confirmé, dans mon scénario, j'ai sous-classé la tâche périodique et créé un modèle à partir de celui-ci car je peux ajouter d'autres champs au modèle selon mes besoins et aussi pour pouvoir ajouter la méthode "terminer". Vous devez définir la propriété activée de la tâche périodique sur False et l'enregistrer avant de la supprimer. L'ensemble du sous-classement n'est pas un must, la méthode schedule_every est celle qui fait vraiment le travail. Lorsque vous êtes prêt à terminer votre tâche (si vous ne l'avez pas sous-classée), vous pouvez simplement utiliser PeriodicTask.objects.filter (name = ...) pour rechercher votre tâche, la désactiver, puis la supprimer.
J'espère que cela t'aides!
from djcelery.models import PeriodicTask, IntervalSchedule from datetime import datetime class TaskScheduler(models.Model): periodic_task = models.ForeignKey(PeriodicTask) @staticmethod def schedule_every(task_name, period, every, args=None, kwargs=None): """ schedules a task by name every "every" "period". So an example call would be: TaskScheduler('mycustomtask', 'seconds', 30, [1,2,3]) that would schedule your custom task to run every 30 seconds with the arguments 1,2 and 3 passed to the actual task. """ permissible_periods = ['days', 'hours', 'minutes', 'seconds'] if period not in permissible_periods: raise Exception('Invalid period specified') # create the periodic task and the interval ptask_name = "%s_%s" % (task_name, datetime.datetime.now()) # create some name for the period task interval_schedules = IntervalSchedule.objects.filter(period=period, every=every) if interval_schedules: # just check if interval schedules exist like that already and reuse em interval_schedule = interval_schedules[0] else: # create a brand new interval schedule interval_schedule = IntervalSchedule() interval_schedule.every = every # should check to make sure this is a positive int interval_schedule.period = period interval_schedule.save() ptask = PeriodicTask(name=ptask_name, task=task_name, interval=interval_schedule) if args: ptask.args = args if kwargs: ptask.kwargs = kwargs ptask.save() return TaskScheduler.objects.create(periodic_task=ptask) def stop(self): """pauses the task""" ptask = self.periodic_task ptask.enabled = False ptask.save() def start(self): """starts the task""" ptask = self.periodic_task ptask.enabled = True ptask.save() def terminate(self): self.stop() ptask = self.periodic_task self.delete() ptask.delete()
Cela a finalement été rendu possible par n correctif inclus dans céleri v4.1.0. Maintenant, il vous suffit de modifier les entrées de planification dans le backend de la base de données, et celery-beat agira selon la nouvelle planification.
Les documents décrivent vaguement comment cela fonctionne. L'ordonnanceur par défaut pour le céleri-beat, PersistentScheduler
, utilise un fichier shelve comme base de données de planification. Toute modification du beat_schedule
le dictionnaire dans l'instance PersistentScheduler
est synchronisé avec cette base de données (par défaut, toutes les 3 minutes), et vice-versa. Les documents décrivent comment ajouter de nouvelles entrées au beat_schedule
en utilisant app.add_periodic_task
. Pour modifier une entrée existante, ajoutez simplement une nouvelle entrée avec le même name
. Supprimez une entrée comme vous le feriez dans un dictionnaire: del app.conf.beat_schedule['name']
.
Supposons que vous souhaitiez surveiller et modifier votre programme de battements de céleri à l'aide d'une application externe. Ensuite, vous avez plusieurs options:
open
le fichier de base de données Shelve et lire son contenu comme un dictionnaire. Réécrire dans ce fichier pour des modifications.Il existe une bibliothèque appelée Django-celery-beat qui fournit les modèles dont on a besoin. Pour lui faire charger dynamiquement de nouvelles tâches périodiques, il faut créer son propre ordonnanceur.
from Django_celery_beat.schedulers import DatabaseScheduler
class AutoUpdateScheduler(DatabaseScheduler):
def tick(self, *args, **kwargs):
if self.schedule_changed():
print('resetting heap')
self.sync()
self._heap = None
new_schedule = self.all_as_schedule()
if new_schedule:
to_add = new_schedule.keys() - self.schedule.keys()
to_remove = self.schedule.keys() - new_schedule.keys()
for key in to_add:
self.schedule[key] = new_schedule[key]
for key in to_remove:
del self.schedule[key]
super(AutoUpdateScheduler, self).tick(*args, **kwargs)
@property
def schedule(self):
if not self._initial_read and not self._schedule:
self._initial_read = True
self._schedule = self.all_as_schedule()
return self._schedule
Vous pouvez vérifier cela flask-djcelery qui configure flask et djcelery et fournit également une api de repos consultable
Je cherchais la même solution pour Celery + Redis qui peut être flexible ajouter/supprimer. Découvrez celui-ci, redbeat , même gars de Heroku, même ils ont mis aussi le Redis + Sentinel.
L'espoir aide :)