Celery: μž‘μ—…μž μ’…λ£Œ μ‹œ μž‘μ—… μ·¨μ†Œ/쀑단

에 λ§Œλ“  2016λ…„ 02μ›” 24일  Β·  3μ½”λ©˜νŠΈ  Β·  좜처: celery/celery

3.1.20(Redis 브둜컀 및 λ°±μ—”λ“œ)을 μ‚¬μš©ν•˜κ³  있으며 μž‘μ—…μžκ°€ μ’…λ£Œλ  λ•Œ ν˜„μž¬ μ‹€ν–‰ 쀑인 μž‘μ—…μ„ 쀑단/μ·¨μ†Œν•˜λŠ” 방법을 μ•Œκ³  μ‹ΆμŠ΅λ‹ˆλ‹€.
μš”μ μ€ κ°€λŠ₯ν•œ 경우 μž‘μ—…μ„ FAILED둜 ν‘œμ‹œν•˜κ³  λ‹€μŒμ— μž‘μ—…μžκ°€ λ‹€μ‹œ μ‹œμž‘ν•  λ•Œ λ‹€μ‹œ μ‹€ν–‰ν•˜μ§€ μ•ŠλŠ” κ²ƒμž…λ‹ˆλ‹€.

ν•œ λ²ˆμ— ν•˜λ‚˜μ˜ μž‘μ—…μ„ μ‹€ν–‰ 쀑이고 μž‘μ—…μ— λΆ€μž‘μš©μ΄ μžˆμœΌλ―€λ‘œ(λ³€κ²½ν•  수 μ—†μŒ) μž‘μ—…μžλ₯Ό μ£½μ΄λŠ” 것은 λ¬Έμ œκ°€ λ°œμƒν–ˆμ„ λ•Œ μ˜ˆμƒλ˜λŠ” μ‚¬μš©μž 행동이 될 것이며 λ‹€μŒμ— μž‘μ—…μ„ λ‹€μ‹œ μ‹€ν–‰ν•˜κ³  싢지 μ•ŠμŠ΅λ‹ˆλ‹€. μž‘μ—…μžλ₯Ό μ‹œμž‘ν•  λ•Œ (λ‚΄κ°€ λ―ΏλŠ” κΈ°λ³Έ ν•œμˆ¨ λ™μž‘ ...)

λ‚˜λŠ” μ„±κ³΅ν•˜μ§€ μ•Šκ³  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(ν•œ λ²ˆμ— ν•˜λ‚˜μ˜ μž‘μ—…λ§Œ μ‹€ν–‰ν•˜κΈ° μœ„ν•΄)λ₯Ό μ‚¬μš©ν•˜κ³  μžˆμœΌλ―€λ‘œ μž‘μ—…μ„ μ˜¬λ°”λ₯΄κ²Œ μŠΉμΈν•˜κ³  λ‹€μŒμ— μž‘μ—…μžλ₯Ό μ‹œμž‘ν•  λ•Œ λ‹€μ‹œ μ‹œμž‘ν•˜μ§€ μ•Šλ„λ‘ μž‘μ—…μ—μ„œ λ³΅κ·€ν•˜κ±°λ‚˜ λ°œμƒμ‹œμΌœμ•Ό ν•©λ‹ˆλ‹€.

쀑단 κ°€λŠ₯ν•œ μž‘μ—…μ„ μ‚¬μš©ν•˜κ³  μžˆμ§€λ§Œ 쀑단 λ™μž‘μ€ μ‚¬μš©μžκ°€ μ˜λ„μ μœΌλ‘œ μž‘μ—…μ„ μ€‘λ‹¨ν•˜κ³  μ‹œμŠ€ν…œμ—μ„œ 일뢀 볡작/κΈ΄ 정리λ₯Ό μˆ˜ν–‰ν•΄μ•Ό ν•  λ•Œ μ½”λ”©λ©λ‹ˆλ‹€. 이 κ²½μš°λŠ” μž‘μ—…μžκ°€ μ’…λ£Œλ˜λŠ” 것과 κ°™μœΌλ©°, 이 경우 ν˜„μž¬ μž‘μ—…μ„ 빨리 μ‹€νŒ¨ν•˜κ²Œ λ§Œλ“€κ³  μ‹ΆμŠ΅λ‹ˆλ‹€.

λ‚˜λŠ” 이것이 μƒλŸ¬λ¦¬μ—μ„œ 일을 ν•˜λŠ” μ μ ˆν•œ 방법이라고 μƒκ°ν•©λ‹ˆκΉŒ?

ν–₯ν›„ λ²„μ „μ—μ„œλŠ” 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(ν•œ λ²ˆμ— ν•˜λ‚˜μ˜ μž‘μ—…λ§Œ μ‹€ν–‰ν•˜κΈ° μœ„ν•΄)λ₯Ό μ‚¬μš©ν•˜κ³  μžˆμœΌλ―€λ‘œ μž‘μ—…μ„ μ˜¬λ°”λ₯΄κ²Œ μŠΉμΈν•˜κ³  λ‹€μŒμ— μž‘μ—…μžλ₯Ό μ‹œμž‘ν•  λ•Œ λ‹€μ‹œ μ‹œμž‘ν•˜μ§€ μ•Šλ„λ‘ μž‘μ—…μ—μ„œ λ³΅κ·€ν•˜κ±°λ‚˜ λ°œμƒμ‹œμΌœμ•Ό ν•©λ‹ˆλ‹€.

쀑단 κ°€λŠ₯ν•œ μž‘μ—…μ„ μ‚¬μš©ν•˜κ³  μžˆμ§€λ§Œ 쀑단 λ™μž‘μ€ μ‚¬μš©μžκ°€ μ˜λ„μ μœΌλ‘œ μž‘μ—…μ„ μ€‘λ‹¨ν•˜κ³  μ‹œμŠ€ν…œμ—μ„œ 일뢀 볡작/κΈ΄ 정리λ₯Ό μˆ˜ν–‰ν•΄μ•Ό ν•  λ•Œ μ½”λ”©λ©λ‹ˆλ‹€. 이 κ²½μš°λŠ” μž‘μ—…μžκ°€ μ’…λ£Œλ˜λŠ” 것과 κ°™μœΌλ©°, 이 경우 ν˜„μž¬ μž‘μ—…μ„ 빨리 μ‹€νŒ¨ν•˜κ²Œ λ§Œλ“€κ³  μ‹ΆμŠ΅λ‹ˆλ‹€.

λ‚˜λŠ” 이것이 μƒλŸ¬λ¦¬μ—μ„œ 일을 ν•˜λŠ” μ μ ˆν•œ 방법이라고 μƒκ°ν•©λ‹ˆκΉŒ?

ν–₯ν›„ λ²„μ „μ—μ„œλŠ” Task ν΄λž˜μŠ€μ—μ„œ λ™μž‘μ„ κ°„λ‹¨νžˆ μž¬μ •μ˜ν•  수 있으면 쒋을 κ²ƒμž…λ‹ˆλ‹€... 예λ₯Ό λ“€μ–΄ on_revoke() λ˜λŠ” on_abort() λ©”μ„œλ“œλ₯Ό μ˜€λ²„λ‘œλ“œν•©λ‹ˆλ‹€. 그리고 일뢀 쑰건에 따라 μ·¨μ†Œ μ‹œ μ—¬λŸ¬ λ™μž‘μ„ ν•˜λŠ” 방법일 μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.
λ‚΄ 2 μ„ΌνŠΈ, λ‚˜λŠ” 아직 μ…€λŸ¬λ¦¬ v4.0을 ν™•μΈν•˜μ§€ μ•Šμ•˜μŠ΅λ‹ˆλ‹€.

이것에 λŒ€ν•œ μ–΄λ–€ μ—…λ°μ΄νŠΈ?

이 νŽ˜μ΄μ§€κ°€ 도움이 λ˜μ—ˆλ‚˜μš”?
0 / 5 - 0 λ“±κΈ‰