2011-06-23 1 views
4

J'ai une tâche que j'exécute une fois par minute en utilisant celerybeat. Ça fonctionne bien. Parfois cependant, la tâche prend quelques secondes de plus qu'une minute à courir à cause de laquelle deux instances de la tâche s'exécutent. Cela conduit à des conditions de course qui gâchent les choses.Faire une seule tâche à la fois dans celerybeat

Je peux (et je devrais probablement) réparer ma tâche pour fonctionner correctement, mais je voulais savoir si le céleri avait des moyens intégrés pour assurer cela. Mes recherches Google superficielles et RTFM n'ont donné aucun résultat.

+1

Je l'ai résolu, en utilisant quelque chose comme pid-file, Quand la tâche exécutée crée un fichier, quand arrête de supprimer le fichier. N'est pas une solution parfaite, mais fonctionne bien – Rustem

Répondre

0

Vous pouvez essayer d'ajouter un classfield à l'objet qui détient la fonction que vous êtes faire exécuter et utiliser ce champ comme « un autre gars travaille ou non » contrôle

+1

Je peux penser à beaucoup de façons en changeant mon code. Je veux savoir si celerybeat fournit quelque chose comme ça par lui-même. –

1

Si vous utilisez un calendrier cron ou le temps intervalle pour exécuter des tâches périodiques, vous aurez toujours le problème. Vous pouvez toujours utiliser un mécanisme de verrouillage à l'aide d'un db ou d'un cache ou même d'un système de fichiers ou encore planifier la tâche suivante à partir de la précédente, ce qui n'est peut-être pas la meilleure approche. Cette question peut probablement vous aider: django celery: how to set task to run at specific interval programmatically

+0

Je vais essayer ceux-ci. Merci! –

+0

Juste pour référence, je suis assez sûr que les intervalles de temps exécutent la tâche un certain laps de temps après la dernière exécution de _started_, pas l'exécution _finished_. En fait, je pense que Celerybeat ne suit même pas les tâches après leur envoi pour exécution. – nitwit

+0

@nitwit vous avez complètement raison. Dans ma réponse je dis "après la dernière exécution" je ne dis pas après l'exécution terminée. :-) Est également vrai que j'ai tort de dire "cela ne devrait pas arriver" Je vais modifier la réponse en conséquence. Merci –

2

Vous pourriez add a lock, en utilisant quelque chose comme memcached ou tout simplement votre base de données.

+0

C'est une bonne solution. Juste curieux, pourquoi utilisent-ils ces lambdas dans l'exemple? Pourquoi ne pas appeler 'add' et' delete' directement? Juste pour transmettre la sémantique, je suppose? – mgalgs

0

Le verrou est un bon moyen de battre ou un cron. Mais, sachez que les tâches rythmées s'exécutent à l'heure de début du travail, pas au moment de l'exécution.

Cela m'a amené à obtenir une condition de course, même avec un verrou. Disons que le travailleur est éteint et bat 10 projets dans la file d'attente. Quand le céleri commence avec 4 processus, tous les 4 attrapent une tâche et dans mon cas 1 ou 2 obtiendraient et placeraient la serrure en même temps.

La première solution consiste à utiliser un cron avec un verrou, car un cron s'exécutera à ce moment-là et non au début du travail.

La deuxième solution consiste à utiliser un mécanisme de verrouillage légèrement plus avancé qui gère les conditions de course. Pour redis regarder dans setnx, ou le plus récent redlock. Cet article de blog est vraiment bon, et comprend un modèle de décorateur qui utilise le mécanisme de verrouillage redis-py: http://loose-bits.com/2010/10/distributed-task-locking-in-celery.html.

Questions connexes