Why can't this Python process for multiprocessing be stopped with Kivy?

I am trying to start the django development server from a Kivy application. So far it has been very good.

Now I want to allow the user to continue working with the program while the server is running. My idea was to create multiprocessing. The process for httpd.serve_forever () is to avoid completely blocking the main program. It works well. This is the code in my internal_django module:

import multiprocessing import os import time from wsgiref.simple_server import make_server def django_wsgi_application(): PROJECT_ROOT = os.path.dirname(os.path.abspath(__file__)) settings_module = "djangosettings"#%s.djangosettings" % PROJECT_ROOT.split(os.sep)[-1] os.environ.update({"DJANGO_SETTINGS_MODULE":settings_module}) from django.core.wsgi import get_wsgi_application application = get_wsgi_application() return application class Singleton(type): _instances = {} def __call__(cls, *args, **kwargs): if cls not in cls._instances: cls._instances[cls] = super(Singleton, cls).__call__(*args, **kwargs) return cls._instances[cls] class DjangoServer(): __metaclass__ = Singleton def start(self): self.httpd = make_server('', 8000, django_wsgi_application()) self.server = multiprocessing.Process(target=self.httpd.serve_forever) self.server.start() print "Now serving on port 8000..." print "Server Process PID = %s" %self.server.pid def stop(self): print("shutdown initiated") print "Server Process PID = %s" %self.server.pid while self.server.is_alive(): self.server.terminate() print("Server should have shut down") time.sleep(1) print("Server is_alive: %s" %self.server.is_alive()) self.server.join() print("server process joined") if __name__ == "__main__": server = DjangoServer() server.start() time.sleep(3) server.stop() 

When I run this code, everything works as expected. This is what is laid out in the console:

 Now serving on port 8000... Server Process PID = 1406 shutdown initiated Server Process PID = 1406 Server should have shut down Server is_alive: False server process joined 

The next step was to provide the ability to stop the server from the Kivy application. For this, I just wanted to use my DjangoServer class, as before:

 from internal_django import DjangoServer class StartScreen(Screen): def start_server(self): server = DjangoServer() server.start() class StopScreen(Screen): def stop_server(self): server = DjangoServer() server.stop() 

But at the same time, the process that once started was never completed. My first idea was that Singleton did not work as expected, and that I was trying to get out of the wrong process. but, as you can see at the output, the PID code is identical. The server receives the terminate command, but continues to work. Here is what the console looks like:

 Now serving on port 8000... Server Process PID = 1406 shutdown initiated Server Process PID = 1406 Server should have shut down Server should have shut down Server should have shut down Server should have shut down Server should have shut down Server should have shut down Server should have shut down Server should have shut down (and so on, until i manually kill the server process) 

Am I using multiprocessing completely wrong? Qiwi somehow interferes with the process?

+5
source share
2 answers

I think there can be two problems here:

  • The signal handler intercepts the TERM request sent by Process.terminate () and ignores it. To make sure that you simply use signal.getsignal (signal.SIGTERM) from the new process and print the results. To work around this problem, you can reset the default behavior with the signal signal.signal (signal.SIGTERM, signal.SIG_DFL), however, keep in mind that there may be a reason why SIGTERM is disabled by frameworks (I am not familiar with with Django and Kivy).

  • If you are using Python 2, you should consider that the interpreter does not process signals if it is blocked in the synchronization primitive from the thread library (Locks, Semaphores ..) or on the native C call. The serve_forever () function may fail in these cases (use force source!). A quick check may try to run the code in Python 3 and see if it works or not.

A quick and dirty solution is to wait a little time and send SIGKILL if the process is still alive.

 import os import signal process.terminate() process.join(1) if process.is_alive() and os.name != 'nt': try: os.kill(process.pid, signal.SIGKILL) process.join() except OSError: return # process might have died while checking it 

In windows, you cannot kill a process in such a simple way that I test os.name.

This is a rather rude approach, so I would rather find the cause of the problem.

+3
source

What happens if you call terminate() , then join() and skip the while loop? In addition, I mix the code a bit and encode the code in _create_server() . Please let me know if this works for you.

 class DjangoServer(): __metaclass__ = Singleton def _create_server(self): httpd = make_server('', 8000, django_wsgi_application()) print "Now serving on port {}...".format(httpd.server_port) httpd.serve_forever() def start(self): self.server = multiprocessing.Process(target=self._create_server) self.server.start() print "Server Process PID = %s" %self.server.pid def stop(self): print("shutdown initiated") print "Server Process PID = %s" %self.server.pid self.server.terminate() self.server.join() print("server process terminated") 
+1
source

Source: https://habr.com/ru/post/1206985/


All Articles