存在的现象

在异步调用任务中经常需要调用第三方的api请求,如果一次执行失败,则应该进行重试执行。否则,如果在执行一些连续性的chain链条任务,前面执行失败,那么后续的也就不用执行了。

下面来看看一个发送邮件失败,然后重试执行的示例。

Celery任务的文档结构

Celery 4.3.0 任务失败重试机制_html

该示例是延续上一篇​​Django 2.1.7 Celery 4.3.0 异步发送邮件示例​​的,如果不清楚如何发送邮件,可以先查阅一下我上一篇的内容。

错误重试示例

故意将邮件服务的地址配置错误

为了做到错误的演示,我首先将发送邮件的smtp地址写错,如下:

Celery 4.3.0 任务失败重试机制_html_02

那么稍后执行发送邮件的时候,就一定会报找不到smtp的错误。

编写错误重试的task任务

Celery 4.3.0 任务失败重试机制_html_03

# 定义任务函数
@celery_app.task(bind=True)
def send_register_active_email(self,to_email, username, token):
'''发送激活邮件'''
# 组织邮件信息
subject = '欢迎信息'
message = ''
sender = settings.EMAIL_FROM
receiver = [to_email]
html_message = '<h1>%s, 欢迎您成为xxx注册会员</h1>请点击下面链接激活您的账户<br/><a href="http://127.0.0.1:8000/user/active/%s">http://127.0.0.1:8000/user/active/%s</a>' % (username, token, token)

print("=========== 执行发送邮件 ===============")

try:
send_mail(subject, message, sender, receiver, html_message=html_message)
except Exception as e:
"""
邮件发送失败,使用retry进行重试

retry的参数可以有:
exc:指定抛出的异常
throw:重试时是否通知worker是重试任务
eta:指定重试的时间/日期
countdown:在多久之后重试(每多少秒重试一次)
max_retries:最大重试次数
"""
raise self.retry(exc=e, countdown=3, max_retries=5)

该示例任务将会进行调用发送邮件,当发生错误后,间隔3秒则重试执行一次,总共5次。
可以通过​​​print​​的打印信息来确认重试的次数。

启动celery任务

windows启动命令:

celery -A celery_tasks worker -l info -P eventlet

linux启动命令:

celery -A celery_tasks worker -l info

执行celery任务

启动完毕celery之后,那么下面进行交互模式进行测试,执行如下:

In [1]: from celery_tasks.tasks import send_register_active_email

In [2]: to_email = 'lijw@******.cn'

In [3]: token = '123456'

In [4]: username = 'lijw'

In [5]: send_register_active_email.delay(to_email,username,token)
Out[5]: <AsyncResult: 02deebc0-5d64-43f9-9ad5-5ccfe260ec70>

执行完毕任务后,查看celery的执行日志,如下:

[2019-10-21 14:01:09,508: INFO/MainProcess] celery@junwei1 ready.
[2019-10-21 14:01:09,509: INFO/MainProcess] pidbox: Connected to redis://127.0.0.1:6379/8.
[2019-10-21 14:01:14,353: INFO/MainProcess] Received task: celery_tasks.tasks.send_register_active_email[7b921776-f6a6-4da0-9c71-b04aac0d139a]

# 任务第一次执行,然后执行失败
[2019-10-21 14:01:14,354: WARNING/MainProcess] =========== 执行发送邮件 ===============
[2019-10-21 14:01:15,311: INFO/MainProcess] Received task: celery_tasks.tasks.send_register_active_email[7b921776-f6a6-4da0-9c71-b04aac0d139a] ETA:[2019-10-21 06:01:18.21
8857+00:00]
[2019-10-21 14:01:15,345: INFO/MainProcess] Task celery_tasks.tasks.send_register_active_email[7b921776-f6a6-4da0-9c71-b04aac0d139a] retry: Retry in 3s: gaierror(11001, 'N
o address found')

# 当执行错误之后,下面则会重试执行5次任务,直到成功,或者失败
[2019-10-21 14:01:18,224: WARNING/MainProcess] =========== 执行发送邮件 ===============
[2019-10-21 14:01:18,253: INFO/MainProcess] Received task: celery_tasks.tasks.send_register_active_email[7b921776-f6a6-4da0-9c71-b04aac0d139a] ETA:[2019-10-21 06:01:21.22
5853+00:00]
[2019-10-21 14:01:18,265: INFO/MainProcess] Task celery_tasks.tasks.send_register_active_email[7b921776-f6a6-4da0-9c71-b04aac0d139a] retry: Retry in 3s: gaierror(11001, 'N
o address found')
[2019-10-21 14:01:21,227: WARNING/MainProcess] =========== 执行发送邮件 ===============
[2019-10-21 14:01:21,255: INFO/MainProcess] Received task: celery_tasks.tasks.send_register_active_email[7b921776-f6a6-4da0-9c71-b04aac0d139a] ETA:[2019-10-21 06:01:24.22
8790+00:00]
[2019-10-21 14:01:21,264: INFO/MainProcess] Task celery_tasks.tasks.send_register_active_email[7b921776-f6a6-4da0-9c71-b04aac0d139a] retry: Retry in 3s: gaierror(11001, 'N
o address found')
[2019-10-21 14:01:24,243: WARNING/MainProcess] =========== 执行发送邮件 ===============
[2019-10-21 14:01:24,280: INFO/MainProcess] Received task: celery_tasks.tasks.send_register_active_email[7b921776-f6a6-4da0-9c71-b04aac0d139a] ETA:[2019-10-21 06:01:27.24
4729+00:00]
[2019-10-21 14:01:24,291: INFO/MainProcess] Task celery_tasks.tasks.send_register_active_email[7b921776-f6a6-4da0-9c71-b04aac0d139a] retry: Retry in 3s: gaierror(11001, 'N
o address found')
[2019-10-21 14:01:27,245: WARNING/MainProcess] =========== 执行发送邮件 ===============
[2019-10-21 14:01:27,271: INFO/MainProcess] Received task: celery_tasks.tasks.send_register_active_email[7b921776-f6a6-4da0-9c71-b04aac0d139a] ETA:[2019-10-21 06:01:30.24
6720+00:00]
[2019-10-21 14:01:27,281: INFO/MainProcess] Task celery_tasks.tasks.send_register_active_email[7b921776-f6a6-4da0-9c71-b04aac0d139a] retry: Retry in 3s: gaierror(11001, 'N
o address found')
[2019-10-21 14:01:30,261: WARNING/MainProcess] =========== 执行发送邮件 ===============
[2019-10-21 14:01:30,279: ERROR/MainProcess] Task celery_tasks.tasks.send_register_active_email[7b921776-f6a6-4da0-9c71-b04aac0d139a] raised unexpected: gaierror(11001, 'N
o address found')
Traceback (most recent call last):
....
raise socket.gaierror(socket.EAI_NONAME, 'No address found')
socket.gaierror: [Errno 11001] No address found

可以看到,上面的日志中的打印信息。
第一次执行任务,则发送了一次报错。
随后一直重试执行了5次都报错,说明重试的5次是从第一次执行失败后计算的。

Celery 4.3.0 任务失败重试机制_发送邮件_04