基于以前的一篇文章,celery+Rabbit MQ的安装和使用

本文更加详细的介绍如何安装和使用celey, Rabbit MQ。

并记录在使用celery时遇到的一些问题。

1.安装 Rabbit MQ

在 OS X上,直接执行如下命令:

  1. $ brew install rabbitmq

其他操作系统下的安装可以参考安装 RabbitMQ

启动RabbitMQ

  1. $ sudo rabbitmq-server

你也可以添加 -detached 属性来让它在后台运行(注意:只有一个破折号):

  1. $ sudo rabbitmq-server -detached

查看RabbitMQ状态

  1. $ sudo rabbitmqctl status

停止RabbitMQ

永远不要用 kill 停止 RabbitMQ 服务器,而是应该用 rabbitmqctl 命令:

  1. $ sudo rabbitmqctl stop

添加用户

默认用户guest,密码guest,只允许本地访问,如需远程访问,需要设置.

  1. $ sudo rabbitmqctl add_user test 123456
  2. Adding user "test" ...

添加虚拟主机,并赋予用户test权限

  1. $ sudo rabbitmqctl add_vhost myvhost
  2. Adding vhost "myvhost" ...
  1. $ sudo rabbitmqctl set_permissions -p myvhost test ".*" ".*" ".*"
  2. Setting permissions for user "test" in vhost "myvhost" ...

2.安装celery

2.1 创建虚拟环境,并安装celery

  1. $ mkdir celery_demo
  2. $ cd celery_demo
  3. $ virtualenv -p python3 venv3
  1. $ ./venv3/bin/pip install celery

2.2 配置celery

创建配置文件 celeryconfig.py,里面包含BROKER_URLCELERYD_LOG_FORMATCELERY_ROUTES.

  1. # celeryconfig.py
  2. RABBIT_MQ = {
  3. 'HOST': '127.0.0.1',
  4. 'PORT': 5672,
  5. 'USER': 'test',
  6. 'PASSWORD': '123456'
  7. }
  8. # broker
  9. BROKER_URL = 'amqp://%s:%s@%s:%s/myvhost' % (RABBIT_MQ['USER'], RABBIT_MQ['PASSWORD'], RABBIT_MQ['HOST'], RABBIT_MQ['PORT'])
  10. # celery日志格式
  11. CELERYD_LOG_FORMAT = '[%(asctime)s] [%(levelname)s] %(message)s'
  12. CELERY_ROUTES = {
  13. 'demo_task.add': {'queue': 'sunday'},
  14. }

其中,参数定义如下:

  • BROKER_URL指定了broker信息,即消息队列的地址。

  • CELERYD_LOG_FORMAT 指定了日志格式。

  • CELERY_ROUTES 指定了路由信息,即调用demo_task.add后,消息具体放入哪个队列,这里是队列名称为sunday

2.3 启动消费者

消费者

消费者代码如下:

  1. # demo_task.py
  2. from celery import Celery
  3. app = Celery("orange", backend='amqp')
  4. app.config_from_object("celeryconfig")
  5. @app.task
  6. def add(x, y):
  7. return x + y

首先,创建Celery实例,从文件中读取配置。

接着,定义task。

其中,在创建Celery实例时,参数backend指定了结果存储后端,用于追踪task执行状态和结果。这里使用amqp,即使用RabbitMQ保存结果。默认情况下,backend参数是关闭的。

使用celery worker启动消费者

  1. ./venv3/bin/celery worker -A demo_task -Q sunday --loglevel=info -f app.log
  2. celery@admindeMacBook-Pro-2.local v4.3.0 (rhubarb)
  3. Darwin-18.2.0-x86_64-i386-64bit 2019-04-20 17:49:40
  4. [config]
  5. .> app: orange:0x109ca0400
  6. .> transport: amqp://test:**@127.0.0.1:5672/myvhost
  7. .> results: disabled://
  8. .> concurrency: 8 (prefork)
  9. .> task events: OFF (enable -E to monitor tasks in this worker)
  10. [queues]
  11. .> sunday exchange=sunday(direct) key=sunday
  12. [tasks]
  13. . demo_task.add

其中,参数定义如下:

  • 参数-A 是app name,即定义celery的文件。

  • 参数-Q指定了队列的名称,如果不指定,默认为celery

  • 参数-f 指定了日志打印文件。

可以通过以下命令查看更多帮助信息:

  • celery help查看celery的选项
  • celery worker --help查看worker的选项

2.4 启动生产者

生产者

代码如下api.py所示:

  1. # api.py
  2. from demo_task import add
  3. print("start...")
  4. result = add.apply_async((1, 2))
  5. print("result:", result)
  6. print(result.ready())
  7. print("end...")

代码中,将12参数放入消息队列。

celery配置backend参数后, 调用任务时,会返回 AsyncResult 实例。

AsyncResultready() 方法可以查看任务是否完成处理。

执行api.py

执行结果分两种情况:worker启动和没有启动。

当celery worker启动的时候,结果如下:

  1. ./venv3/bin/python api.py
  2. start...
  3. result: 60dd0ab6-5fa2-4190-954e-584eb519384f
  4. True
  5. end...

可以看到,task很快得到执行,结果状态为True。

当celery worker没有启动的时候,结果如下:

  1. ./venv3/bin/python api.py
  2. start...
  3. result: 7280466f-73cd-44ec-85e7-5ad4f079a797
  4. False
  5. end...

可以看到,结果状态为False。

直接获取结果

可以使用get()函数等待任务完成,但这很少使用,因为它把异步调用变成了同步调用。

对于get()的使用,按照是否设置超时参数,分为两种:不使用超时参数timeout和使用超时参数timeout。

(1)不使用超时参数timeout

默认timeout为None,不会超时,而是阻塞住。

通过tcpdump抓包,可以发现,get调用后,每隔30s,RabbitMQ(server端)向生产者API(client端)发送心跳包,共发了5次。

最后,过了3分钟,RabbitMQ(server端)关闭连接,生产者API(client端)也关闭连接,报错:

  1. start...
  2. result: aae4fb20-823c-4674-8bff-28429f14d5d7
  3. False
  4. Traceback (most recent call last):
  5. File "api.py", line 13, in <module>
  6. result.get()
  7. File "/workspace/celery_demo/venv3/lib/python3.6/site-packages/celery/result.py", line 226, in get
  8. on_message=on_message,
  9. File "/workspace/celery_demo/venv3/lib/python3.6/site-packages/celery/backends/base.py", line 496, in wait_for_pending
  10. no_ack=no_ack,
  11. File "/workspace/celery_demo/venv3/lib/python3.6/site-packages/celery/backends/amqp.py", line 146, in wait_for
  12. on_interval=on_interval)
  13. File "/workspace/celery_demo/venv3/lib/python3.6/site-packages/celery/backends/amqp.py", line 223, in consume
  14. conn, consumer, timeout, on_interval)[task_id]
  15. File "/workspace/celery_demo/venv3/lib/python3.6/site-packages/celery/backends/amqp.py", line 204, in drain_events
  16. wait(timeout=1)
  17. File "/workspace/celery_demo/venv3/lib/python3.6/site-packages/kombu/connection.py", line 315, in drain_events
  18. return self.transport.drain_events(self.connection, **kwargs)
  19. File "/workspace/celery_demo/venv3/lib/python3.6/site-packages/kombu/transport/pyamqp.py", line 103, in drain_events
  20. return connection.drain_events(**kwargs)
  21. File "/workspace/celery_demo/venv3/lib/python3.6/site-packages/amqp/connection.py", line 500, in drain_events
  22. while not self.blocking_read(timeout):
  23. File "/workspace/celery_demo/venv3/lib/python3.6/site-packages/amqp/connection.py", line 505, in blocking_read
  24. frame = self.transport.read_frame()
  25. File "/workspace/celery_demo/venv3/lib/python3.6/site-packages/amqp/transport.py", line 256, in read_frame
  26. frame_header = read(7, True)
  27. File "/workspace/celery_demo/venv3/lib/python3.6/site-packages/amqp/transport.py", line 448, in _read
  28. raise IOError('Server unexpectedly closed connection')
  29. OSError: Server unexpectedly closed connection

(2)使用超时参数timeout

如果使用timeout参数,get(timeout)调用发起后, 当超过timeout指定的时间仍然没有获得结果,会超时报错。

例如,调用get(timeout=1)

  1. ... ...
  2. # sync
  3. print(result.get(timeout=1))
  4. print("end...")

如果worker没有启动或者worker处理超时,get会报超时错误:

  1. start...
  2. result: 190ad871-aae2-48ac-a18e-962cd2d537b7
  3. False
  4. Traceback (most recent call last):
  5. File "/workspace/celery_demo/venv3/lib/python3.6/site-packages/celery/backends/amqp.py", line 146, in wait_for
  6. on_interval=on_interval)
  7. File "/workspace/celery_demo/venv3/lib/python3.6/site-packages/celery/backends/amqp.py", line 223, in consume
  8. conn, consumer, timeout, on_interval)[task_id]
  9. File "/workspace/celery_demo/venv3/lib/python3.6/site-packages/celery/backends/amqp.py", line 202, in drain_events
  10. raise socket.timeout()
  11. socket.timeout
  12. During handling of the above exception, another exception occurred:
  13. Traceback (most recent call last):
  14. File "api.py", line 14, in <module>
  15. print(result.get(timeout=1))
  16. File "/workspace//celery_demo/venv3/lib/python3.6/site-packages/celery/result.py", line 226, in get
  17. on_message=on_message,
  18. File "/workspace/celery_demo/venv3/lib/python3.6/site-packages/celery/backends/base.py", line 496, in wait_for_pending
  19. no_ack=no_ack,
  20. File "/workspace/celery_demo/venv3/lib/python3.6/site-packages/celery/backends/amqp.py", line 148, in wait_for
  21. raise TimeoutError('The operation timed out.')
  22. celery.exceptions.TimeoutError: The operation timed out.

2.5 查看结果

查看app.log中的日志

  1. [2019-04-20 20:53:59,327] [INFO] Connected to amqp://test:**@127.0.0.1:5672/myvhost
  2. [2019-04-20 20:53:59,345] [INFO] mingle: searching for neighbors
  3. [2019-04-20 20:54:00,379] [INFO] mingle: all alone
  4. [2019-04-20 20:54:00,441] [INFO] celery@admindeMacBook-Pro-2.local ready.
  5. [2019-04-20 20:55:46,498] [INFO] Received task: demo_task.add[1c8d47bd-449d-4bd9-b4db-819777081d23]
  6. [2019-04-20 20:55:46,561] [INFO] Task demo_task.add[1c8d47bd-449d-4bd9-b4db-819777081d23] succeeded in 0.060540573904290795s: 3

3.任务过期

调用apply_async时使用参数expires,则表示任务有超时时间,超过这个时间后,task不会得到执行。

  1. result = add.apply_async((1, 2), expires=10)

当worker没有启动或者其他异常情况下,会出现任务超时,不被执行。

查看日志,可以看到task过期,不会被执行。

  1. [2019-04-20 21:32:45,828] [INFO] Received task: demo_task.add[12691c27-3f2f-4c96-9b4e-54636e20d0eb] expires:[2019-04-20 13:31:51.030013+00:00]
  2. [2019-04-20 21:32:45,829] [INFO] Discarding revoked task: demo_task.add[12691c27-3f2f-4c96-9b4e-54636e20d0eb]

3.参考

Celery 初步

calling API

Configuration and defaults

expiration

celery+Rabbit MQ实战记录的更多相关文章

  1. celery rabbit mq 详解

    Celery介绍和基本使用 Celery 是一个 基于python开发的分布式异步消息任务队列,通过它可以轻松的实现任务的异步处理, 如果你的业务场景中需要用到异步任务,就可以考虑使用celery, ...

  2. celery+RabbitMQ 实战记录2—工程化使用

    上篇文章中,已经介绍了celery和RabbitMQ的安装以及基本用法. 本文将从工程的角度介绍如何使用celery. 1.配置和启动RabbitMQ 请参考celery+RabbitMQ实战记录. ...

  3. Rabbit MQ config文件解析

    Rabbit MQ config文件解析 tcp_listeners:用于监听AMQP连接的端口或主机名/对(不带TLS),默认端口:5672 2.numtcpacceptors :将接受TCP侦听器 ...

  4. Spring Boot:使用Rabbit MQ消息队列

    综合概述 消息队列 消息队列就是一个消息的链表,可以把消息看作一个记录,具有特定的格式以及特定的优先级.对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息,对消息队列有读权限的进程则可以 ...

  5. 使用Rabbit MQ消息队列

    使用Rabbit MQ消息队列 综合概述 消息队列 消息队列就是一个消息的链表,可以把消息看作一个记录,具有特定的格式以及特定的优先级.对消息队列有写权限的进程可以向消息队列中按照一定的规则添加新消息 ...

  6. redis反向代理docker容器中的rabbit mq服务

    最近做的项目中用到了docker,发现docker容器还真挺好用的,可以统一来管理各种资源,项目. 但是在实际使用中就碰到下面这个问题(下面所有的应用都是在docker中启动的): 通过nginx来反 ...

  7. 在 Windows 上安装Rabbit MQ 指南

    rabbitMQ是一个在AMQP协议标准基础上完整的,可服用的企业消息系统.他遵循Mozilla Public License开源协议.采用 Erlang 实现的工业级的消息队列(MQ)服务器. Ra ...

  8. windows下的php rabbit mq安装、配置

    http://www.cnblogs.com/shanyou/p/4067250.html 这篇博文写的rabbit mq和erlang的安装以及rabbitmq可视化插件的一些操作 接下去开始安装P ...

  9. (转)在 Windows 上安装Rabbit MQ 指南

    rabbitMQ是一个在AMQP协议标准基础上完整的,可服用的企业消息系统.他遵循Mozilla Public License开源协议.采用 Erlang 实现的工业级的消息队列(MQ)服务器. Ra ...

随机推荐

  1. Problem 6: Sum square difference

    The sum of the squares of the first ten natural numbers is, 12 + 22 + ... + 102 = 385 The square of ...

  2. Java面试题集锦(持续更新)

    1.面向对象的特征有哪些方面? 答:面向对象的特征主要有以下几个方面: -抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面.抽象只关注对象有哪些属性和行为,并不关注这 ...

  3. day14 内置函数二

    lamda 语法: 函数名 = lambda 参数: 返回值注意: 1. 函数的参数可以有多个. 多个参数之间⽤逗号隔开 2. 匿名函数不管多复杂. 只能写⼀⾏, 且逻辑结束后直接返回数据 3. 返回 ...

  4. bat给文件追加换行内容

    如果有很多文件怎么给文件结尾追加换行内容呢? bat似乎没有专门的换行符,要实现似乎只能echo一下 set filename="123.txt" echo.>>%fi ...

  5. cf A Simple Task---线段树

    Examples Input 10 5abacdabcda7 10 05 8 11 4 03 6 07 10 1 Output cbcaaaabdd Input 10 1agjucbvdfk1 10 ...

  6. Regular Express 匹配中文,所有中文标点符号

    import re import requests text=requests.get("https://movie.douban.com").text #1.匹配汉字 \u4E0 ...

  7. 添加宿主为控制台应用程序的WCF服务

    1.创建WCF服务库:WcfServiceLibrary,根据自动创建的代码修改自己的WCF 服务协议.操作协议.数据协议.本次先实现简单的WCF最基本的通信方式:请求->应答模式. 定义服务. ...

  8. 我的自定义框架 || 基于Spring Boot || 第一步

    今天在园子里面看到一位大神写的springboot做的框架,感觉挺不错,遂想起来自己还没有一个属于自己的框架,决定先将大神做好的拿过来,然后加入自己觉得需要的模块,不断完善 目前直接复制粘贴过来的,后 ...

  9. Windows10 VS2017 C++模拟点击按键

    #include "pch.h" #include <Windows.h> #include <stdio.h> #include <iostream ...

  10. 浅谈java中的祖先类Object

    首先一道题: public class User{ private String name; private int age; public String getName() { return nam ...