mirror of
				https://github.com/zulip/zulip.git
				synced 2025-11-03 21:43:21 +00:00 
			
		
		
		
	uwsgi: Force Django load before returning the uwsgi worker function.
Django lazy-loads much of its modules, including the application's. This defers the time to during the first request it serves. When doing rolling-restarts, this means that the worker is marked "ready" despite having multiple seconds more work to do. With small numbers of workers, this causes a significant capacity drop, since effectively more than one worker can be still reloading at a time. It also results in poor user experience for the requests which are unlucky enough to be served first. Use the technique detailed in the uwsgi documentation[^1] to fake a request during initial application load, which forces the application to be loaded. [^1]: https://uwsgi-docs.readthedocs.io/en/latest/articles/TheArtOfGracefulReloading.html#dealing-with-ultra-lazy-apps-like-django
This commit is contained in:
		
				
					committed by
					
						
						Tim Abbott
					
				
			
			
				
	
			
			
			
						parent
						
							8589becc48
						
					
				
				
					commit
					eef65d7e30
				
			@@ -25,6 +25,9 @@ setup_path()
 | 
			
		||||
 | 
			
		||||
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "zproject.settings")
 | 
			
		||||
 | 
			
		||||
from collections.abc import Callable
 | 
			
		||||
from typing import Any
 | 
			
		||||
 | 
			
		||||
from django.core.wsgi import get_wsgi_application
 | 
			
		||||
 | 
			
		||||
try:
 | 
			
		||||
@@ -33,6 +36,37 @@ try:
 | 
			
		||||
    # setting points here.
 | 
			
		||||
 | 
			
		||||
    application = get_wsgi_application()
 | 
			
		||||
 | 
			
		||||
    # We force loading of the main parts of the application now, by
 | 
			
		||||
    # handing it a fake request, rather than have to pay that price
 | 
			
		||||
    # during the first request served by this process.  Hitting the
 | 
			
		||||
    # /health endpoint will not only load Django and all of the views
 | 
			
		||||
    # (by loading the URL dispatcher) but will also force open any
 | 
			
		||||
    # lazy-loaded service connections.
 | 
			
		||||
    #
 | 
			
		||||
    # The return value (and thus response status) of this healthcheck
 | 
			
		||||
    # request is ignored, so we do return the application handler even
 | 
			
		||||
    # if connections are not fully available yet.  This at least
 | 
			
		||||
    # allows application logging to handle any such errors, instead of
 | 
			
		||||
    # arcane errors from uwsgi not being able to load its handler
 | 
			
		||||
    # function.
 | 
			
		||||
    def ignored_start_response(
 | 
			
		||||
        status: str, headers: list[tuple[str, str]], exc_info: Any = None, /
 | 
			
		||||
    ) -> Callable[[bytes], object]:
 | 
			
		||||
        return lambda x: None
 | 
			
		||||
 | 
			
		||||
    application(
 | 
			
		||||
        {
 | 
			
		||||
            "REQUEST_METHOD": "GET",
 | 
			
		||||
            "SERVER_NAME": "127.0.0.1",
 | 
			
		||||
            "SERVER_PORT": "443",
 | 
			
		||||
            "PATH_INFO": "/health",
 | 
			
		||||
            "REMOTE_ADDR": "127.0.0.1",
 | 
			
		||||
            "wsgi.input": sys.stdin,
 | 
			
		||||
            "wsgi.url_scheme": "https",
 | 
			
		||||
        },
 | 
			
		||||
        ignored_start_response,
 | 
			
		||||
    )
 | 
			
		||||
except Exception:
 | 
			
		||||
    # If /etc/zulip/settings.py contains invalid syntax, Django
 | 
			
		||||
    # initialization will fail in django.setup().  In this case, our
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user