Pregunta

Tengo una pequeña aplicación de servidor web que escribí en Python que va y obtiene algunos datos de un sistema de base de datos y los devuelve al usuario como XML. Esa parte funciona bien: puedo ejecutar la aplicación del servidor web de Python desde la línea de comandos y puedo hacer que los clientes se conecten a ella y obtengan datos. En este momento, para ejecutar el servidor web, tengo que iniciar sesión en nuestro servidor como usuario administrador y tengo que iniciar manualmente el servidor web. Quiero que el servidor web se inicie automáticamente cuando el sistema se inicie como un servicio y se ejecute en segundo plano.

Utilizando el código del sitio ActiveState y StackOverflow , tengo una muy buena idea de cómo ir sobre la creación de un servicio, y creo que ya lo he ordenado, puedo instalar e iniciar mi servidor web como un servicio de Windows. Sin embargo, no puedo averiguar cómo detener el servicio nuevamente. Mi servidor web se crea a partir de un servidor BaseHTTPS:

server = BaseHTTPServer.HTTPServer(('', 8081), SIMSAPIServerHandler)
server.serve_forever()

La llamada serve_forever (), como es lógico, hace que el servidor web se sitúe en un bucle infinito y espere las conexiones HTTP (o una pulsación de tecla ctrl-break, no útil para un servicio). Me da la idea del código de ejemplo anterior de que se supone que su función main () se encuentra en un bucle infinito y solo se sale de ella cuando se encuentra con un " parada " condición. Mis principales llamadas serve_forever (). Tengo una función SvcStop:

def SvcStop(self):
    self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
    exit(0)

Lo que parece ser llamado cuando hago " python myservice stop " desde la línea de comandos (puedo poner una línea de depuración allí que produce resultados en un archivo) pero en realidad no sale de todo el servicio: las llamadas subsiguientes a " python myservice start " me da un error:

  

Error al iniciar el servicio: una instancia de   el servicio ya se está ejecutando.

y las siguientes llamadas a parar me dan:

  

Error al detener el servicio: el servicio   no puede aceptar mensajes de control en este   hora. (1061)

Creo que necesito algún reemplazo para serve_forever (serve_until_stop_received, o lo que sea) o necesito alguna forma de modificar SvcStop para que detenga todo el servicio.

Aquí hay una lista completa (he recortado incluye / comentarios para ahorrar espacio):

class SIMSAPIServerHandler(BaseHTTPServer.BaseHTTPRequestHandler):
    def do_GET(self):
        try:
            reportTuple = self.path.partition("/")
            if len(reportTuple) < 3:
                return
            if reportTuple[2] == "":
                return
            os.system("C:\\Programs\\SIMSAPI\\runCommandReporter.bat " + reportTuple[2])
            f = open("C:\\Programs\\SIMSAPI\\out.xml", "rb")
            self.send_response(200)
            self.send_header('Content-type', "application/xml")
            self.end_headers()
            self.wfile.write(f.read())
            f.close()
            # The output from CommandReporter is simply dumped to out.xml, which we read, write to the user, then remove.
            os.unlink("C:\\Programs\\SIMSAPI\\out.xml")
            return
        except IOError:
            self.send_error(404,'File Not Found: %s' % self.path)



class SIMSAPI(win32serviceutil.ServiceFramework):
    _svc_name_ = "SIMSAPI"
    _svc_display_name_ = "A simple web server"
    _svc_description_ = "Serves XML data produced by SIMS CommandReporter"

    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)           

    def SvcStop(self):
            self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
            exit(0)

    def SvcDoRun(self):
        import servicemanager
        servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,servicemanager.PYS_SERVICE_STARTED,(self._svc_name_, '')) 

        self.timeout = 3000

        while 1:
            server = BaseHTTPServer.HTTPServer(('', 8081), SIMSAPIServerHandler)
            server.serve_forever()

def ctrlHandler(ctrlType):
    return True

if __name__ == '__main__':
    win32api.SetConsoleCtrlHandler(ctrlHandler, True)
    win32serviceutil.HandleCommandLine(SIMSAPI)
¿Fue útil?

Solución

Esto es lo que hago:

En lugar de crear una instancia directa de la clase BaseHTTPServer.HTTPServer, escribo un nuevo descendiente de la misma que publica un " parada " método:

class AppHTTPServer (SocketServer.ThreadingMixIn, BaseHTTPServer.HTTPServer):
    def serve_forever(self):
        self.stop_serving = False
        while not self.stop_serving:
            self.handle_request()

    def stop (self):
        self.stop_serving = True

Y luego, en el método SvcStop que ya tienes, llamo a ese método para interrumpir el ciclo serve_forever ():

def SvcStop(self):
    self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
    self.httpd.stop()

(self.httpd es la instancia de AppHTTPServer () que implementa el servidor web)

Si usa setDaemon () correctamente en los subprocesos de fondo e interrumpe correctamente todos los bucles en el servicio, entonces la instrucción

exit(0)

en SvcStop () no debería ser necesario

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top