celery应用--周期性任务

Celery Beat是Celery框架的一个组件,用于调度和执行周期性任务,它允许在指定的时间间隔内自动触发任务的运行,而无需手动触发。

定义周期性任务

可以通过在Celery应用程序中定义周期性任务来使用Celery Beat,这些任务通常定义为带有@periodic_task装饰器的函数,指定任务的执行时间间隔。

from celery import Celery
from celery.schedules import crontab

app = Celery('myapp', broker='amqp://guest@localhost//')

@app.on_after_configure.connect
def setup_periodic_tasks(sender, **kwargs):
    # 每分钟执行一次任务
    sender.add_periodic_task(60.0, my_task.s(), name='my_task')

    # 每天凌晨执行任务
    sender.add_periodic_task(
        crontab(hour=0, minute=0),
        my_daily_task.s(),
        name='my_daily_task',
    )

@app.task
def my_task():
    print("执行周期性任务")

@app.task
def my_daily_task():
    print("执行每日任务")

在上述示例中,setup_periodic_tasks函数使用add_periodic_task方法定义了两个周期性任务。my_task任务将每分钟执行一次,而my_daily_task任务将在每天凌晨执行一次。

时间表选项

Celery Beat支持多种时间表选项,可用于定义任务的执行时间间隔。常见的选项包括:
crontab:基于类似Cron表达式的调度规则,例如每天特定时间执行、每周特定天执行等。
solar:基于日出、日落等太阳事件的调度规则。
schedule:基于固定时间间隔的调度规则,例如每隔一段时间执行一次。

from celery.schedules import crontab, solar, schedule

# 使用 crontab
sender.add_periodic_task(crontab(hour=1, minute=0), my_task.s())

# 使用 solar
sender.add_periodic_task(solar('sunrise', -30), my_task.s())

# 使用 schedule
sender.add_periodic_task(schedule(run_every=timedelta(minutes=5)), my_task.s())

配置Celery Beat

可以通过配置文件或命令行参数来配置Celery Beat的行为。其中一种常见的配置方法是使用celeryconfig.py文件,该文件包含了Celery Beat的配置选项。

# celeryconfig.py

# 使用 Redis 作为调度器
broker_url = 'redis://localhost:6379/0'

# 指定时区
timezone = 'Asia/Shanghai'

# 指定任务模块
beat_schedule = {
    'my_task': {
        'task': 'myapp.my_task',
        'schedule': crontab(hour=1, minute=0),
        'args': (),
    },
}

在上述示例中,我们使用Redis作为调度器,并配置了my_task任务的调度规则。

启动Celery Beat:要启动Celery Beat,可以使用celery beat命令。

celery -A myapp beat

这将启动Celery Beat进程,并根据配置文件中的设置调度和执行周期性任务。

Celery Beat是一个强大的工具,可用于自动调度和执行周期性任务。通过合理配置和使用Celery Beat,您可以轻松管理和执行定期运行的任务。

在 Celery 的 Beat 调度器中,你可以使用 crontab 和 timedelta 两种方式来定义定时任务的调度。

crontab:crontab 是一个类似于 UNIX 中的 cron 语法的调度器。它允许你以更精细的方式定义任务的执行时间。你可以指定分钟、小时、日期、月份和星期几等字段的值来创建复杂的调度规则。例如,每天的特定时间运行任务,每周的特定日期和时间运行任务等。

from celery.schedules import crontab

app.conf.beat_schedule = {
    'task1': {
        'task': 'my_app.my_task',
        'schedule': crontab(minute=0, hour='*/2'),  # 每隔两小时运行一次任务
    },
}

timedelta:timedelta 是一个相对时间间隔的调度器。你可以指定一个时间间隔,例如每隔多少秒、分钟、小时、天等运行任务。相对于 crontab,timedelta 更适合简单的定时任务场景。

from datetime import timedelta

app.conf.beat_schedule = {
    'task2': {
        'task': 'my_app.my_task',
        'schedule': timedelta(seconds=30),  # 每隔30秒运行一次任务
    },
}

总的来说,crontab 提供了更灵活和复杂的任务调度规则,可以精确到分钟和日期级别。而 timedelta 则适合简单的间隔时间调度,以秒、分钟、小时等为单位。

你可以根据任务的需求和调度规则选择合适的调度器类型,以实现准确和可靠的定时任务功能。

定时任务示例

使用celery实现一个周期性任务,每隔10s打印一次"hello,world"
1.创建一个目录my_scheduler,在该目录下创建两个文件
test/my_scheduler/celery.py

from celery import Celery

app = Celery('my_scheduler', broker='redis://127.0.0.1:6379/0', backend='redis://127.0.0.1:6379/0')
app.autodiscover_tasks(['my_scheduler.celery_task'])

app.conf.beat_schedule = {
    'hello-every-10-seconds': {
        'task': 'my_scheduler.celery_task.hello',
        'schedule': 10.0,
    },
}

test/my_scheduler/celery_task.py

from celery import Celery
from celery.schedules import crontab

# app = Celery('my_scheduler', broker='redis://localhost:6379/0')
from celery import shared_task


@shared_task
def hello():
    print('Hello, world!')

2.在test下执行

celery --broker=redis://127.0.0.1:6379/0 -A my_scheduler beat
D:\program\python\work_use\test>celery --broker=redis://127.0.0.1:6379/0 -A my_scheduler beat
celery beat v5.2.7 (dawn-chorus) is starting.
__    -    ... __   -        _
LocalTime -> 2024-04-17 15:24:03
Configuration ->
    . broker -> redis://127.0.0.1:6379/0
    . loader -> celery.loaders.app.AppLoader
    . scheduler -> celery.beat.PersistentScheduler
    . db -> celerybeat-schedule
    . logfile -> [stderr]@%WARNING
    . maxinterval -> 5.00 minutes (300s)

3.在test目录下执行

celery -A my_scheduler worker -l info -P eventlet
celery -A my_scheduler worker -l info -P eventlet
D:\APP_install\python\lib\site-packages\requests\__init__.py:102: RequestsDependencyWarning: urllib3 (1.26.8) or chardet (5.1.0)/charset_normalizer (2.0.12) doesn't match a supported version!
  warnings.warn("urllib3 ({}) or chardet ({})/charset_normalizer ({}) doesn't match a supported "

 -------------- celery@DESKTOP-DJPRLQD v5.2.7 (dawn-chorus)
--- ***** -----
-- ******* ---- Windows-10-10.0.19041-SP0 2024-04-17 15:37:39
- *** --- * ---
- ** ---------- [config]
- ** ---------- .> app:         my_scheduler:0x20a1ff8da00
- ** ---------- .> transport:   redis://127.0.0.1:6379/0
- ** ---------- .> results:     redis://127.0.0.1:6379/0
- *** --- * --- .> concurrency: 12 (eventlet)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
 -------------- [queues]
                .> celery           exchange=celery(direct) key=celery


[tasks]
  . my_scheduler.celery_task.hello

[2024-04-17 15:37:39,394: INFO/MainProcess] Connected to redis://127.0.0.1:6379/0
[2024-04-17 15:37:39,417: INFO/MainProcess] mingle: searching for neighbors
[2024-04-17 15:37:40,442: INFO/MainProcess] mingle: all alone
[2024-04-17 15:37:40,447: INFO/MainProcess] pidbox: Connected to redis://127.0.0.1:6379/0.
[2024-04-17 15:37:40,450: INFO/MainProcess] celery@DESKTOP-DJPRLQD ready.
[2024-04-17 15:37:40,591: INFO/MainProcess] Task my_scheduler.celery_task.hello[d225f94b-1c2f-4bd0-9bda-a080c996434b] received
[2024-04-17 15:37:40,591: WARNING/MainProcess] Hello, world!
[2024-04-17 15:37:40,638: INFO/MainProcess] Task my_scheduler.celery_task.hello[208783fe-e88e-4ef4-8e74-49082e7c8f25] received
[2024-04-17 15:37:40,639: WARNING/MainProcess] Hello, world!
[2024-04-17 15:37:40,689: INFO/MainProcess] Task my_scheduler.celery_task.hello[d225f94b-1c2f-4bd0-9bda-a080c996434b] succeeded in 0.09399999999732245s: None
[2024-04-17 15:37:40,690: INFO/MainProcess] Task my_scheduler.celery_task.hello[208783fe-e88e-4ef4-8e74-49082e7c8f25] succeeded in 0.046999999991385266s: None

celery@DESKTOP-DJPRLQD ready.就代表celery已经准备好处理task了,Task my_scheduler.celery_task.hello[208783fe-e88e-4ef4-8e74-49082e7c8f25] received代表开始消费task了,在redis里面查询就有打印了:

127.0.0.1:6379> get celery-task-meta-208783fe-e88e-4ef4-8e74-49082e7c8f25
"{\"status\": \"SUCCESS\", \"result\": null, \"traceback\": null, \"children\": [], \"date_done\": \"2024-04-17T07:37:40.687011\", \"task_id\": \"208783fe-e88e-4ef4-8e74-49082e7c8f25\"}"

如果将定时任务修改有返回值:

@app.task
def hello():
    print('Hello, world!')
    return "hello world"

则在redis里面的result字段将保存返回值:

127.0.0.1:6379> get celery-task-meta-5f37e97d-10a7-43d3-84b4-f00613bf602d
"{\"status\": \"SUCCESS\", \"result\": \"hello world\", \"traceback\": null, \"children\": [], \"date_done\": \"2024-04-17T07:42:27.053864\", \"task_id\": \"5f37e97d-10a7-43d3-84b4-f00613bf602d\"}"

注意:
app.autodiscover_task()执行报错

Received unregistered task of type 'my_scheduler.celery_task.hello'.
The message has been ignored and discarded.

Did you remember to import the module containing this task?
Or maybe you're using relative imports?

Please see
http://docs.celeryq.org/en/latest/internals/protocol.html
for more information.

可以看到是因为发送的任务未注册导致,需要指定注册的目录:app.autodiscover_tasks([‘my_scheduler.celery_task’])

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值