首页 > 解决方案 > HTTP Server 在嵌套线程方案中保持线程活动

问题描述

我有一个小的 HTTPServer 实现,我正在启动以侦听来自 API 的回调。在测试中,这个实现是保持最里面的线程活着。这是服务器:

import http
import uuid
from http import server

class Server(server.HTTPServer):

    RequestLog:list = []
    ErrorList:list = []
    Serve:bool = True

    def __init__(self, server_address, RequestHandlerClass):

        self.RequestLog = []
        self.ErrorList = []
        self.Serve:bool = True

        return super().__init__(server_address, RequestHandlerClass)

    def LogRequest(self, clientAddress, success, state, params:dict={}):
        """docstring"""

        uid = uuid.uuid1()
        logItem = {"RequestID" : uid,
                   "ClientAddress" : clientAddress,
                   "Success" : success,
                   "State" : state,
                   "Params" : params}

        self.RequestLog.append(logItem)

    def GetRequestItem(self, state):
        """docstring"""

        logItem = {}
        if self.RequestLog and len(self.RequestLog):
            logItem = [d for d in self.RequestLog if d["State"] == state][0]

        return logItem

    def service_actions(self):

        try:
            if not self.Serve:
                self.shutdown()
                self.server_close()
        except Exception as e:
            err = e
            raise e

        return super().service_actions()

    def handle_error(self, request, client_address):


        logItem = {"clientAddress" : client_address,
                   "success" : False,
                   "state" : None,
                   "params" : None}

        try:
            self.LogRequest(**logItem)
            x = request
        except Exception as e:
            self.shutdown()
            err = e
            raise e

        return super().handle_error(request, client_address)

因此,上面的服务器实现所做的是记录有关请求的信息ResquestLog:list,然后提供一种方法GetRequestItem,可用于拉取记录请求的存在。在测试中,我抛出错误并用handle_error()覆盖捕获它。这是启动服务器的调用函数,轮询请求,然后通过将其Server.Serve方法设置为关闭服务器False

def AwaitCallback(self, server_class=Server,
                     handler_class=OAuthGrantRequestHandler):
        """docstring"""

        server_address = ("127.0.0.1", 8080)
        self.Httpd = server_class(server_address, handler_class)
        self.Httpd.timeout = 200
        t1 = threading.Thread(target=self.Httpd.serve_forever)

        try:
            t1.start()

            #poll for request result
            result = {}
            x = 0
            while x < self.Timeout:
                if len(self.Httpd.RequestLog) > 0:
                    break
                time.sleep(.5)

        finally:
            #Terminate Server
            if self.Httpd:
                self.Httpd.Serve = False
            if t1:
                t1.join()
    return

上述方法坚持t1.join()通话。在对象挂起时检查self.Httpd对象告诉我服务器serve_forever()循环已关闭,但线程在调用时仍显示它处于活动状态t1.is_alive()。发生什么了?我唯一能想到的是,当self.shutdown()在 t1 线程中调用它时,它真的会产生循环而不是关闭它并保持胎面活着?关于关机的文档只是说shutdown() : Tell the serve_forever() loop to stop and wait until it does.很好而且很模糊。有任何想法吗?

编辑 1:如何在 BaseHTTPRequestHandler 子类中停止 BaseHTTPServer.serve_forever() 中 建议的答案?完全不同。他们建议用更简单的实现覆盖 socketserver.BaseServer.serve_forever() 循环的所有本机功能,而我正在尝试正确使用本机实现。到目前为止,据我所知,我上面的工作代码示例应该实现与答案所暗示的相同的事情,但子线程没有终止。于是这个问题。

标签: pythonpython-3.xmultithreadinghttpserver

解决方案


推荐阅读