Celery: ワーカーのシャットダウン時にタスクを取り消す/中止する

作成日 2016年02月24日  ·  3コメント  ·  ソース: celery/celery

3.1.20(Redisブローカーとバックエンド)を使用していますが、ワーカーがシャットダウンされているときに現在実行中のタスクを中止/取り消す方法が必要です。
重要なのは、可能であればタスクをFAILEDとしてマークし、次にワーカーが再開するときにタスクを再実行しないことです。

私は一度に1つのタスクを実行していますが、そのタスクには副作用があるため(変更できません)、問題が発生したときにワーカーを強制終了すると予想されるユーザーの動作になり、次にタスクを再実行したくありません。ワーカーを起動する時間(私が信じているデフォルトのsighandlerの動作...)

http://stackoverflow.com/a/8230470を試しましたが成功しませんでした。
また、ブートステップからコントロールインターフェイスまたはワーカーを使用していくつかのことを試しました。

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()

この方法でインストール:

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'))

しかし、私のタスクを取り消す/中止することはできないようです(おそらく、停止後にワーカーが制御メッセージを処理していないためですか?)、アイデアが不足しています。

詳細を確認したい場合は、コードはhttps://github.com/asmodehn/celerosから取得されます。

方法はありますか、それともこれはまだ不可能なカスタマイズですか?

Feature Request

最も参考になるコメント

ありがとう !
ワーカーのシャットダウン時に実行中のタスクを取り消すことができました。 :

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()

まず、reserved_requestsリストのタスクを取り消して、シャットダウンの直前に待機中のタスクが引き継ぐのを基本的に防ぎます。

次に、アクティブなリクエストを取り消してから、タスクでSoftTimeLimitExceeded例外をトリガーして、タスクでクリーンアップ動作をトリガーできるようにします。 私はacks_lateを使用しているので(一度に1つのタスクのみを実行するため)、タスクを正しく確認し、次にワーカーを起動したときに再起動しないように、タスクから戻るかレイズする必要があります。

中止可能なタスクを使用していますが、中止動作は、ユーザーが意図的にタスクを中止したい場合にコード化されており、システムは複雑で長いクリーンアップを実行する必要があります。 このケースは、ワーカーがシャットダウンしているようなものです。その場合、現在のタスクをすぐに失敗させたいと思います。

これはセロリで物事を行うための適切な方法だと思いますか?

将来のバージョンでは、Taskクラスの動作を単純に再定義できると便利です...たとえば、on_revoke()またはon_abort()メソッドをオーバーロードします。 そして、いくつかの条件に応じて、取り消し時に複数の動作をする方法かもしれません...
ちょうど私の2セント、私はまだセロリv4.0をチェックしていません。

全てのコメント3件

シャットダウン中にリモートコントロールコマンドを自分自身に送信することはできません。ワーカー内部を使用してタスクを取り消す必要があります(リモートコントロールコマンドがcelery / worker / control.pyでどのように実装されているかを参照してください)。

おそらく、ブートステップがプールに依存していることを確認して、シャットダウン時にstop()メソッドが最初に呼び出されるようにする必要があります。

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

ありがとう !
ワーカーのシャットダウン時に実行中のタスクを取り消すことができました。 :

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()

まず、reserved_requestsリストのタスクを取り消して、シャットダウンの直前に待機中のタスクが引き継ぐのを基本的に防ぎます。

次に、アクティブなリクエストを取り消してから、タスクでSoftTimeLimitExceeded例外をトリガーして、タスクでクリーンアップ動作をトリガーできるようにします。 私はacks_lateを使用しているので(一度に1つのタスクのみを実行するため)、タスクを正しく確認し、次にワーカーを起動したときに再起動しないように、タスクから戻るかレイズする必要があります。

中止可能なタスクを使用していますが、中止動作は、ユーザーが意図的にタスクを中止したい場合にコード化されており、システムは複雑で長いクリーンアップを実行する必要があります。 このケースは、ワーカーがシャットダウンしているようなものです。その場合、現在のタスクをすぐに失敗させたいと思います。

これはセロリで物事を行うための適切な方法だと思いますか?

将来のバージョンでは、Taskクラスの動作を単純に再定義できると便利です...たとえば、on_revoke()またはon_abort()メソッドをオーバーロードします。 そして、いくつかの条件に応じて、取り消し時に複数の動作をする方法かもしれません...
ちょうど私の2セント、私はまだセロリv4.0をチェックしていません。

これに関する更新はありますか?

このページは役に立ちましたか?
0 / 5 - 0 評価