简体   繁体   English

单击按钮仅运行一次celery任务

[英]run celery task only once on button click

I created a django app with a celery task that organises database tables. 我创建了一个celery任务来组织数据库表的django应用。 The celery task takes about 8 seconds to do the job ( quite heavy table moves and lookups in over 1 million lines ) 芹菜任务大约需要8秒钟来完成这项工作(相当多的表移动和超过100万行的查找)

This celery starts through a button click by a registered user. 此芹菜通过注册用户单击按钮开始。

I created a task-view in views.py and a separate task-url in urls.py. 我在views.py中创建了一个任务视图,并在urls.py中创建了一个单独的task-url。 When navigating to this task-url, the task starts. 导航到此任务URL时,任务开始。

My Problem: 我的问题:

  1. When you refresh the task-url while the task is not finished, you fire up a new task. 在任务未完成时刷新任务URL时,将启动新任务。
  2. With this set-up, you navigate to another page or reload the view 通过此设置,您可以导航到另一个页面或重新加载视图

How do I prevent the task from firing up each time on refresh and prevent navigating to another page. 如何防止每次刷新时启动任务,并防止导航到另一个页面。 Ideally, a user can only run one task of this particular type. 理想情况下,用户只能运行此特定类型的一项任务。

Might this be doable with JQuery/Ajax? 可以在JQuery / Ajax中实现吗? Could some hero point me out in the right direction as I am not an expert an have no experience with JQuery/Ajax. 因为我不是专家,也没有使用JQuery / Ajax的经验,所以有些英雄可以向我指出正确的方向。

Thanks 谢谢

"How do I prevent the task from firing up each time on refresh" “如何防止每次刷新时启动任务”

First make sure you use the "POST/redirect/GET" pattern: your view should only fire the task on a "POST" request (GET request must not have side-effects), and then return a HttpResponseRedirect . 首先,请确保使用“ POST / redirect / GET”模式:您的视图应仅在“ POST”请求上触发任务(GET请求必须没有副作用),然后返回HttpResponseRedirect

This won't prevent the user from firing a second task while the first is still running, but it does prevent re-submitting the form each time you refresh ("GET") the page... 这不会阻止用户在第一个任务仍在运行时触发第二个任务,但确实可以防止每次刷新(“ GET”)页面时重新提交表单...

Ideally, a user can only run one task of this particular type. 理想情况下,用户只能运行此特定类型的一项任务。

When firing a task, store it's id in the session, and before firing a task check the session for a task id. 触发任务时,将其ID存储在会话中,并触发任务之前检查会话中的任务ID。 If there's one, use it to check the task's state. 如果有,请使用它检查任务的状态。 If it's done (whatever the result), remove the task id and proceed with the new task, else just display a message telling your user he already has a task running. 如果完成(无论结果如何),请删除任务ID并继续执行新任务,否则仅显示一条消息,告诉您用户他已经在运行任务。

Just make sure you correctly handle the case of a "ghost" task_id in the session (it might be a long finished task for which celery already discarded the results, or a task that got lost in a worker or broker crash - yeah, sh!t happens - etc). 只要确保您在会话中正确处理了“幽灵” task_id的情况即可(这可能是一个长期完成的任务,芹菜已经放弃了该结果,或者是一个因工人或经纪人崩溃而迷失的任务-是的,嘘! t发生-等等)。 A working solution is to actually store a (timestamp, task_id) pair and if celery has no state for the task_id - actually "no state" is (mis)named celery.states.PENDING , which really means "I don't have a clue about this task's state ATM" - check the timestamp. 一个(timestamp, task_id)解决方案是实际存储(timestamp, task_id)对,并且如果celery没有task_id的状态-实际上“无状态”被命名为celery.states.PENDING ,这实际上意味着“我没有一个有关此任务的状态ATM的线索”-检查时间戳记。 If it's way older than it should then you can probably consider it as long dead and 6 feets under. 如果它比它应有的年代久远,那么您可能会认为它已经死了而且在6英尺以下。

and prevent navigating to another page. 并防止导航到另一个页面。

Why would you want to prevent your user to do something else in the meantime, actually ? 实际上,您为什么要阻止您的用户执行其他操作? From a UI/UX point of view, once the task is fired, your user should be redirected to a "please wait" page with (as much as possible) some progress bar or similar feedback. 从UI / UX的角度来看,一旦任务被触发,您的用户应被重定向到“请稍候”页面,并(尽可能)带有一些进度条或类似的反馈。 The simple (if a bit heavy) solution here is to do some polling using ajax : you setup a view that takes a task_id, check results / progress and returns them as json, and the 'please wait' page calls this views (using ajax) every X seconds to update itself (and possibly redirect the user to the next page when the task is done). 这里的简单(如果有点繁琐)的解决方案是使用ajax进行一些轮询:您设置一个接受task_id的视图,检查结果/进度,并将其返回为json,然后“请等待”页面调用此视图(使用ajax )每隔X秒更新一次(可能会在完成任务后将用户重定向到下一页)。

Now if there are some operations (apart from re-launching the same task) your user couldn't do while a task is running, you can use the same "check session for a current task" mechanism for those operations (making it a view decorator really helps). 现在,如果有一些操作(除了重新启动同一任务),而用户在任务运行时无法执行,则可以对这些操作使用相同的“检查当前任务的会话”机制(将其作为视图装饰器确实有帮助)。

I believe it can be done more easily on the server side using locks,see this question Running "unique" tasks with celery 我相信使用锁可以在服务器端更轻松地完成此操作,请参见此问题。 用芹菜运行“独特”任务

If it needs to be done on the client side, possible approach would be setting cookie like this 如果需要在客户端完成,可能的方法是像这样设置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 });
}

and deleting when the task is finished 并在任务完成时删除

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM