What happens when you have an infinite loop in your Django view code?

Something I was just thinking about:

Let's say I write a view code for my Django site, and I make a mistake and create an infinite loop.

Whenever someone tries to access a view, the worker assigned to the request (whether it be a working Gevent or a Python thread) will remain in the loop indefinitely.

If I understood correctly, the server would send a timeout error to the client in 30 seconds. But what will happen to the Python worker? Will it continue to work endlessly? That sounds dangerous!

Imagine that I have a server on which I have allocated 10 workers. I let it work, and at some point the client tries to access the view using an infinite loop. An employee will be assigned to him and will be effectively dead until the next server restart. It is dangerous that at first I would not notice this, because the site would be imperceptibly slower, having 9 workers instead of 10. But then this can happen again and again over a long period of time, maybe months. The site will become slower, until, in the end, it will be very slow with one employee.

Restarting the server will solve the problem, but I would not want my site functionality to depend on a server reboot.

Is this a real problem? Is there any way to avoid this?

Update:. I am also very grateful that I found a thread / worker stop path that was stuck in an infinite loop, so I could send it by email so that I know the problems. (I do not know how to do this because there are no exceptions.)

Refresh for people saying that “Avoid writing code with infinite loops”: in case it wasn’t obvious, I don’t spend my free time deliberately putting endless loops in my code. When this happens, they are bugs, and bugs can be minimized, but never completely eliminated. I want to know that even when I'm wrong, there will be a security network that will notify me and allow me to solve the problem.

+7
source share
3 answers

This is a real problem. In the case of gevent, due to context switching, it can even immediately stop your site from responding.

It all depends on your environment. For example, when starting django during production through uwsgi, you can set harakiri - this is the time in seconds, after which the request processing flow will be killed if it does not complete the response processing. It is highly recommended that you set this value to deal with some erroneous requests or bad code. Such an event is reported in the uwsgi journal. I believe that other solutions for launching Django in production have similar options.

Otherwise, due to the network architecture, disconnecting the client will not stop the endless loop, and by default there will be no answer at all - just an endless download. Various timeout options (one of which is harakiri ) can ultimately show the connection timeout — for example, php has (as I recall) a default time of 30 seconds and it will return a 504 gateway timeout. The timeout for disconnecting the connector depends on the settings of the http server and does not stop the application flow; it closes only the client socket.

If you do not use gevent (or any other green threads), an infinite loop will consume 100% of the available processor power (limited to one core), possibly consuming more and more memory, so your site will work quite slowly and / or time out very quickly . Django itself is not aware of the request time, so as mentioned earlier, the stacks of your production environment is a way to prevent this. In the case of uwsgi http://uwsgi-docs.readthedocs.org/en/latest/Options.html#harakiri-verbose is the way to go.

Harakiri prints a trace of the stack of killed processes: ( https://uwsgi-docs.readthedocs.org/en/latest/Tracebacker.html?highlight=harakiri ) directly to the uwsgi log, and due to the alarm system you may receive a notification email ( http://uwsgi-docs.readthedocs.org/en/latest/AlarmSubsystem.html )

+4
source

I just tested this on a Django development server.

Results:

  • Does not give a timeout after 30 seconds. (this may be because it is not a production server)
  • It stays on loading until I close the page.

I guess one way to avoid this without actually avoiding such code is to use threads to control timeouts and be able to stop the thread.

Maybe something like:

 import threading from django.http import HttpResponse class MyThread(threading.Thread): def __init__(self): threading.Thread.__init__(self) def run(self): print "your possible infinite loop code here" def possible_loop_view(request): thread = MyThread() thread.start() return HttpResponse("html response") 
+2
source

Yes, your analysis is correct. Workflow / process will continue to work. Moreover, if there is no standby / sleep mode in the loop, it will start the processor. Other threads / process will receive very little CPU, as a result, your entire site will respond more slowly.

Also, I don't think the server will explicitly send a timeout error to the client. If a TCP timeout is set, the TCP connection will be closed.

The client may also have some waiting time to get an answer that may appear in the picture.

Avoiding such code is the best way to avoid such code. You may also have some server monitoring tool to look for CPU / memory usage and notify of abnormal activity so that you can take action.

0
source

All Articles