"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
.
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...
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. 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.
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). 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. If it's way older than it should then you can probably consider it as long dead and 6 feets under.
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. 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).
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).