celery-redbeat实现异步任务调度

介绍:

   Python项目,需要异步调度,包含定时任务,可引入Celery及celery-redbeat作为调度工具。

其中,celery[Celery - Distributed Task Queue — Celery 5.2.7 documentation]是python的任务调度框架,celery-redbeat是clelery beat[Welcome to Celery Redbeat’s documentation! — Celery Redbeat documentation]的一种,用于监听任务,需依靠redis


目标:

   通过实例讲解,了解如何使用celery-redbeat监听任务,实现实时任务


Demo:

环境:Python==3.7.5 celery==5.2.7 redis==4.3.4 eventlet==0.33.1 celery-redbeat==2.0.0

目录:

(1)创建celery配置, celery_config.py

# celery worker 配置
broker_url = 'redis://:$password@$host:$port/db'        # broker url, db=0
result_backend = 'redis://:$password@$host:$port/db'     # 结果存储, db=1
task_serializer = 'json'
result_serializer = 'json'
accept_content = ['application/json']
timezone = 'Asia/Shanghai'
enable_utc = False
task_compression = "gzip"
worker_max_tasks_per_child = 100                            # 一个worker进程最多执行任务数
worker_cancel_long_running_tasks_on_connection_loss = True  # 连接中断重连后,无需重复发送任务
worker_log_format = "[%(asctime)s][%(levelname)s][%(processName)s] %(message)s"  # 日志

# celery beat 配置
beat_scheduler = 'redbeat.RedBeatScheduler'
redbeat_redis_url = broker_url
redbeat_key_prefix = 'redbeat'                      # 任务前缀
redbeat_redis_options = {'max_retries': 3}
beat_max_loop_interval = 1                          # 监听频率,秒
redbeat_lock_timeout = beat_max_loop_interval * 5   # 锁超时,秒

# 配置路由,可以不配置,默认是celery队列
task_routes = {
    'demo.tasks.add': {'queue': 'add'},
    'demo.tasks.div': {'queue': 'div'},
}

(2) 创建celery 任务,tasks.py

from abc import ABC

from celery.utils.log import get_task_logger
from celery import Task

from demo import app

logger = get_task_logger(__name__)


class AsyncTask(Task, ABC):
    """ 重写Task类 """

    def before_start(self, task_id, args, kwargs):
        """ 任务开始前 """

        logger.info('=1111==before_start=task_id={}==args={}==kwargs={}==task=={}'.
                    format(task_id, args, kwargs, self.request.task))

    def on_failure(self, exc, task_id, args, kwargs, einfo):
        """ 任务执行失败 """

        logger.error('=222==on_failure=task_id={}==args={}==kwargs={}=exc={}=einfo={}==task=={}'.
                     format(task_id, args, kwargs, exc, einfo, self.request.task))

    def on_success(self, retval, task_id, args, kwargs):
        """ 任务执行成功 """

        logger.info('=333==on_success=task_id={}==args={}==kwargs={}==retval={}=task=={}'.
                    format(task_id, args, kwargs, retval, self.request.task))

    def on_retry(self, exc, task_id, args, kwargs, einfo):
        """ 任务重试 """

        logger.warning('=444==on_retry=task_id={}==args={}==kwargs={}=exc={}=einfo={}==task=={}'.
                       format(task_id, args, kwargs, exc, einfo, self.request.task))


# 任务一
@app.task(base=AsyncTask)
def add(x, y):
    return x + y


# 任务二
@app.task(base=AsyncTask)
def div(x, y):
    return x / y

(3) 创建celery app, demo.py

from celery import Celery

app = Celery('demo', include=['tasks'])  # demo是celery应用名,include加载创建好的任务
app.config_from_object('celery_config')  # 加载celery 配置


if __name__ == '__main__':
    app.start()   # 启动
    print(app.conf.humanize(with_defaults=False, censored=True))

(4) 创建调度任务,scheduler.py

from redbeat import RedBeatSchedulerEntry
from celery.schedules import schedule, crontab

from celery import Celery

app = Celery(include=['tasks'])
app.config_from_object("celery_config")

task_name = ":task-add"  # ":"是分割符,建议加上
entry = RedBeatSchedulerEntry(app=app, name=task_name,  # 任务名
                              task='tasks.add',  # 任务,需要与tasks.py任务名一致
                              #schedule=schedule(run_every=11), # 调度规则,每多少秒循环执行
                              schedule=crontab(minute='*/10'),  # 调度规则,定时任务
                              args=[3, 11],  # 任务参数
                              enabled=True,  # 开启,False时关闭任务
                              options={"queue": 'add'}  # 指定队列, celery worker启动时需要指定队列
                              )

entry.save()

# 通过key,删除任务
key = 'redbeat:task-add'   # 配置中的redbeat_key_prefix + task_name
entry = RedBeatSchedulerEntry.from_key(key, app=app)
entry.delete()

# 终止执行中的任务
from demo import app
celery_id = "b67bd725-6dc1-4c63-a184-b0faae736d17"
app.control.revoke(celery_id, terminate=True)

注意事项:同一任务暂停后,再启动,可能到调度时刻执行两次,可用RedBeatSchedulerEntry.from_key(key, app=app).reschedule()解决

调度规则参考:Periodic Tasks — Celery 5.2.7 documentation


启动:

(1) celery worker:

celery -A demo worker -c 2  -P eventlet -l INFO -Q celery,add  -f /tmp/worker.log

-A 应用名 

-c worker数 

-P 执行池[windows 只能是solo] 

-l 日志类型 

-f 日志文件

-Q 调度队列[只有在配置了task_routes时使用]

 (2) celery beat:

celery -A demo beat -l INFO -f /tmp/beat .log

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值