Celery 定义和调用异步任务Task
https://docs.celeryq.dev/en/stable/userguide/tasks.html
使用app.task装饰器定义
需要通过导入celery app,然后使用@app.task装饰器来定义任务
from celery_app.py import app
@app.task
def add(x, y):
return x + y
可以为task任务设置一些额外的参数,如:
from celery_app.py import app
# 单独设置task的序列化器,覆盖全局设置中的序列化器设置。
@app.task(serializer='json')
def add(x, y):
return x + y
注意事项:如果你的函数、方法有多个装饰器,则必须保证@app.task装饰器是最后一个执行的,如下所示:
from celery_app.py import app
@app.task(serializer='json')
@decorator2
@decorator1
def add(x, y):
return x + y
使用shared_task装饰器定义
当我们使用@app.task装饰器定义我们的异步任务时,那么这个任务依赖于根据项目名生成的Celery实例(celery配置文件中定义)。
然而我们在进行Django开发时为了保证每个app的可重用性,一般会在每个app文件夹下编写异步任务tasks.py,这些任务并不依赖于具体的Django项目名。使用@shared_task装饰器能让我们避免对某个项目名对应Celery实例的依赖,使app的可移植性更强。
@shared_task装饰器允许您在没有任何具体celery app实例的情况下创建任务:
from celery import shared_task
@shared_task
def add(x, y):
return x + y
常用的任务参数
设置任务Task名称
每个任务都必须有一个唯一的名称。
如果没有提供显式名称,任务装饰器将为您生成一个名称,该名称将基于 :定义任务的模块py文件名 + 任务函数的名。
最佳实践:使用模块名称作为任务名,这样,如果另一个模块中已经定义了具有该名称的任务,则名称不会发生冲突。
@app.task(name='tasks.add')
def add(x, y):
return x + y
您可以通过调用其 .name 属性来得知任务的名称:
add.name
'tasks.add'
任务参数bind的作用
绑定任务意味着任务的第一个参数将始终是任务实例 ( self ),就像 Python 方法中的self参数一样:
logger = get_task_logger(__name__)
@app.task(bind=True)
def add(self, x, y):
# self就是任务自身实例
# 打印任务实例的ID
logger.info(self.request.id)
任务失败重试(使用 app.Task.retry() )、访问有关当前任务请求的信息(如self.request.id)以及添加到自定义任务基类的任何其他功能都需要bind参数。
ignore_result
如果您不关心任务的结果,请务必设置 ignore_result 选项,因为存储结果会浪费时间和资源。
@app.task(ignore_result=True)
def mytask():
something()
甚至可以再celery配置文件中使用 task_ignore_result 设置项进行全局设置禁用结果存储。
在调用 apply_async 时,通过传递 ignore_result 布尔参数,可以在每次执行的基础上启用/禁用结果。
result = mytask.apply_async(1, 2, ignore_result=False)
获取请求任务信息
https://docs.celeryq.dev/en/stable/userguide/tasks.html#task-request
app.Task.request 包含与当前正在执行的任务相关的信息和状态。
任务重试retry
app.Task.retry() 可用于重新执行任务,例如在发生可恢复错误时。
当您调用 retry 时,它会使用相同的任务 ID 发送一条新消息,并且会注意确保该消息与原始任务传递到同一队列。
当重试任务时,这也会记录为任务状态,以便您可以使用结果实例跟踪任务的进度(请参阅状态)。
retry函数参数:https://docs.celeryq.dev/en/stable/reference/celery.app.task.html#celery.app.task.Task.retry
task有关重试的常用参数:
- max_retries,最大重试次数,默认为3
- retry_backoff:
True或者False、或者一个数值,用于设置异常自动重试的时间间隔。- 如果是True,则第一次是1秒,第二次是2秒,第三次是4秒的指数形式递增。
- 如果是数值,则延迟时间为: 第n次:(retry_backoff×2^(n-1)) 秒。
示例:
# retry_backoff:异常自动重试的时间间隔 第n次(retry_backoff×2^(n-1))s
# max_retries:异常自动重试次数的上限
@app.task(bind=True, max_retries=3)
def send_twitter_status(self, oauth, tweet):
try:
twitter = Twitter(oauth)
twitter.update_status(tweet)
except (Twitter.FailWhaleError, Twitter.LoginError) as exc:
# retry函数也可以使用max_retries,会覆盖task设置的max_retries。
# 抛出retry函数异常就是等同于执行重试操作
raise self.retry(exc=exc, max_retries=5)
再来一个以前学习的实例(发送短信验证码)
@shared_task(bind=True)
def send_sms(self, mobile, smscode):
send_result = -1
try:
send_result = CCP().send_template_sms(to=mobile, datas=[smscode, "%d" % (SMS_EXPIRE / 60)], temp_id=1)
except Exception as exc:
raise self.retry(exc=exc, max_retries=3)
finally:
# 如果返回结果为-1,则表示发送失败
if send_result == -1:
# 尝试再次发送
raise self.retry(exc=Exception('短信供应商发送失败,重试中..'), max_retries=3)
注意:任务发生异常重试前,默认是等待设置中的default_retry_delay的值(默认3分钟)
可以全局设置default_retry_delay,也可以单独给task设置。
甚至可以在调用retry的时候提供countdown参数来覆盖default_retry_delay
@app.task(bind=True, default_retry_delay=30 * 60) # retry in 30 minutes.
def add(self, x, y):
try:
something_raising()
except Exception as exc:
# overrides the default delay to retry after 1 minute
raise self.retry(exc=exc, countdown=60)
任务异常自动重试
https://docs.celeryq.dev/en/stable/userguide/tasks.html#automatic-retry-for-known-exceptions
该功能在4.0版本后提供。
有时候我们想在某些特定异常时自动进行任务重试。
在4.0版本后,可以在task装饰器中使用autoretry_for 参数告诉 Celery 进行自动重试任务:
from twitter.exceptions import FailWhaleError
# 当refresh_timeline任务发生FailWhaleError异常时会自动进行任务重试
@app.task(autoretry_for=(FailWhaleError,))
def refresh_timeline(user):
return twitter.refresh_timeline(user)
如果要为内部 retry() 调用指定自定义参数,请将 retry_kwargs 参数传递给 app.task() 装饰器:
# 使用retry_kwargs参数指定retry函数的参数,以此覆盖task中的max_retries设置的3次重试次数
@app.task(max_retries=3, autoretry_for=(FailWhaleError,),
retry_kwargs={'max_retries': 5})
def refresh_timeline(user):
return twitter.refresh_timeline(user)
使用autoretry_for参数相当于手动处理异常:
@app.task
def refresh_timeline(user):
try:
twitter.refresh_timeline(user)
except FailWhaleError as exc:
raise refresh_timeline.retry(exc=exc, max_retries=5)
调用异步任务
https://docs.celeryq.dev/en/stable/userguide/calling.html#guide-calling
Celery提供了2种以异步方式调用任务的方法,delay和apply_async方法
使用 delay() 方法调用任务:
# 导入任务函数
from proj.tasks import add
# 调用任务函数的delay()方法,delay方法可以传递任务的参数
add.delay(2, 2)
delay方法实际上是另一个名为 apply_async() 的方法的快捷方式:
apply_async()方法可以使用更多的参数:
格式:apply_async(args=(), kwargs={}, route_name=None, queue=指定队列, **options,)
# 导入任务函数
from proj.tasks import add
# 调用任务函数的delay()方法,apply_async传递参数时使用args来指定。
add.apply_async(args=[3, 5])
每个任务调用都会被赋予一个唯一标识符(UUID)——这就是任务 ID。
delay 和 apply_async 方法返回一个 AsyncResult 实例,该实例可用于跟踪任务执行状态。
但为此,您需要启用结果后端(result_backend),以便可以将状态存储在某处。
避免启动同步子任务
错误做法:
@app.task
def update_page_info(url):
page = fetch_page.delay(url).get()
info = parse_page.delay(page).get()
store_page_info.delay(url, info)
@app.task
def fetch_page(url):
return myhttplib.get(url)
@app.task
def parse_page(page):
return myparser.parse_document(page)
@app.task
def store_page_info(url, info):
return PageInfo.objects.create(url, info)
正确做法:
def update_page_info(url):
# fetch_page -> parse_page -> store_page
chain = fetch_page.s(url) | parse_page.s() | store_page_info.s(url)
chain()
@app.task()
def fetch_page(url):
return myhttplib.get(url)
@app.task()
def parse_page(page):
return myparser.parse_document(page)
@app.task(ignore_result=True)
def store_page_info(info, url):
PageInfo.objects.create(url=url, info=info)
自定义异常类celery中的注意事项:
https://docs.celeryq.dev/en/stable/userguide/tasks.html#creating-pickleable-exceptions
获取任务执行结果
https://docs.celeryq.dev/en/stable/reference/celery.result.html
Celery 定义和调用异步任务Task的更多相关文章
- 异步和多线程,委托异步调用,Thread,ThreadPool,Task,Parallel,CancellationTokenSource
1 进程-线程-多线程,同步和异步2 异步使用和回调3 异步参数4 异步等待5 异步返回值 5 多线程的特点:不卡主线程.速度快.无序性7 thread:线程等待,回调,前台线程/后台线程, 8 th ...
- Celery 源码解析三: Task 对象的实现
Task 的实现在 Celery 中你会发现有两处,一处位于 celery/app/task.py,这是第一个:第二个位于 celery/task/base.py 中,这是第二个.他们之间是有关系的, ...
- Celery(一个懂得 异步任务、定时任务、周期任务 的"芹菜")
一.什么是Celery? Celery 是基于Python实现的模块,用于执行异步.定时.周期任务的,其结构的组成是: - 用户任务 app - 管道 broker 用于存储任务(官方推荐 redis ...
- Winform同步调用异步函数死锁原因分析、为什么要用异步
1.前言 几年前,一个开发同学遇到同步调用异步函数出现死锁问题,导致UI界面假死.我解释了一堆,关于状态机.线程池.WindowsFormsSynchronizationContext.Post.co ...
- C# 委托的三种调用示例(同步调用 异步调用 异步回调)
首先,通过代码定义一个委托和下面三个示例将要调用的方法: 复制代码 代码如下: public delegate int AddHandler(int a,int b); public class ...
- C# 异步编程Task整理(二)异常捕捉
一.在任务并行库中,如果对任务运行Wait.WaitAny.WaitAll等方法,或者求Result属性,都能捕获到AggregateException异常. 可以将AggregateExceptio ...
- 20160711--C# 委托的三种调用示例(同步调用 异步调用 异步回调)【转载】
首先,通过代码定义一个委托和下面三个示例将要调用的方法: 代码如下: public delegate int AddHandler(int a,int b); public class 加法类 { p ...
- C# 同步调用 异步调用 异步回调 多线程的作用
同步调用 : 委托的Invoke方法用来进行同步调用.同步调用也可以叫阻塞调用,它将阻塞当前线程,然后执行调用,调用完毕后再继续向下进行. 异步调用 :同步调用会阻塞线程,如果是要调用一项繁重的 ...
- 基于任务的异步编程(Task,async,await)
这节讲一下比较高级的异步编程用法Task,以及两个异步关键字async和await. Task是在C#5.0推出的语法,它是基于任务的异步编程语法,是对Thread的升级,也提供了很多API,先看一下 ...
- javascript 内部函数的定义及调用
内部函数:定义在另一个函数中的函数 例如: <script> function outer(){ function inner(){ } } </script> inner() ...
随机推荐
- 使用flask开发web应用
Flask环境搭建 要开发flash应用,我们需要做一些准备工作 我写了个初始化的脚本 Pip_init.sh来安装初始工作 可以到我的git上去下载该脚本进行初始化安装 要启动flask应用,我们需 ...
- KRPano插件解密大师更新支持最新版KRPano的XML/JS解密
KRPano插件解密大师是一款专业的全景解密工具,它可以帮助你轻松解密KRPano的XML/JS插件,还能分析下载静态和动态网站的资源.你无需任何编程知识,只需一键点击,就能快速完成解密,学习全景开发 ...
- Oracle12C登录PDB容器
Oracle12C登录PDB用户,此为12C的新特性 ①首先管理员身份登录 sqlplus / as sysdba;--管理员身份登录 show con_name;--查看此时连接容器 显示:CDB$ ...
- Git——Git 常用命令
文章目录 仓库 配置 增加/删除文件 代码提交 分支 标签 查看信息 远程同步 撤销 其他 仓库 # 在当前目录新建一个Git代码库 $ git init # 新建一个目录,将其初始化为Git代码库 ...
- Vue源码学习(九):响应式前置:实现对象的依赖收集(dep和watcher)
好家伙,这是目前为止最绕的一章,也是十分抽象的一章 由于实在太过抽象,我只能用一个不那么抽象的实例去说服我自己 完整代码已开源https://github.com/Fattiger4399/ana ...
- IDEA工具第一篇:细节使用-习惯设置
安装好Idea后,直接上手clone代码进入编码时代,有没有那么一刻你会觉用起来没有那么顺手流畅呢? 下面是关于 [Windows] 下安装idea的一些习惯设置[ Mac大致一样 ] 一.修改系统文 ...
- 掌握Go类型内嵌:设计模式与架构的新视角
本文深入探讨了Go语言中的类型内嵌特性,从基础概念到实际应用,以及相关的最佳实践.文章不仅讲解了如何在Go中实现和使用类型内嵌,还通过具体的代码示例展示了其应用场景和潜在陷阱.最后,文章总结了类型内嵌 ...
- 征集 meme
当你每次兴致勃勃地和好友分享自己喜欢的歌但 Ta 不屑一顾 / 不喜欢时:
- 02-RAID技术 学习心得
RAID 术语 扇区:是磁盘中最小的存储单元,向磁盘读写数据时是以扇区为最小单元进行存储 block:block,是由N个扇区组成一个块: 在磁盘相同偏移处横向逻辑分割,就形成了stripee: 一个 ...
- vue打包部署遇到的问题
网站上线中遇到的问题(跨域,404,空白页解决方案) 因为本人是后端开发工程师,对前端开发不了解,踩了很多坑,所以将踩过的坑分享出来,以供参考 网站地址:这里 这段时间将项目部署到服务器中引发了几个问 ...