如何在Celery-Django应用程序中监视工作人员的事件?

时间:2013-03-01 13:53:36

标签: python monitor django-celery

根据关于real-time monitoring of celery workers的芹菜教程,人们还可以通过编程方式捕捉工人制作的事件并采取相应的行动。

我的问题是如何在Celery-Django应用程序中将监视器集成为this示例中的监视器?

编辑: 本教程中的代码示例如下所示:

from celery import Celery

def my_monitor(app):
    state = app.events.State()

    def announce_failed_tasks(event):
        state.event(event)
        task_id = event['uuid']

        print('TASK FAILED: %s[%s] %s' % (
            event['name'], task_id, state[task_id].info(), ))
    with app.connection() as connection:
        recv = app.events.Receiver(connection, handlers={
                'task-failed': announce_failed_tasks,
                'worker-heartbeat': announce_dead_workers,
        })
        recv.capture(limit=None, timeout=None, wakeup=True)

if __name__ == '__main__':
    celery = Celery(broker='amqp://guest@localhost//')
    my_monitor(celery)

因此,我希望捕获worker发送的task_failed事件,并获得其教程显示的task_id,以便从为我的应用程序配置的结果后端获取此任务的结果并进一步处理。我的问题是,对于我来说,如何获取应用程序并不明显,因为在django-celery项目中,我对Celery库的实例化并不透明。

我也对工作人员完成任务时如何处理结果有任何其他想法。

2 个答案:

答案 0 :(得分:17)

好的,我找到了一种方法,虽然我不确定这是解决方案,但它对我有用。监视器功能基本上直接连接到代理并侦听不同类型的事件。我的代码如下所示:

from celery.events import EventReceiver
from kombu import Connection as BrokerConnection

def my_monitor:
    connection = BrokerConnection('amqp://guest:guest@localhost:5672//')

    def on_event(event):
        print "EVENT HAPPENED: ", event

    def on_task_failed(event):
        exception = event['exception']
        print "TASK FAILED!", event, " EXCEPTION: ", exception

    while True:
        try:
            with connection as conn:
                recv = EventReceiver(conn,
                                 handlers={'task-failed' : on_task_failed,
                                           'task-succeeded' : on_event,
                                           'task-sent' : on_event,
                                           'task-received' : on_event,
                                           'task-revoked' : on_event,
                                           'task-started' : on_event,
                                           # OR: '*' : on_event
                                           })
            recv.capture(limit=None, timeout=None)
    except (KeyboardInterrupt, SystemExit):
        print "EXCEPTION KEYBOARD INTERRUPT"
        sys.exit()

这就是全部。我在与普通应用程序不同的进程中运行它,这意味着我创建了一个只运行此函数的celery应用程序的子进程。 HTH

答案 1 :(得分:7)

小心一些陷阱

  1. 您需要在芹菜配置中将CELERY_SEND_EVENTS标志设置为true。
  2. 您还可以在工作人员的新主题中设置事件监视器。
  3. 这是我的实施:

    class MonitorThread(object):
        def __init__(self, celery_app, interval=1):
            self.celery_app = celery_app
            self.interval = interval
    
            self.state = self.celery_app.events.State()
    
            self.thread = threading.Thread(target=self.run, args=())
            self.thread.daemon = True
            self.thread.start()
    
        def catchall(self, event):
            if event['type'] != 'worker-heartbeat':
                self.state.event(event)
    
            # logic here
    
        def run(self):
            while True:
                try:
                    with self.celery_app.connection() as connection:
                        recv = self.celery_app.events.Receiver(connection, handlers={
                            '*': self.catchall
                        })
                        recv.capture(limit=None, timeout=None, wakeup=True)
    
                except (KeyboardInterrupt, SystemExit):
                    raise
    
                except Exception:
                    # unable to capture
                    pass
    
                time.sleep(self.interval)
    
    if __name__ == '__main__':
        app = get_celery_app() # returns app
        MonitorThread(app)
        app.start()