Forums

Http response not sent to the client after child process spawned.

Hello

I have an issue with the server not sending the request to the client. I've narrowed the problem to the code below :

solve_async = Process(target=sudoku.solve, args=(grid, persistent_grid))
solve_async.start()
return HttpResponseRedirect(reverse('solver:solved', args=(persistent_grid.id,)))

As you can see, in this code I'm spawning a child process and right after (the child process don't block) a response is sent to the client. But from the client side, the response is not received. I can see that the browser is waiting for the response and finally timeout.

For information, the child process is working perfectly. I can tell because it updates record in the database.

There's no entry in the error log.

In the server logo there's

2020-05-22 11:48:24 Fri May 22 11:48:24 2020 - received message 0 from emperor
2020-05-22 11:48:24 SIGINT/SIGQUIT received...killing workers...
2020-05-22 11:48:26 worker 1 buried after 2 seconds
2020-05-22 11:48:26 goodbye to uWSGI.
2020-05-22 11:48:26 chdir(): No such file or directory [core/uwsgi.c line 1610]
2020-05-22 11:48:26 VACUUM: unix socket /var/sockets/anotherdeadpixel.pythonanywhere.com/socket removed

Any idea why the HttpResponseRedirect line of code is not executed by the server ?

Thanks for your help !

That does sound a bit odd. What happens if you put some debugging print statements before and after the call to the start method? If you do this:

print(f"{datetime.now()} about to start", flush=True)
solve_async.start()
print(f"{datetime.now()} started, returning response", flush=True)
return HttpResponseRedirect(reverse('solver:solved', args=(persistent_grid.id,)))

...with a from datetime import datetime at the top of the file, then you'll get timestamped messages in the server log file, which might allow you to get more of a handle on what is going on.

Hello Giles, thanks for your suggestion !

I did that and can confirm that the debugging prints appear in the server log file.

2020-05-23 10:53:17 2020-05-23 10:53:17.296740 about to start  
2020-05-23 10:53:17 2020-05-23 10:53:17.299919 started, returning response

Still the browser is waiting for a response and finally timeout. Forgot to mention this before, but the same code is running fine locally.

Also, I noticed in the server log the line

2020-05-23 10:52:37 *** Operational MODE: single process ***

Could this explain the issue (as I'm starting a second process) ?

Thank you !

I wonder if the redirect was sent to the the browser but the redirected url is taking a long time / timing out?

Hello Conrad,

The redirected url is of type /id/solved. It is a very simple html page that render very quickly.

You can check it:

http://anotherdeadpixel.pythonanywhere.com/13/solved/

So I don't think that's the issue.

To me, looks like the main Django process is in a incoherent state after the child process is spawn, and fails to resume properly the rendering. I keep on investigating.

Thank You !

what is solve_async.start()? Does it spawn a subprocess or does it try to run async code? If it's just running async code then I think there's a possibility that it is blocking. And since you have a free account, there is only one worker, and so the second request to the redirected /id/solved url never loads because the first request is still blocking.

Can you use browser dev tools to check if the redirect ever gets back to the browser?

Hello Conrad,

Thanks for keeping investigating with me :)

Indeed, solve_async.start() spawn a subprocess that (should) run asynchronously from the main process. If there's only one worker permitted with free account (didn't know that) then the behaviour of the code and your explanation totally make sense.

This is also confirmed by the fact that, out of curiosity, I deployed the app to Heroku and it's working great. So the app code is not the culprit ;-)

Thanks for your help, mystery resolved !

It is true that free accounts get only one web worker.

Anyhow, I would say that the recommended architecture would be to do the solving on a different machine. ie. instead of the web server, you should pass the solving off to say an always on task that is running in the background aside from the web server.