celery beat queue最佳实战配置

以下代码软件版本为:
Python 3.7.3
redis 3.2.1(pip3 install redis,用来连接redis数据库)
celery 4.3.0
redis数据库:redis-5.0.5

目录结构
注意:修改celery_profile、celery_tasks、celery_schedule都需要重启celery对应服务,求大神告知,添加任务和定时不重启服务的办法。

# 四个文件,都在celery文件夹里
celery 
		|
		celery_profile.py
		celery_tasks.py
		celery_schedule.py
		send_tasks.py

celery_profile.py

from celery import Celery
from kombu import Exchange, Queue

app = Celery('test',
             broker='redis://:123456@192.168.0.100/10',
             backend='redis://:123456@192.168.0.100/11',
             # 包含以下两个任务文件,去相应的py文件中找任务,对多个任务做分类
             )

# 看了一篇文章说,如果使用redis做broker,exchange可以不配置;但如果使用rabbitMQ做broker,就必须要配置。
# 如果不配置队列,下面命令可以注释掉(简单的环境,建议不要配置)。
queue = (
    Queue('default', exchange=Exchange('default', type='direct'), routing_key='default'),
    Queue('app_task1', exchange=Exchange('app_task1', type='direct'), routing_key='app_task1'),
    Queue('app_task2', exchange=Exchange('app_task2', type='direct'), routing_key='app_task2'),
)

# 一旦配置了route后,所有的任务名都必须要指定route,否则任务无法执行。
# 经过测试,route匹配是最长匹配规则。
'''
注意:
以下的配置,app_task1队列worker,不会处理task2任务。
但queue default队列的worker,会处理所有队列的任务。
也就是当队列app_task2的worker全部坏了,queue default的worker会处理这个队列的任务。
worker启动时,不指定队列,即不加-Q,那默认就属于这个队列,既可以为所有队列提供worker服务。默认队列名称为celery。
'''
route = {
    # 匹配任务名以task开头的任何任务。
    'task*': {'queue': 'app_task1', 'routing_key': 'app_task1'},
    # 精确匹配任务名称。task2名称的任务,就匹配这条路由。
    'task2': {'queue': 'app_task2', 'routing_key': 'app_task2'},
    # 其它的任务名称,匹配这条路由
    # 如果以上队列的worker服务器坏了,这些任务会被全部放进这个队列里,该队列的worker将继续处理这些任务
    # 下面这条队列一定要配置,否则其它任务无法处理。
    '*': {'queue': 'default', 'routing_key': 'default'},
}

app.conf.update(
    task_serializer='json',
    # Ignore other content
    accept_content=['json'],
    result_serializer='json',
    # 指定时区,不指定默认为 ‘UTC’
    timezone='Asia/Shanghai',
    enable_utc=False,
    # 任务结果一小时内没有获取则过期,缺省一天.
    # result_expires=3600,
    #  Number of CPU cores.机器缺省几核,这个数字就是多少.建议不要配置
    # worker_concurrency=4,
    # 如果不配置队列,下面两条命令可以注释掉(简单的环境,建议不要配置)。
    task_queues=queue,
    task_routes=route,
)

celery_tasks.py

from celery_profile import app
import time

# @app.task(name="task1", time_limit=10)  ,使用time_limit可以限制任务运行的时长,
# 超过这个时间任务没运行结束,进程会被强行杀掉重启,然后跳过这个任务,执行下一个任务.
@app.task(name='task1')
def celery_task1(arg):
    return 'celery_task1,执行结果为:%s' % arg

@app.task(name="task2")
def celery_task2(arg):
    return 'celery_task2,执行结果为:%s' % arg

# 做定时任务
@app.task(name='schedule_add')
def schedule_add(x, y):
    print('定时任务开始运行')
    x + y
    return x + y

celery_schedule.py

from celery_profile import app
from celery.schedules import crontab

app.conf.beat_schedule = {
    'add-every-monday-morning': {
        'task': 'schedule_add',
        'schedule': 1.0,
        'args': (16, 16),
    },
}

"""
可以使用crontab,增加定时灵活度
比如:
'schedule': crontab(hour=7, minute=30, day_of_week=1),
"""

send_tasks.py

from celery_tasks import celery_task1
from celery_tasks import celery_task2
from time import sleep
from datetime import timedelta
from datetime import datetime

result_1 = celery_task1.delay("第一个任务执行.")
print(result_1.id)
result_2 = celery_task2.delay("第二个任务执行.")
print(result_2.id)

# result_1 = celery_task1.apply_async(args=['第一个任务执行', ], countdown=15)
# print(result_1.id)
#
# result_1 = celery_task1.apply_async(args=['第一个任务执行', ], eta=datetime.now() + timedelta(seconds=10))
# print(result_1.id)

开启worker服务:
开启两个worker服务器,分别处理两个队列(-Q 后面加队列名称,指定worker处理的队列名称):
注意:非本队列的任务,这台worker就不会处理了。

celery worker -A celery_tasks -l info -n bruce1 -Q app_task1
celery worker -A celery_tasks -l info -n bruce2 -Q app_task2

# 后台启动方法为:
celery multi start logging/celery -A celery_tasks -l info -n bruce1 -Q app_task1

注意:后台启动,看不到下面这段话:

celery beat v4.3.0 (rhubarb) is starting.
__    -    ... __   -        _
LocalTime -> 2019-07-17 01:25:48
Configuration ->
    . broker -> redis://:**@192.168.0.100:6379/10
    . loader -> celery.loaders.app.AppLoader
    . scheduler -> celery.beat.PersistentScheduler
    . db -> celerybeat-schedule
    . logfile -> [stderr]@%INFO
    . maxinterval -> 5.00 minutes (300s)

我们同样也可以通过apply_aynsc()方法来设置任务发送到那个队列中:
这里配置任务加入队列,要高于route配置的。
result_1 = celery_task1.apply_async(queue=‘app_task2’)

我们也可设置一个worker服务器处理两个队列中的任务:
celery worker -A celery_tasks -l info -n bruce3 -Q app_task1,app_task2

如果启动不指定-Q队列,将处理所有队列任务。
celery worker -A celery_tasks -l info -n bruce4
启动之后,能够看到下面这么一段话:
-------------- [queues]
.> app_task1 exchange=app_task1(direct) key=app_task1
.> app_task2 exchange=app_task2(direct) key=app_task2
.> default exchange=default(direct) key=default

启动定时器:
celery beat -A celery_schedule -l info -f logging/schedule_tasks.log
-f logging/schedule_tasks.log:定时任务日志输出路径

后台运行,加参数"–detach":
celery beat -A celery_schedule -l info -f logging/schedule_tasks.log --detach

启动生产者:
python3 send_tasks.py

最简单的route queue配置:

下面这种配置,代码要比上面简单很多。在应用上,主要的区别是,缺省队列worker,不处理所有队列的任务,只负责缺省任务,即celery队列。

在celery_profile.py里,注释以上route queue代码,添加如下代码:

route = {
    # 匹配任务名以task开头的任何任务。
    'task*': {'queue': 'queue1'},
    # 精确匹配任务名称。task2名称的任务,就匹配这条路由。
    # 队列queue1,不会处理task2的任务。
    'task2': {'queue': 'queue2'},
    # 其它任务名称,全部放进celery队列里。这条代码不配置也可以,因为默认任务都在celery队列。
    # 注意:与上面的route配置不同,这种方式的配置,缺省队列的worker,不会对其它队列做任务处理。
    # '*': {'queue': 'celery'},
    }
    
app.conf.update(
    # 如果不配置队列,下面命令可以注释掉(简单的环境,建议不要配置)。
    task_routes=route,
)

启动worker:
celery worker -A celery_tasks -l info -n bruce4
可以看到如下这条信息,意味着只处理celery队列的任务

[queues]
                .> celery           exchange=celery(direct) key=celery
  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值