Celery: Aufgaben beim Herunterfahren des Workers widerrufen/abbrechen

Erstellt am 24. Feb. 2016  ·  3Kommentare  ·  Quelle: celery/celery

Ich verwende 3.1.20 (Redis-Broker und -Backend) und hätte gerne eine Möglichkeit, die derzeit ausgeführten Aufgaben abzubrechen/zu widerrufen, wenn der Worker heruntergefahren wird.
Der Punkt ist, die Aufgaben wenn möglich als FEHLGESCHLAGEN zu markieren und sie nicht erneut auszuführen, wenn der Worker das nächste Mal neu startet.

Ich führe eine Aufgabe nach der anderen aus und da die Aufgabe Nebeneffekte hat (und das kann ich nicht ändern), wäre das Beenden des Arbeiters das erwartete Benutzerverhalten, wenn etwas schief geht, und ich möchte nicht, dass die Aufgabe als nächstes erneut ausgeführt wird Zeit, zu der ich den Worker starte (Standard-Sighandler-Verhalten, glaube ich ...)

Ich habe http://stackoverflow.com/a/8230470 ohne Erfolg versucht.
Und ich habe auch ein paar Dinge mit der Steuerschnittstelle oder dem Worker von einem Bootstep ausprobiert:

from celery import Celery, bootsteps
from celery.task.control import revoke

# TODO : configuration for tests...
class BootPyrosNode(bootsteps.StartStopStep):

    def __init__(self, worker, **kwargs):
        logging.warn('{0!r} is starting from {1}'.format(worker, __file__))

        [...]

    def create(self, worker):
        return self

    def start(self, worker):
        # our step is started together with all other Worker/Consumer
        # bootsteps.
        pass  # not sure in which process this is run.

    def stop(self, worker):
        # the Consumer calls stop every time the consumer is restarted
        # (i.e. connection is lost) and also at shutdown.  The Worker
        # will call stop at shutdown only.
        logging.warn('{0!r} is stopping. Attempting abort of current tasks...'.format(worker))
        for req in worker.state.active_requests:
            # worker.app.control.revoke(req.id, terminate=True) # not working
            # revoke(req.id, terminate=True) # not working
        self.node_proc.shutdown()

so installiert:

celeros_app = Celery()

# setting up custom bootstep to start ROS node and pass ROS arguments to it
celeros_app.steps['worker'].add(BootPyrosNode)
celeros_app.user_options['worker'].add(Option('-R', '--ros-arg', action="append", help='Arguments for ros initialisation'))

Es scheint jedoch, dass meine Aufgabe nicht widerrufen/abgebrochen werden kann (vielleicht weil der Worker nach dem Stoppen keine Kontrollnachrichten verarbeitet? ) Und mir gehen die Ideen aus.

Wenn Sie mehr sehen möchten, kommt der Code von: https://github.com/asmodehn/celeros.

Gibt es eine Möglichkeit oder ist dies eine Anpassung, die noch nicht möglich ist?

Feature Request

Hilfreichster Kommentar

Danke !
Es ist mir gelungen, laufende Aufgaben beim Herunterfahren des Workers zu widerrufen. :

def stop(self, worker):
        # the Consumer calls stop every time the consumer is restarted
        # (i.e. connection is lost) and also at shutdown.  The Worker
        # will call stop at shutdown only.
        logging.warn('{0!r} is stopping. Attempting termination of current tasks...'.format(worker))

        # Following code from worker.control.revoke

        task_ids = []
        terminated = set()

        # cleaning all reserved tasks since we are shutting down
        signum = _signals.signum('TERM')
        for request in [r for r in worker.state.reserved_requests]:
            if request.id not in terminated:
                task_ids.append(request.id)
                terminated.add(request.id)
                logger.info('Terminating %s (%s)', request.id, signum)
                request.terminate(worker.pool, signal=signum)

        # Aborting currently running tasks, and triggering soft timeout exception to allow task to clean up.
        signum = _signals.signum('USR1')
        for request in [r for r in worker.state.active_requests]:
            if request.id not in terminated:
                task_ids.append(request.id)
                terminated.add(request.id)
                logger.info('Terminating %s (%s)', request.id, signum)
                request.terminate(worker.pool, signal=signum)  # triggering SoftTimeoutException in Task

        if terminated:
            terminatedstr = ', '.join(task_ids)
            logger.info('Tasks flagged as revoked: %s', terminatedstr)

        self.node_proc.shutdown()

Zuerst widerrufe ich die Aufgabe in der Liste reserved_requests, um im Grunde zu verhindern, dass wartende Aufgaben kurz vor dem Herunterfahren übernommen werden.

Dann widerrufe ich die aktive Anfrage und löse dann die SoftTimeLimitExceeded-Ausnahme in der Aufgabe aus, um ein Bereinigungsverhalten in der Aufgabe auslösen zu können. Da ich acks_late verwende (um jeweils nur eine Aufgabe auszuführen), muss ich von der Aufgabe zurückkehren oder sie erhöhen, um sie ordnungsgemäß zu bestätigen, und sie muss nicht neu gestartet werden, wenn ich den Worker das nächste Mal starte.

Ich verwende abbrechbare Aufgaben, aber das Abbruchverhalten ist codiert, wenn ein Benutzer eine Aufgabe wissentlich abbrechen möchte und das System eine komplexe/lange Bereinigung durchführen muss. Dieser Fall ähnelt eher dem Herunterfahren des Workers, und in diesem Fall möchte ich, dass die aktuelle Aufgabe schnell fehlschlägt.

Ich denke, das wäre eine richtige Art, Dinge in Sellerie zu tun?

In einer zukünftigen Version wäre es schön, ein Verhalten in der Task-Klasse einfach neu definieren zu können... zum Beispiel das Überladen einer on_revoke()- oder on_abort()-Methode. Und vielleicht eine Möglichkeit, abhängig von bestimmten Bedingungen mehrere Verhaltensweisen beim Widerruf zu haben ...
Nur meine 2 Cent, ich habe Sellerie v4.0 noch nicht überprüft.

Alle 3 Kommentare

Sie können während des Herunterfahrens keine Fernsteuerungsbefehle an sich selbst senden, Sie müssen die Aufgaben mithilfe von Worker-Interna widerrufen (sehen Sie, wie der Fernsteuerungsbefehl in celery/worker/control.py implementiert ist).

Sie sollten wahrscheinlich auch sicherstellen, dass Ihr Bootstep vom Pool abhängt, damit Ihre Methode stop() beim Herunterfahren zuerst aufgerufen wird:

class Step..:
    requires = ('celery.worker.components:Pool',)

Danke !
Es ist mir gelungen, laufende Aufgaben beim Herunterfahren des Workers zu widerrufen. :

def stop(self, worker):
        # the Consumer calls stop every time the consumer is restarted
        # (i.e. connection is lost) and also at shutdown.  The Worker
        # will call stop at shutdown only.
        logging.warn('{0!r} is stopping. Attempting termination of current tasks...'.format(worker))

        # Following code from worker.control.revoke

        task_ids = []
        terminated = set()

        # cleaning all reserved tasks since we are shutting down
        signum = _signals.signum('TERM')
        for request in [r for r in worker.state.reserved_requests]:
            if request.id not in terminated:
                task_ids.append(request.id)
                terminated.add(request.id)
                logger.info('Terminating %s (%s)', request.id, signum)
                request.terminate(worker.pool, signal=signum)

        # Aborting currently running tasks, and triggering soft timeout exception to allow task to clean up.
        signum = _signals.signum('USR1')
        for request in [r for r in worker.state.active_requests]:
            if request.id not in terminated:
                task_ids.append(request.id)
                terminated.add(request.id)
                logger.info('Terminating %s (%s)', request.id, signum)
                request.terminate(worker.pool, signal=signum)  # triggering SoftTimeoutException in Task

        if terminated:
            terminatedstr = ', '.join(task_ids)
            logger.info('Tasks flagged as revoked: %s', terminatedstr)

        self.node_proc.shutdown()

Zuerst widerrufe ich die Aufgabe in der Liste reserved_requests, um im Grunde zu verhindern, dass wartende Aufgaben kurz vor dem Herunterfahren übernommen werden.

Dann widerrufe ich die aktive Anfrage und löse dann die SoftTimeLimitExceeded-Ausnahme in der Aufgabe aus, um ein Bereinigungsverhalten in der Aufgabe auslösen zu können. Da ich acks_late verwende (um jeweils nur eine Aufgabe auszuführen), muss ich von der Aufgabe zurückkehren oder sie erhöhen, um sie ordnungsgemäß zu bestätigen, und sie muss nicht neu gestartet werden, wenn ich den Worker das nächste Mal starte.

Ich verwende abbrechbare Aufgaben, aber das Abbruchverhalten ist codiert, wenn ein Benutzer eine Aufgabe wissentlich abbrechen möchte und das System eine komplexe/lange Bereinigung durchführen muss. Dieser Fall ähnelt eher dem Herunterfahren des Workers, und in diesem Fall möchte ich, dass die aktuelle Aufgabe schnell fehlschlägt.

Ich denke, das wäre eine richtige Art, Dinge in Sellerie zu tun?

In einer zukünftigen Version wäre es schön, ein Verhalten in der Task-Klasse einfach neu definieren zu können... zum Beispiel das Überladen einer on_revoke()- oder on_abort()-Methode. Und vielleicht eine Möglichkeit, abhängig von bestimmten Bedingungen mehrere Verhaltensweisen beim Widerruf zu haben ...
Nur meine 2 Cent, ich habe Sellerie v4.0 noch nicht überprüft.

Gibt es hierzu Neuigkeiten?

War diese Seite hilfreich?
0 / 5 - 0 Bewertungen