1from __future__ import absolute_import 2 3from typing import Callable 4from typing import Optional 5 6 7class uWSGIConfigError(Exception): 8 """uWSGI configuration error. 9 10 This is raised when uwsgi configuration is incompatible with the library. 11 """ 12 13 14class uWSGIMasterProcess(Exception): 15 """The process is uWSGI master process.""" 16 17 18def check_uwsgi(worker_callback=None, atexit=None): 19 # type: (Optional[Callable], Optional[Callable]) -> None 20 """Check whetever uwsgi is running and what needs to be done. 21 22 :param worker_callback: Callback function to call in uWSGI worker processes. 23 """ 24 try: 25 import uwsgi 26 except ImportError: 27 return 28 29 if not uwsgi.opt.get("enable-threads"): 30 raise uWSGIConfigError("enable-threads option must be set to true") 31 32 # If uwsgi has more than one process, it is running in prefork operational mode: uwsgi is going to fork multiple 33 # sub-processes. 34 # If lazy-app is enabled, then the app is loaded in each subprocess independently. This is fine. 35 # If it's not enabled, then the app will be loaded in the master process, and uwsgi will `fork()` abruptly, 36 # bypassing Python sanity checks. We need to handle this case properly. 37 # The proper way to handle that is to allow to register a callback function to run in the subprocess at their 38 # startup, and warn the caller that this is the master process and that (probably) nothing should be done. 39 if uwsgi.numproc > 1 and not uwsgi.opt.get("lazy-apps") and uwsgi.worker_id() == 0: 40 41 if not uwsgi.opt.get("master"): 42 # Having multiple workers without the master process is not supported: 43 # the postfork hooks are not available, so there's no way to start a different profiler in each 44 # worker 45 raise uWSGIConfigError("master option must be enabled when multiple processes are used") 46 47 # Register the function to be called in child process at startup 48 if worker_callback is not None: 49 try: 50 import uwsgidecorators 51 except ImportError: 52 raise uWSGIConfigError("Running under uwsgi but uwsgidecorators cannot be imported") 53 uwsgidecorators.postfork(worker_callback) 54 55 if atexit is not None: 56 57 original_atexit = getattr(uwsgi, "atexit", None) 58 59 def _atexit(): 60 try: 61 atexit() 62 except Exception: 63 pass 64 65 if original_atexit is not None: 66 original_atexit() 67 68 uwsgi.atexit = _atexit 69 70 raise uWSGIMasterProcess() 71