PeriodicTask.objects.create(
interval=interval,
crontab=crontab,
clocked=clocked,
name=data["name"],
task=data["task"], # dropdown
args=json.dumps(json.loads(data["args"])),
one_off=True if schedule_type == "clocked" else False,
expires=datetime.strptime(data["expires"], '%Y-%m-%d %H:%M:%S.%f') if data["expires"] else None
)
-它在设置过期时间后仍在运行
-它不调用函数,但它命中worker
例如:在worker终端
[2024-07-22 07:06:16,334: INFO/MainProcess] Task test[390404a1-9814-4208-85a2-6e1269bc09d9] received
[2024-07-22 07:06:16,334: INFO/MainProcess] Discarding revoked task: test[390404a1-9814-4208-85a2-6e1269bc09d9]
和celerybeat终端中
[2024-07-22 07:06:16,327: WARNING/MainProcess] 390404a1-9814-4208-85a2-6e1269bc09d9 has an expiration date in the past (16.325898s ago).
We assume this is intended and so we have set the expiration date to 0 instead.
According to RabbitMQ's documentation:
"Setting the TTL to 0 causes messages to be expired upon reaching a queue unless they can be delivered to a consumer immediately."
If this was unintended, please check the code which published this task.```
代码片段显示你正在使用 Celery 的定期任务,并为其设置了过期时间(
expires
参数)。然而,你观察到即使任务过期了,它仍然在 Celery Beat 和 Celery Worker 之间传递,尽管它没有真正执行。
出现这种情况可能有以下几个原因:
1. 过期时间设置不正确:
-
时区问题:
确保
expires
参数中使用的时间与 Celery Beat 和 Celery Worker 使用的时区一致。如果时区不一致,过期时间可能会被错误地解释。 -
时间格式问题:
确保
expires
参数使用的是 Celery 能够正确解析的时间格式。根据你的代码,你使用的是'%Y-%m-%d %H:%M:%S.%f'
,这应该是正确的格式。 - 过期时间已过: 检查你设置的过期时间是否已经过去。如果过期时间在任务创建之前,Celery 会将其视为无效的过期时间。
2. RabbitMQ 消息队列的行为:
- 消息持久化: Celery 默认使用持久化的消息队列,这意味着即使 Celery 停止运行,消息也会被保存在队列中。如果你的任务在过期之前没有被消费,它可能会在 Celery 重新启动后再次被调度。
- 消息 TTL: Celery Beat 会根据任务的过期时间设置消息的 TTL(Time-to-Live)。然而,RabbitMQ 的默认行为是只有当消息到达队列头部时才会检查 TTL。如果队列中有其他消息,即使过期,你的任务也可能需要等待一段时间才会被丢弃。
3. Celery 配置问题:
- CELERY_TIMEZONE: 确保 Celery 的时区设置正确,与你的应用程序和数据库一致。
-
CELERY_ENABLE_UTC:
如果你使用的是 UTC 时间,请确保
CELERY_ENABLE_UTC
设置为True
。
解决方法:
-
检查并更正过期时间:
确保
expires
参数使用正确的时间、时区和格式。 - 配置 RabbitMQ: 可以考虑配置 RabbitMQ 以使用非持久化队列或调整消息 TTL。但要注意,这可能会影响其他 Celery 任务。
-
使用
revoke()
方法: 如果需要立即停止一个定期任务,可以使用revoke()
方法。例如: ```python from celery.task.control import revoke
revoke(task_id, terminate=True) ``` 4. 升级 Celery 版本: 一些旧版本的 Celery 可能存在与过期时间处理相关的 bug。尝试升级到最新版本。
代码改进建议:
-
使用时区感知的 datetime 对象:
为了避免时区问题,建议使用时区感知的
datetime
对象。可以使用pytz
库来创建时区感知的对象。 - 记录日志: 在你的任务代码中添加日志记录,以便更好地了解任务执行和过期时间处理的过程。
通过仔细检查代码、配置和 Celery 的行为,你应该能够找到导致问题的原因并解决它。
标签:python,django,celery From: 78777365