Django: How to run a function when server exits?

前端 未结 2 1847
独厮守ぢ
独厮守ぢ 2021-01-12 09:24

I am writing a Django project where several processes are opened using Popen. Right now, when the server exits, these processes are orphaned. I have a function to terminate

相关标签:
2条回答
  • 2021-01-12 09:43

    First of all "When the server quits" is ambiguous. Does this stuff run when responding to a request? Does this stuff run during a management command?

    Let's assume for the sake of argument, that you are running this somewhere in a view, so you want to have something that runs after each view returns in order to clean up junk that the view left hanging around.

    Most likely, what you are looking to do is to write some Middleware. Even more specifically, some sort of process_response.

    However, based on the short description of what you have so far, it sounds far more likely that you should be using some task manager, such as Celery to manage asynchronous tasks and processes.

    0 讨论(0)
  • 2021-01-12 09:49

    Since you haven't specified which HTTP server you are using (uWSGI, nginx, apache etc.), you can test this recipe out on a simple dev server.

    What you can try is to register a cleanup function via atexit module that will be called at process termination. You can do this easily by overriding django's builtin runserver command.

    Create a file named runserver.py and put that in $PATH_TO_YOUR_APP/management/commands/ directory.

    Assuming PROCESSES_TO_KILL is a global list holding references to orphan processes that will be killed upon server termination.

    import atexit
    import signal
    import sys
    
    from django.core.management.commands.runserver import BaseRunserverCommand
    
    class NewRunserverCommand(BaseRunserverCommand):
        def __init__(self, *args, **kwargs):
            atexit.register(self._exit)
            signal.signal(signal.SIGINT, self._handle_SIGINT)
            super(Command, self).__init__(*args, **kwargs)
    
        def _exit(self):
            for process in PROCESSES_TO_KILL:
                process.terminate()
    
        def _handle_SIGINT(signal, frame):
            self._exit()
            sys.exit(0)
    

    Just be aware that this works great for normal termination of the script, but it won't get called in all cases (e.g. fatal internal errors).

    Hope this helps.

    0 讨论(0)
提交回复
热议问题