У меня есть небольшая реализация 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()
.Так, что происходит?Единственное, о чем я могу думать, это то, что когда в потоке t1 вызывается self.shutdown()
, это действительно приводит к циклу, а не к его выключению и поддерживает протектор?Документация по отключению просто говорит shutdown() : Tell the serve_forever() loop to stop and wait until it does.
Красиво и мрачно.Есть идеи?
Редактировать 1: ответ, предложенный на Как остановить BaseHTTPServer.serve_forever () в подклассе BaseHTTPRequestHandler? совсем другое.Они предлагают переопределить всю встроенную функциональность цикла socketserver.BaseServer.serve_forever () с более простой реализацией, тогда как я пытаюсь правильно использовать встроенную реализацию.Насколько я понимаю, пример моего рабочего кода выше должен достичь того же, что предлагает ответ, но дочерний поток не завершается.Таким образом, этот вопрос.