之前讲到利用celery异步处理一些耗时或者耗资源的任务,但是近来分析数据的时候发现一个奇怪的现象,即是某些数据重复了,自然想到是异步任务重复执行了。

查阅之后发现,到如果一个任务太耗时,任务完成时间超过了broker的时间(Redis默认为一小时)则任务会被再次分配到worker.

Visibility Timeout

The visibility timeout defines the number of seconds to wait for the worker to acknowledge the task before the message is redelivered to another worker. Be sure to see Caveats below.

This option is set via the broker_transport_options setting:

app.conf.broker_transport_options = {'visibility_timeout': 3600}  # 1 hour.

The default visibility timeout for Redis is 1 hour.

问题在于我的应用中的异步任务耗时绝不可能超过Redis默认的一小时,那么问题出在这个“Acknowledge”了,一开始我的理解是这个acknowledge是worker收到了broker发送的任务。但是通过查看workererr.log 发现:

[2019-03-01 14:20:30,695: INFO/MainProcess] Received task: task_async[4e0378e2-ff5d-4394-a842-ece2d1c8118a] ETA:[2019-03-01 15:44:03.692831+08:00]

[2019-03-01 15:23:58,477: INFO/MainProcess] Received task: task_async[4e0378e2-ff5d-4394-a842-ece2d1c8118a] ETA:[2019-03-01 15:44:03.692831+08:00]

[2019-03-01 15:44:04,620: INFO/ForkPoolWorker-2] Task task_async[4e0378e2-ff5d-4394-a842-ece2d1c8118a] succeeded in 0.003580662072636187s: None

[2019-03-01 15:44:04,621: INFO/ForkPoolWorker-1] Task task_async[4e0378e2-ff5d-4394-a842-ece2d1c8118a] succeeded in 0.004984764964319766s: None

1. 重复执行的任务被发送了多次 (时间间隔为1小时)

2. worker多次接收到同样的任务(同ID),并且几乎一样的ETA(预计执行时间)

3. 在ETA到达之后,这个任务会被多个子线程认领并执行,每次执行时间并不长

所以为什么14:20:30任务接收到之后15:23:58任务再次发送呢,问题在约“Acknowledge”(认领)并不是以“Received”为结束标志的,看celery对于acknowledge的解释:

acknowledged

Workers acknowledge messages to signify that a message has been handled. Failing to acknowledge a message will cause the message to be redelivered. Exactly when a transaction is considered a failure varies by transport. In AMQP the transaction fails when the connection/channel is closed (or lost), but in Redis/SQS the transaction times out after a configurable amount of time (the visibility_timeout).

所以说是以“Handled”来进行判定而非任务已被接收,所以会出现当我的定时任务在一小时后才执行的情况下,第一次发送的任务虽然接受了但是并未执行(Acknowledge),所以一小时后任务再次被发送。

解决这个问题的时候回看celery开篇教程中的一段:

Ideally task functions should be idempotent: meaning the function won’t cause unintended effects even if called multiple times with the same arguments. Since the worker cannot detect if your tasks are idempotent, the default behavior is to acknowledge the message in advance, just before it’s executed, so that a task invocation that already started is never executed again.

最佳实践中的任务应该是幂等的!

总结起来:

1. Task received的时候并不是acknowledge的时候,而task执行才是acknowledge (任务才会从broker队列中移除).

2. 我的任务都是定时任务(超过一小时),所以我设置visibility_time 超出我的定时,则重复执行不会再发生.

3. 如果任务很长或者跨度很长,如果对于只执行一次有严格要求,可以参考celery_once.

4. 还是要仔细阅读官方文档!!

Ref:

Scheduled tasks are being duplicated

https://github.com/cameronmaske/celery-once

http://docs.celeryproject.org/en/latest/getting-started/brokers/redis.html#visibility-timeout

https://github.com/celery/django-celery/issues/176

Celery异步任务重复执行(Redis as broker)的更多相关文章

  1. Celery异步处理

    1.Celery概述 1.1问题抛出 我们在做网站后端程序开发时,会碰到这样的需求:用户需要在我们的网站填写注册信息,我们发给用户一封注册激活邮件到用户邮箱,如果由于各种原因,这封邮件发送所需时间较长 ...

  2. celery异步任务框架

    目录 Celery 一.官方 二.Celery异步任务框架 Celery架构图 消息中间件 任务执行单元 任务结果存储 三.使用场景 四.Celery的安装配置 五.两种celery任务结构:提倡用包 ...

  3. django、celery异步发邮件

    django.celery异步发邮件 django自带的send_mail发邮件功能执行发邮件功能会因为网络的原因造成花费的时间过长,为了解决这个问题,可以用celery + redis代替 安装包: ...

  4. Django使用Celery异步任务队列

    1  Celery简介 Celery是异步任务队列,可以独立于主进程运行,在主进程退出后,也不影响队列中的任务执行. 任务执行异常退出,重新启动后,会继续执行队列中的其他任务,同时可以缓存停止期间接收 ...

  5. celery异步消息处理框架

    Celery 1.什么是Clelery Celery是一个简单.灵活且可靠的,处理大量消息的分布式系统 专注于实时处理的异步任务队列 同时也支持任务调度 Celery架构 Celery的架构由三部分组 ...

  6. Celery 异步任务

    Celery https://www.cnblogs.com/DragonFire/p/10356615.html 介绍: Celery 是芹菜 Celery 是基于Python实现的模块, 用于执行 ...

  7. Celery 异步任务 , 定时任务 , 周期任务 的芹菜

    1.什么是Celery?Celery 是芹菜Celery 是基于Python实现的模块, 用于执行异步定时周期任务的其结构的组成是由    1.用户任务 app    2.管道 broker 用于存储 ...

  8. celery异步认知

    celery是异步任务的框架 是由python实现的异步框架. 在使用celery我们经常分为三个部分, 第一部分就是我们所说的客户端, 就是发起异步任务的一方, 第二部分 任务队列 broker 第 ...

  9. Django商城项目笔记No.6用户部分-注册接口-短信验证码实现celery异步

    Django商城项目笔记No.4用户部分-注册接口-短信验证码实现celery异步 接上一篇,如何解决前后端请求跨域问题? 首先想一下,为什么图片验证码请求的也是后端的api.meiduo.site: ...

随机推荐

  1. 2017-2018-1 20179209《Linux内核原理与分析》第二周作业

    本周课业主要通过分析汇编代码执行情况掌握栈的变化.本人本科时期学过intel 80X86汇编语言,所以有一定基础:在Linux中32位AT&T风格的汇编稍微熟悉就可以明白.所以我学习的重点放在 ...

  2. 扫盲--.net 程序集

    前言:用了几天的时间把高级编程里面程序集一章看完了,原来自己只知道写代码,右键添加引用,从来也不知道操作的实质是什么,微软总是这个套路,鼠标点点就能把任务完成,这对新手友好但是对要通透了解程序执行和内 ...

  3. MySQL——存储引擎

    核心知识点 1.InnoDB:数据和索引存放在单独的文件,聚簇索引,行级锁,事务,MVCC 2.MyISAM: (1)缺点:不支持事务和表级锁,因为不支持表锁,锁颗粒比较大,因此适合只读和小文件. ( ...

  4. Zookeeper四字命令

    ZooKeeper 支持某些特定的四字命令(The Four Letter Words)与其进行交互.它们大多是查询命令,用来获取 ZooKeeper 服务的当前状态及相关信息.用户在客户端可以通过 ...

  5. TensorFlow框架(6)之RNN循环神经网络详解

    1. RNN循环神经网络 1.1 结构 循环神经网络(recurrent neural network,RNN)源自于1982年由Saratha Sathasivam 提出的霍普菲尔德网络.RNN的主 ...

  6. 20145239杜文超 《Java程序设计》第8周学习总结

    20145239 <Java程序设计>第8周学习总结 教材学习内容总结 通用API 日志API 1.java.util.logging包提供了日志功能相关类与接口,使用日志的起点是logg ...

  7. 51Nod 1294 修改数组 —— LIS

    题目链接:http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1294 1294 修改数组  题目来源: HackerRank ...

  8. HTML5响应式导航

    HTML5响应式导航HTML5,响应式,jQuery特效,HTML5导航,HTML5响应式导航是一款基于HTML5实现的深灰色响应式导航菜单. 地址:http://www.huiyi8.com/sc/ ...

  9. HDU 2643 Rank:第二类Stirling数

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2643 题意: 有n个个选手参赛,问排名有多少种情况(可以并列). 题解: 简化问题: 将n个不同的元素 ...

  10. 利用ThinkPHP做项目步骤

    ThinkPHP使用规则:约定大于配置 创建入口文件: 1.在ThinkPHP目录下创建一个入口文件index.php 2.访问入口文件的同时系统会自动把对应的应用目录文件Test创建出来 3.打开H ...