当前位置:

首页 > 编程开发 > Python Celery如何动态添加定时任务?

Python Celery如何动态添加定时任务?

一、背景实际工作中会有一些耗时的异步任务需要使用定时调度,比如发送邮件,拉取数据,执行定时脚本通过celery实现调度主要思想是通过引入中间人redis,启动worker进行任务执行,celery-beat进行定时任务数据存储二、Celery动态添加定时任务的官方文档celery文档:https://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html#beat-custom-schedulerscelery自定义调度类说明:自定义调

本文目录

      一、背景

      实际工作中会有一些耗时的异步任务需要使用定时调度,比如发送邮件,拉取数据,执行定时脚本

      通过celery 实现调度主要思想是 通过引入中间人redis,启动 worker 进行任务执行 ,celery-beat进行定时任务数据存储

      二、Celery动态添加定时任务的官方文档

      celery文档:https://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html#beat-custom-schedulers

      celery 自定义调度类说明: 

      自定义调度器类可以在命令行中指定(--scheduler参数)

      django-celery-beat文档 : https://pypi.org/project/django-celery-beat/

      关于django-celery-beat 插件的说明: 

      此扩展使您能够将定期任务计划存储在数据库中,可以从 Django 管理界面管理周期性任务,您可以在其中创建、编辑和删除周期性任务以及它们应该运行的频率

      三、celery简单实用

      3.1 基础环境配置

      1. 安装最新版本的Django

      pip3 install django #当前我安装的版本是 3.0.6

      2. 创建项目

      django-admin startproject typeidea
      django-admin startapp blog

      3.安装 celery

      pip3 install django-celery
      pip3 install -U Celery 
      pip3 install "celery[librabbitmq,redis,auth,msgpack]" 
      pip3 install django-celery-beat # 用于动态添加定时任务
      pip3 install django-celery-results
      pip3 install redis

      3.2 测试使用Celery应用

      1. 创建blog目录、新建task.py

      首先在Django项目中创建一个blog文件夹,并且在blog文件夹下创建tasks.py模块, 如下:

      Python Celery如何动态添加定时任务?

       tasks.py代码如下: 

      #!/usr/bin/env python
      # -*- coding: UTF-8 -*-
       
      """
      #File: tasks.py
      #Time: 2022/3/30 2:26 下午
      #Author: julius
      """
      from celery import Celery
       
      # 使用redis做为broker
      app = Celery('blog.tasks2',broker='redis://127.0.0.1:6379/0')
       
      # 创建任务函数
      @app.task
      def my_task():
          print('任务正在执行...')

      Celery第一个参数是给其设定一个名字, 第二参数我们设定一个中间人broker, 在这里我们使用Redis作为中间人。my_task函数是我们编写的一个任务函数, 通过加上装饰器app.task, 将其注册到broker的队列中。

      2. 启动redis、创建worker

      现在我们在创建一个worker, 等待处理队列中的任务。

      进入项目的根目录,执行命令: celery -A celery_tasks.tasks worker -l info

      Python Celery如何动态添加定时任务?

       3. 调用任务

      下面来测试一下功能,创建一个任务,加入任务队列中,提供worker执行。

      进入python终端, 执行如下代码:

      $ python manage.py shell
      >>> from blog.tasks import my_task
      >>> my_task.delay()
      

      调用一个任务函数,将会返回一个AsyncResult对象,这个对象可以用来检查任务的状态或者获得任务的返回值。

      4. 查看结果

      在worker的终端查看任务执行情况,可以看到已经收到83484dfe-f729-417b-8e51-6c7ae32a1377 任务,并打印了任务执行信息

      Python Celery如何动态添加定时任务?

      5. 存储并查看任务执行状态

      把任务执行结果赋值给ret,然后调用result() 会产生 DisabledBackend 报错,可见没有配置后端存储的时候并不能保存任务执行的状态信息,下一节我们会讲到如何配置backend保存任务执行结果

      $ python manage.py shell
      >>> from blog.tasks import my_task
      >>> ret=my_task.delay()
      >>> ret.result()

      Python Celery如何动态添加定时任务?

      四、配置backend存储任务执行结果 

      如果我们想跟踪任务的状态,Celery需要将结果保存到某个地方。有几种保存的方案可选:SQLAlchemy、Django ORM、Memcached、 Redis、RPC (RabbitMQ/AMQP)。

      1. 添加backend参数

      在本例中我们使用Redis作为存储结果的方案,通过Celery的backend参数来设定任务结果存储地址。我们将tasks模块修改如下:

      from celery import Celery
       
      # 使用redis作为broker以及backend
      app = Celery('celery_tasks.tasks',
                   broker='redis://127.0.0.1:6379/8',
                   backend='redis://127.0.0.1:6379/9')
       
      # 创建任务函数
      @app.task
      def my_task(a, b):
          print("任务函数正在执行....")
          return a + b

      给Celery增加了backend参数,指定redis作为结果存储,并将任务函数修改为两个参数,并且有返回值。

      2. 调用任务/查看任务执行结果

      下面再来执行调用一下这个任务看看。

      $ python manage.py shell
      >>> from blog.tasks import my_task
      >>> res=my_task.delay(10,40)
      >>> res.result
      50
      >>> res.failed()
      False

      再来看看worker的执行情况,如下:

      Python Celery如何动态添加定时任务?

      可以看到celery任务已经执行成功了。

      但是这只是一个开始,下一步要看看如何添加定时的任务。

      四、优化Celery目录结构

      上面直接将Celery的应用创建、配置、tasks任务全部写在了一个文件,这样在后面项目越来越大,也是不方便的。下面来拆分一下,并且添加一些常用的参数。

      基本结构如下

      Python Celery如何动态添加定时任务?

      $ vim typeidea/celery.py (Celery应用文件)

      #!/usr/bin/env python
      # -*- coding: UTF-8 -*-
       
      """
      #File: celery.py
      #Time: 2022/3/30 12:25 下午
      #Author: julius
      """
      import os
      from celery import Celery
      from blog import celeryconfig
      project_name='typeidea'
      # set the default django setting module for the 'celery' program
      os.environ.setdefault('DJANGO_SETTINGS_MODULE','typeidea.settings')
      app = Celery(project_name)
       
      app.config_from_object('django.conf:settings')
       
      app.autodiscover_tasks()

      vim blog/celeryconfig.py (配置Celery的参数文件)

      #!/usr/bin/env python
      # -*- coding: UTF-8 -*-
       
      """
      #File: celeryconfig.py
      #Time: 2022/3/30 2:54 下午
      #Author: julius
      """
      
      # 设置结果存储
      from typeidea import settings
      import os
       
      os.environ.setdefault("DJANGO_SETTINGS_MODULE", "typeidea.settings")
      CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/0'
      # 设置代理人broker
      BROKER_URL = 'redis://127.0.0.1:6379/1'
      # celery 的启动工作数量设置
      CELERY_WORKER_CONCURRENCY = 20
      # 任务预取功能,就是每个工作的进程/线程在获取任务的时候,会尽量多拿 n 个,以保证获取的通讯成本可以压缩。
      CELERYD_PREFETCH_MULTIPLIER = 20
      # 非常重要,有些情况下可以防止死锁
      CELERYD_FORCE_EXECV = True
      # celery 的 worker 执行多少个任务后进行重启操作
      CELERY_WORKER_MAX_TASKS_PER_CHILD = 100
      # 禁用所有速度限制,如果网络资源有限,不建议开足马力。
      CELERY_DISABLE_RATE_LIMITS = True
       
      CELERY_ENABLE_UTC = False
      CELERY_TIMEZONE = settings.TIME_ZONE
      DJANGO_CELERY_BEAT_TZ_AWARE = False
      CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler'

      vim blog/tasks.py (tasks 任务文件)

      import time
      from blog.celery import app
       
      # 创建任务函数
      @app.task
      def my_task(a, b, c):
          print('任务正在执行...')
          print('任务1函数休眠10s')
          time.sleep(10)
          return a + b + c

      五、开始使用django-celery-beat调度器

      使用 django-celery-beat 动态添加定时任务  celery 4.x 版本在 django 框架中是使用 django-celery-beat 进行动态添加定时任务的。前面虽然已经安装了这个库,但是还要再说明一下。

      1. 安装 django-celery-beat

      pip3 install django-celery-beat

      2.在项目的 settings 文件配置 django-celery-beat 

      INSTALLED_APPS = [
          'blog',
          'django_celery_beat',
          ...
      ]
       
      # Django设置时区
      LANGUAGE_CODE = 'zh-hans'  # 使用中国语言
      TIME_ZONE = 'Asia/Shanghai'  # 设置Django使用中国上海时间
      # 如果USE_TZ设置为True时,Django会使用系统默认设置的时区,此时的TIME_ZONE不管有没有设置都不起作用
      # 如果USE_TZ 设置为False,TIME_ZONE = 'Asia/Shanghai', 则使用上海的UTC时间。
      USE_TZ = False

      3. 创建 django-celery-beat 相关表

      执行Django数据库迁移: python manage.py migrate

      Python Celery如何动态添加定时任务?

      4. 配置Celery使用 django-celery-beat

      配置 celery.py

      import os
       
      from celery import Celery
       
      from blog import celeryconfig
       
      # 为celery 设置环境变量
      os.environ.setdefault("DJANGO_SETTINGS_MODULE","typeidea.settings")
      # 创建celery app
      app = Celery('blog')
      # 从单独的配置模块中加载配置
      app.config_from_object(celeryconfig)
       
      # 设置app自动加载任务
      app.autodiscover_tasks([
          'blog',
      ])

      配置 celeryconfig.py

      # 设置结果存储
      from typeidea import settings
      import os
       
      os.environ.setdefault("DJANGO_SETTINGS_MODULE", "typeidea.settings")
      CELERY_RESULT_BACKEND = 'redis://127.0.0.1:6379/0'
      # 设置代理人broker
      BROKER_URL = 'redis://127.0.0.1:6379/1'
      # celery 的启动工作数量设置
      CELERY_WORKER_CONCURRENCY = 20
      # 任务预取功能,就是每个工作的进程/线程在获取任务的时候,会尽量多拿 n 个,以保证获取的通讯成本可以压缩。
      CELERYD_PREFETCH_MULTIPLIER = 20
      # 非常重要,有些情况下可以防止死锁
      CELERYD_FORCE_EXECV = True
      # celery 的 worker 执行多少个任务后进行重启操作
      CELERY_WORKER_MAX_TASKS_PER_CHILD = 100
      # 禁用所有速度限制,如果网络资源有限,不建议开足马力。
      CELERY_DISABLE_RATE_LIMITS = True
       
      CELERY_ENABLE_UTC = False
      CELERY_TIMEZONE = settings.TIME_ZONE
      DJANGO_CELERY_BEAT_TZ_AWARE = False
      CELERY_BEAT_SCHEDULER = 'django_celery_beat.schedulers:DatabaseScheduler'

      编写任务 tasks.py

      import time
      from celery import Celery
      from blog.celery import app
       
      # 使用redis做为broker
      # app = Celery('blog.tasks2',broker='redis://127.0.0.1:6379/0',backend='redis://127.0.0.1:6379/1')
       
      # 创建任务函数
      @app.task
      def my_task(a, b, c):
          print('任务正在执行...')
          print('任务1函数休眠10s')
          time.sleep(10)
          return a + b + c
       
      @app.task
      def my_task2():
          print("任务2函数正在执行....")
          print('任务2函数休眠10s')
          time.sleep(10)

      5. 启动定时任务work

      启动定时任务首先需要有一个work执行异步任务,然后再启动一个定时器触发任务。

      启动任务 work

      $ celery -A blog worker -l info

      Python Celery如何动态添加定时任务?

      启动定时器触发 beat

      celery -A blog beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler

      Python Celery如何动态添加定时任务?

      六、具体操作演练

      6.1 创建基于间隔时间的周期性任务

      1. 初始化周期间隔对象interval 对象

      >>> from django_celery_beat.models import PeriodicTask, IntervalSchedule
      >>> schedule, created = IntervalSchedule.objects.get_or_create( 
      ...       every=10, 
      ...       period=IntervalSchedule.SECONDS, 
      ...  )
      >>> IntervalSchedule.objects.all()
      ]>

      2.创建一个无参数的周期性间隔任务

      >>>PeriodicTask.objects.create(interval=schedule,name='my_task2',task='blog.tasks.my_task2',)
      

      beat 调度服务日志显示如下:

      Python Celery如何动态添加定时任务?

       worker 服务日志显示如下:

      Python Celery如何动态添加定时任务?

      3.创建一个带参数的周期性间隔任务

      >>> PeriodicTask.objects.create(interval=schedule,name='my_task',task='blog.tasks.my_task',args=json.dumps([10,20,30]))
      

      beat 调度服务日志结果:

      Python Celery如何动态添加定时任务?

       worker 服务日志结果:

      Python Celery如何动态添加定时任务?

      4.如何高并发执行任务

      需要并行执行任务的时候,就需要设置多个worker来执行任务。 

      6.2 创建一个不带参数的周期性间隔任务

      1.初始化 crontab 的调度对象

      >>> import pytz
      >>> schedule, _ = CrontabSchedule.objects.get_or_create(
      ... minute='*',
      ... hour='*',
      ... day_of_week='*',
      ... day_of_month='*',
      ... timezone=pytz.timezone('Asia/Shanghai')
      ... )

      2. 创建不带参数的定时任务

      PeriodicTask.objects.create(crontab=schedule,name='my_task2_crontab',task='blog.tasks.my_task2',)

      beat 调度服务执行结果 

      Python Celery如何动态添加定时任务?

       worker 执行服务结果

      Python Celery如何动态添加定时任务?

      6.3 周期性任务的查询、删除操作

      1. 周期性任务的查询

      >>> PeriodicTask.objects.all()
      , ]>
      >>> PeriodicTask.objects.get(name='my_task2_crontab')
      
      >>> for task in PeriodicTask.objects.all():
      ...     print(task.id)
      ... 
      1
      13
      >>> PeriodicTask.objects.get(id=13)
      
      >>> PeriodicTask.objects.get(name='my_task2_crontab')
      

       控制台实际操作记录

      Python Celery如何动态添加定时任务?

      2.周期性任务的暂停/启动

      2.1 设置my_taks2_crontab 暂停任务

      >>> my_task2_crontab = PeriodicTask.objects.get(id=13)
      >>> my_task2_crontab.enabled
      True
      >>> my_task2_crontab.enabled=False
      >>> my_task2_crontab.save()

      查看worker输出:

      Python Celery如何动态添加定时任务?

       可以看到worker从19:31以后已经没有输出了,说明已经成功吧my_task2_crontab 任务暂停

      2.2 设置my_task2_crontab 开启任务

      把任务的 enabled 为 True 即可:

      >>> my_task2_crontab.enabled
      False
      >>> my_task2_crontab.enabled=True
      >>> my_task2_crontab.save()

      查看worker输出:

      Python Celery如何动态添加定时任务?

       可以看到worker从19:36开始有输出,说明已把my_task2_crontab 任务重新启动

      3. 周期性任务的删除

      获取到指定的任务后调用delete(),再次查询指定任务会发现已经不存在了

      PeriodicTask.objects.get(name='my_task2_crontab').delete()
      >>> PeriodicTask.objects.get(name='my_task2_crontab')
      Traceback (most recent call last):
        File "", line 1, in 
        File "/Users/julius/PycharmProjects/typeidea/.venv/lib/python3.9/site-packages/django/db/models/manager.py", line 85, in manager_method
          return getattr(self.get_queryset(), name)(*args, **kwargs)
        File "/Users/julius/PycharmProjects/typeidea/.venv/lib/python3.9/site-packages/django/db/models/query.py", line 435, in get
          raise self.model.DoesNotExist(
      django_celery_beat.models.PeriodicTask.DoesNotExist: PeriodicTask matching query does not exist.
      本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
      作者最新文章
      编程开发 Python
      相关文章 更多
      python删除一个列表里的重复元素的方法与代码示例
      python删除一个列表里的重复元素的方法与代码示例

      学习如何使用Python高效删除列表中的重复元素。本文提供5种常见方法的代码示例,涵盖保持顺序与不保持顺序的场景,适合初学者和进阶开发者参考。

      Python写接口的步骤及完整代码示例
      Python写接口的步骤及完整代码示例

      详细讲解使用Python编写Web接口的核心步骤与完整代码示例,涵盖环境准备、路由定义、数据校验、服务启动及调试测试方法。

      codex怎么读取word文档及docx文件操作教程
      codex怎么读取word文档及docx文件操作教程

      介绍如何利用编程工具读取和解析Word文档(docx格式),涵盖基础文本提取代码示例、结构化数据处理逻辑,以及处理复杂排版时的技术局限与替代方案。

      怎么在Python中调用C语言代码提升性能
      怎么在Python中调用C语言代码提升性能

      详细讲解在Python中调用C语言代码提升性能的完整实践指南,包含原理分析、编译步骤、ctypes与CFFI具体实现、性能对比及常见陷阱。

      Python与C语言的性能差异及底层原理
      Python与C语言的性能差异及底层原理

      深入解析Python与C语言在执行效率上的数量级差异,从编译机制、变量内存布局、动态类型推断到GIL锁,系统阐明底层核心原理。

      Python和C语言哪个更适合编程入门
      Python和C语言哪个更适合编程入门

      客观对比Python与C语言在心智负担、底层机制与学习反馈上的核心差异,提供清晰有据的选择标准与切实的入门学习路径。

      selenium上传文件教程本地文件路径设置方法
      selenium上传文件教程本地文件路径设置方法

      深入解析Selenium处理文件上传的技术细节,涵盖标准HTML控件的路径直接注入法与非标准控件的系统级模拟方案,提供Windows与Linux环境下的路径设置最佳实践及常见异常排查。

      大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景
      大数据开发语言选型:Java对比Scala与Python的优缺点及适用场景

      针对大数据工程场景,系统对比Java、Scala与Python在执行性能、生态结合、开发效率和维护成本上的核心差异,给出清晰的架构选型依据与落地方案。

      langgraph python guide中文入门教程详解
      langgraph python guide中文入门教程详解

      本篇LangGraph Python中文入门教程详解,系统梳理StateGraph状态机定义、节点编写、边与条件路由、检查点持久化(MemorySaver)等核心机制,提供从环境安装到完整循环智能体构建的代码示例与实操指导。

      Windows 安装 Python:从官方入口到虚拟环境的可复现实践
      Windows 安装 Python:从官方入口到虚拟环境的可复现实践

      面向后端开发者,基于 Python 官方文档说明如何在 Windows 上安装 Python、创建 venv 虚拟环境及使用 pip 管理依赖。包含可复制命令、验证方法及工具选择边界,避免常见配置误区。

      查看更多
      精品专题 更多
      装机必备
      装机必备

      正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

      Windows
      Windows

      正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

      PDF教程
      PDF教程

      正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

      Mac软件 更多
      讯飞智作 网页版
      讯飞智作 网页版
      Windows/ macOS/ Linux

      讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

      火山引擎 网页版
      火山引擎 网页版
      Windows/ macOS/ Linux

      火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

      Aperty macOS版
      Aperty macOS版
      macOS

      Aperty 是 Skylum 推出的 AI 人像修图软件,支持自然肤质修饰、瑕疵处理、面部与身体调整、预设及批量同步。

      WINDOWS 更多
      讯飞智作 网页版
      讯飞智作 网页版
      Windows/ macOS/ Linux

      讯飞智作是一款基于语音合成技术、虚拟人驱动技术与数字人形象声音构建能力的 AI 数字人音视频创作平台。

      火山引擎 网页版
      火山引擎 网页版
      Windows/ macOS/ Linux

      火山引擎是字节跳动旗下企业级云与AI服务平台。聚焦大模型核心能力,依托字节自研豆包多模态大模型,凭借火山方舟一站式平台,提供模型精调、推理部署、智能应用搭建等全链路服务,结合高性能AI算力,助力各行业快速落地大模型数字化与智能化应用。

      PixTV 网页版
      PixTV 网页版
      Windows

      PixTV 是一款在浏览器中使用的 AI 视觉内容创作平台,提供图片、视频、音频、文字生成、AI 分镜、局部重绘、提示词反推和无限画布等工具,适合短剧、漫剧、广告及社交媒体内容制作。