仅在单击按钮时运行 celery 任务
Posted
技术标签:
【中文标题】仅在单击按钮时运行 celery 任务【英文标题】:run celery task only once on button click 【发布时间】:2018-04-14 23:55:16 【问题描述】:我创建了一个带有 celery 任务的 django 应用程序,用于组织数据库表。 celery 任务大约需要 8 秒来完成这项工作(相当繁重的表移动和超过 100 万行的查找)
这个 celery 是通过一个注册用户点击一个按钮开始的。
我在 views.py 中创建了一个任务视图,并在 urls.py 中创建了一个单独的任务 URL。导航到此任务 URL 时,任务启动。
我的问题:
-
当您在任务未完成的情况下刷新任务 URL 时,您会启动一个新任务。
使用此设置,您可以导航到另一个页面或重新加载视图
如何防止任务在每次刷新时启动并防止导航到另一个页面。理想情况下,用户只能运行此特定类型的一项任务。
这对 JQuery/Ajax 是否可行?由于我不是专家,也没有使用 JQuery/Ajax 的经验,因此能否有英雄指出我正确的方向。
谢谢
【问题讨论】:
【参考方案1】:“如何防止任务在每次刷新时启动”
首先确保您使用“POST/redirect/GET”模式:您的视图应该只在“POST”请求时触发任务(GET 请求必须没有副作用),并且然后返回一个HttpResponseRedirect
。
这不会阻止用户在第一个任务仍在运行时触发第二个任务,但它确实阻止每次刷新(“GET”)页面时重新提交表单。 ..
理想情况下,用户只能运行此特定类型的一项任务。
触发任务时,将其 ID 存储在会话中,在触发任务之前检查会话中的任务 ID。如果有,用它来检查任务的状态。如果完成(无论结果如何),删除任务 ID 并继续执行新任务,否则只显示一条消息,告诉您的用户他已经有一个任务正在运行。
只需确保您正确处理会话中“幽灵”task_id 的情况(它可能是 celery 已经丢弃结果的长期完成任务,或者在工作人员或代理崩溃中丢失的任务 - 是的, sh!t 发生 - 等等)。一个可行的解决方案是实际存储 (timestamp, task_id)
对,如果 celery 没有 task_id 的状态
- 实际上“无状态”被(错误)命名为celery.states.PENDING
,这实际上意味着“我不知道这个任务的状态 ATM” - 检查时间戳。如果它比它应该的旧得多,那么你可能会认为它已经死了并且在 6 英尺以下。
并防止导航到另一个页面。
实际上,您为什么要阻止您的用户在此期间执行其他操作?从 UI/UX 的角度来看,一旦任务被触发,您的用户应该被重定向到带有(尽可能)一些进度条或类似反馈的“请稍候”页面。这里的简单(如果有点重)解决方案是使用 ajax 进行一些轮询:您设置一个带有 task_id 的视图,检查结果/进度并将它们作为 json 返回,“请稍候”页面调用此视图(使用 ajax ) 每 X 秒更新一次(并可能在任务完成后将用户重定向到下一页)。
现在,如果有一些操作(除了重新启动相同的任务)您的用户在任务运行时无法执行,您可以对这些操作使用相同的“检查当前任务的会话”机制(使视图装饰器真的很有帮助)。
【讨论】:
嗨 Bruno,我终于使用 Ajax POST 来获取注册到 views.py 的按钮并使用 30 秒超时进行缓存。为一个特定的会话变量设置特定的超时是行不通的。关于导航到另一个页面:这仅在我使用特定 url 指向类似 html 时才相关。 我的缓存目前正在发生的另一件事。我无法从我的 celery 任务中清除缓存,因为这是来自“worker”的缓存,而不是来自“web”进程的缓存。关于如何做到这一点的任何想法?还是去找别的东西然后缓存? 缓存是可以的,直到你必须使它们失效我相信在服务器端使用锁可以更轻松地完成,请参阅这个问题Running "unique" tasks with celery
如果需要在客户端完成,可能的方法是像这样设置cookie
if (typeof $.cookie("running") === "undefined")
var date = new Date();
var minutes = 20;
date.setTime(date.getTime() + (minutes * 60 * 1000));
$.cookie("running", "true", expires: date );
任务完成后删除
【讨论】:
以上是关于仅在单击按钮时运行 celery 任务的主要内容,如果未能解决你的问题,请参考以下文章
安排 Django Celery 定期任务从某个时间运行到另一个时间
如果结果已经可用,则仅在单击按钮时启动异步任务并执行操作,否则等待结果然后执行操作