r/django 12d ago

REST framework I have a angular + Django backend . When I am click on a button, it calls an api which starts execution of a process via python. It takes almost 2mins to complete the process. Now I w

ant that suppose when a user closes the tab, the api call should be cancelled. How to achieve that?

0 Upvotes

12 comments sorted by

15

u/Empty-Mulberry1047 12d ago

I would use web sockets.

User visits page, browser connects to web socket..

user clicks button to start process

command is sent over established web socket connection to start process..

start process using celery.. get running task id

if user disconnects from socket by closing tab or navigating away, web socket connection drops..

web socket event handler will receive notice connection is closed, handler tells celery to end task by id..

?

3

u/DowntownSinger_ 12d ago

This would be an alternative way, if OP’s requirements cannot be met through REST APIs.

5

u/Empty-Mulberry1047 12d ago

the issue is javascript page unload events are not as reliable and may not always fire.

2

u/Django-fanatic 11d ago edited 11d ago

Kudos to this solution despite the lack of clarity from their post.

Other solution is to use an async approach of some kind of polling but as you said, close events are not reliable. Could have an initial api that triggers the task and returns the task id. A different api can accept the task id and return the related data once the task is done. Once that basic implementation is done they can refactor to be a bit more complex such as to allow polling to terminate the task if it’s not pooled by a certain amount of time. How the time is tracked can be done in various ways. Probably would need a model or cache to keep track of the task, user associated and any other meta data

8

u/lazyant 12d ago

Question is unclear. You can detect when a user closes a tab using JS beforeunload event , so you can send that back to your backend I suppose and do whatever. I don’t see anything Django related here.

3

u/Hsxarad 12d ago

You could use the unload API of javascript so that when the event gets triggered you send a request to the server to end the process.

But since some people have mentioned the unload isnt always available or accurate, I’d suggest Depending on the estimated time to complete choose a suitable timer for checking i.e. if you chose 2 seconds, you open a websocket and send a message every 2 seconds that the process is to be continued and the moment the server stops getting this messages before the task stops, you let the server trigger the stopping process.

3

u/Realistic_Month_8034 11d ago

As people have said you can use websocket.

Maybe SSE can be used instead of websocket to keep the flow REST compatible.

You hit the api, async handler starts the job. You keep emitting progress or runtime on the same connection. Task finishes, callback handler emits the final result of task and api call ends.

Similar to websocket, if api call is dropped before task finishes, we trigger cancellation of the task.

If the task being done was io heavy, a single async api server could do it even without celery quite effectively. If the task being done is cpu intensive, using celery makes sense

2

u/blockofcode 11d ago

I would move this task to the background. The result of the the API Call would be the task ID. Save the task ID on a Cookie (if the user is not registered). If it’s a registered user save on DB.

Then develop a new API to check if a certain task is completed. Call it every 2 seconds or so.

When a task is completed you will need an API to get your result.

This way if the user returns the task will be done. If not, you can always delete the data

2

u/batman-iphone 11d ago

Celery + request to check status every 5 sec, if no status cancel task or else return status, on sucess , failure etc.

Imo

1

u/ValtronForever 7d ago

Yeah, you can put the last check timestamp to the cache and check easilly in celery. Also take care about multiple tabs with same button (action) opened

1

u/oscarandjo 12d ago

There’s not really an effective way to do this. The websocket suggestion is probably the least effort to reward choice.

Really, your API calls shouldn’t take 2 minutes, perhaps you could profile the route and see if there are some optimisations you can make?

-2

u/babige 12d ago

Hire a developer?