Command(runserver.py)

django 실행(runserver) 커맨드 분석

python [manage.py](<http://manage.py>) runserver
  1. manage.py에 등록된 main 함수 호출

  2. execute_from_command_line에서 입력된 인자(”runserver”)를 받고 ManagementUtility에 전달

  3. utility.execute() 실행

  4. fetch_command().run_from_argv(): runserver command 클래스의 handle 메소드 실행

  5. Runserver.handle(): 주소 파싱 및 유효성 검증 후 run 메소드 실행

  6. Runserver.run(): inner_run 메소드 실행 with 파일 와치 리로더

    1. start_django 실행: django-main-thread 생성(target=inner_run)
  7. Runserver.inner_run()

    1. check_migrations()
    2. handler = get_handler() → WSGIHandler 반환
    3. run 함수 호출
  8. run 함수 실행

    # wsgi_handler: StaticFilesHandler or WSGIHandler
    def run(addr, port, wsgi_handler, ipv6=False, threading=False, server_cls=WSGIServer):
        server_address = (addr, port)
    		
        if threading:  # threading = True
    		    # ---------- 다음 스텝 호출 ----------
            httpd_cls = type('WSGIServer', (socketserver.ThreadingMixIn, server_cls), {})
        else:
            httpd_cls = server_cls
        httpd = httpd_cls(server_address, WSGIRequestHandler, ipv6=ipv6)
        if threading:
            httpd.daemon_threads = True
        httpd.set_app(wsgi_handler)
        httpd.serve_forever()
    

WSGIServer(simple_server.WSGIServer, HTTPServer, TCPServer, BaseServer)

  1. init() 실행

    class TCPServer(BaseServer):
        def __init__(self, server_address, RequestHandlerClass, bind_and_activate=True):
            """Constructor.  May be extended, do not override."""
            BaseServer.__init__(self, server_address, RequestHandlerClass)
            self.socket = socket.socket(self.address_family,
                                        self.socket_type)
            if bind_and_activate:
                try:
                    self.server_bind()  # 소켓 바인딩(socket.bind(self.server_address))
                    self.server_activate()  # socket.listen()
                except:
                    self.server_close()  # socket.close()
                    raise
    
  2. serve_forever()

    # BaseServer.__is_shut_down = threading.Event()
    # BaseServer.__shutdown_request = False
    class BaseServer:
        def serve_forever(self, poll_interval=0.5):
            self.__is_shut_down.clear()
            try:
                with _ServerSelector() as selector:
                    # selector에 read event를 감지할 수 있도록 등록
                    selector.register(self, selectors.EVENT_READ)
    
                    while not self.__shutdown_request:
    			              # read event 발생 시 ready에 값 할당(리스트)
                        ready = selector.select(poll_interval)
                        if self.__shutdown_request:
                            break
                        if ready:
    		                    # selector 값 변경 감지되면 요청 처리 메소드 호출
                            self._handle_request_noblock()
    
                        self.service_actions()
            finally:
                self.__shutdown_request = False
                self.__is_shut_down.set()
    
  3. _handle_request_noblock(): 자식 클래스들에 정의된 메소드 호출

    class BaseServer:
    		def _handle_request_noblock(self):
    		    try:
    				    # TCPServer.get_request()
    		        request, client_address = self.get_request()  # socket.accept()
    		    except OSError:
    		        return
    		    if self.verify_request(request, client_address):
    		        try:
    				        # ThreadingMixIn.process_request()
    		            self.process_request(request, client_address)
    		        except Exception:
    		            self.handle_error(request, client_address)
    		            # TCPServer.shutdown_request()
    		            self.shutdown_request(request)
    		        except:
    		            self.shutdown_request(request)
    		            raise
    		    else:
    		        self.shutdown_request(request)
    
        def finish_request(self, request, client_address):
    		    # self.RequestHandlerClass = WSGIRequestHandler
    		    # ---------- 다음 스텝 호출 ----------
            self.RequestHandlerClass(request, client_address, self)
    
    class TCPServer(BaseServer):
        def shutdown_request(self, request):
            try:
                request.shutdown(socket.SHUT_WR)
            except OSError:
                pass #some platforms may raise ENOTCONN here
            self.close_request(request)
    
        def close_request(self, request):
            request.close()
    
    class ThreadingMixIn:
    		def process_request_thread(self, request, client_address):
    		    try:
    				    # BaseServer.finish_request
    		        self.finish_request(request, client_address)
    		    except Exception:
    		        self.handle_error(request, client_address)
    		    finally:
    				    # TCPServer.shutdown_request
    		        self.shutdown_request(request)
    		
    		def process_request(self, request, client_address):
    		    if self.block_on_close:
    		        vars(self).setdefault('_threads', _Threads())
    		    t = threading.Thread(target = self.process_request_thread,
    		                         args = (request, client_address))
    		    t.daemon = self.daemon_threads
    		    self._threads.append(t)
    		    t.start()
    
    # from django.core.servers.basehttp WSGIServer
    # django level에서 사용
    # class WSGIServer(socketserver.ThreadingMixin, simple_server.WSGIServer):  
    

WSGIRequestHandler(simple_server.WSGIRequestHandler, BaseHTTPRequestHandler, StreamRequestHandler, BaseRequestHandler)

  1. init() 호출

    class BaseRequestHandler:
        def __init__(self, request, client_address, server):
            self.request = request
            self.client_address = client_address
            self.server = server
    				# StreamRequestHandler.setup()
            self.setup()
            try:
    		        # WSGIRequestHandler.handle()
                self.handle()
            finally:
    		        # StreamRequestHandler.finish()
                self.finish()
                
                
    class StreamRequestHandler(BaseRequestHandler):
        def setup(self):
            self.connection = self.request  # socket obj
            if self.timeout is not None:
                self.connection.settimeout(self.timeout)
            if self.disable_nagle_algorithm:
                self.connection.setsockopt(socket.IPPROTO_TCP,
                                           socket.TCP_NODELAY, True)
            self.rfile = self.connection.makefile('rb', self.rbufsize)
            if self.wbufsize == 0:
    		        # class _SocketWriter(BufferedIOBase)
                self.wfile = _SocketWriter(self.connection)
            else:
                self.wfile = self.connection.makefile('wb', self.wbufsize)
    
        def finish(self):
            if not self.wfile.closed:
                try:
                    self.wfile.flush()
                except socket.error:
                    pass
            self.wfile.close()
            self.rfile.close()
            
    
    class WSGIRequestHandler(simple_server.WSGIRequestHandler):
        def handle(self):
            self.close_connection = True
            self.handle_one_request()
            while not self.close_connection:
                self.handle_one_request()
            try:
                self.connection.shutdown(socket.SHUT_WR)
            except (AttributeError, OSError):
                pass
                
        def handle_one_request(self):
            self.raw_requestline = self.rfile.readline(65537)
            if len(self.raw_requestline) > 65536:
                self.requestline = ''
                self.request_version = ''
                self.command = ''
                self.send_error(414)
                return
    
            if not self.parse_request():  # An error code has been sent, just exit
                return
    				
    				# self.rfile = io.BufferedReader
    				# self.wfile = socketserver._SocketWriter
    		    # ---------- 다음 스텝 호출 ----------
            handler = ServerHandler(
                self.rfile, self.wfile, self.get_stderr(), self.get_environ()
            )
            handler.request_handler = self      # backpointer for logging & connection closing
            handler.run(self.server.get_app())