前一篇内容我介绍了执行耗时任务的神器celery,但是感觉还是缺点料,本篇章再来继续深入讲诉以及介绍一下celery执行任务的错误重试机制。
我在最近开发平台的时候需要使用celery多次频繁并发使用paramiko库进行ssh远程命令执行调用。
在执行的过程中,主控服务器在百度云,远程调用阿里云的服务器是很OK的,暂时没有发现什么错误,一路任务顺畅执行,一点错误都没。
但是当我远程调用腾讯云服务器的时候,总会偶尔出现一些报错的情况,这就让我很纠结郁闷了。
因为这是最底层的调用方式,而我解决这种报错情况的方式是改用ansible进行执行,并且将多个执行shell命令写成脚本进行一次性调用。
将多次并发的远程调用尽量合并一次性执行,将shell执行的错误返回进行处理。
尽管做了那么多的改动以及优化,任务依然会出现ssh访问被偶尔阻止的情况,这时候就只能上这个错误重试了。
本次说明,我采用的是发送邮件错误的情况作为示例,如下:
在异步调用任务中经常需要调用第三方的api请求,如果一次执行失败,则应该进行重试执行。否则,如果在执行一些连续性的chain链条任务,前面执行失败,那么后续的也就不用执行了。
下面来看看一个发送邮件失败,然后重试执行的示例。
为了做到错误的演示,我首先将发送邮件的smtp地址写错,如下:
那么稍后执行发送邮件的时候,就一定会报找不到smtp的错误。
# 定义任务函数
@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
的打印信息来确认重试的次数。
windows启动命令:
celery -A celery_tasks worker -l info -P eventlet
linux启动命令:
celery -A celery_tasks worker -l info
启动完毕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错误重试的机制大概就是如此。后续,我会继续尽量将工作中碰到的问题,以及解决的方法抛出来进行分享,谢谢。