Pergunta

Eu tenho um aplicativo de servidor web pequeno eu tenho escrito em Python que vai e pega alguns dados de um sistema de banco de dados e retorna para o usuário como XML. Essa parte funciona bem - eu possa executar o aplicativo de servidor web Python na linha de comando e eu posso ter clientes se conectar a ele e voltar dados. No momento, para executar o servidor web que eu tenho que estar conectado ao nosso servidor como o usuário administrador e eu tenho que iniciar manualmente o servidor web. Quero ter o servidor web iniciar automaticamente no início do sistema como um serviço e executado em segundo plano.

Usando o código de ActiveState 's local e StackOverflow , eu tenho uma boa idéia de como ir sobre a criação de um serviço, e eu acho que eu tenho que pouco classificadas - Eu posso instalar e iniciar meu servidor web como um serviço Windows. Não posso, no entanto, descobrir como parar o serviço novamente. Meu servidor web é criada a partir de uma BaseHTTPServer:

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

A chamada serve_forever (), naturalmente, faz com que o sit servidor web em um loop infinito e espera para conexões HTTP (ou uma tecla ctrl-break, não é útil para um serviço). Recebo a idéia do código de exemplo acima que a sua função main () é suposto para se sentar em um loop infinito e só sair dela quando se trata accross uma condição "stop". Meu principal chamadas serve_forever (). Eu tenho uma função SvcStop:

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

O que parece ser pago quando eu faço "parada python myservice" na linha de comando (eu posso colocar uma linha de depuração lá dentro que produz saída para um arquivo), mas na verdade não sair todo o serviço - chamadas subsequentes para " python myservice início" me dá um erro:

Erro de serviço de início: Uma instância de o serviço já está em execução.

e chamadas subsequentes para parada me dá:

Erro de serviço parar: O serviço não pode aceitar mensagens de controle neste Tempo. (1061)

Eu acho que preciso tanto algum substituto para serve_forever (serve_until_stop_received, ou qualquer outro) ou eu preciso de alguma forma de modificar SvcStop assim que pára todo o serviço.

Aqui está uma lista completa (eu aparado inclui / comentários para economizar espaço):

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)
Foi útil?

Solução

Isto é o que eu faço:

Em vez de instanciação diretamente o BaseHTTPServer.HTTPServer classe, eu escrever um novo descendente a partir dele que publica um método "stop":

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

E, em seguida, na SvcStop método que você já tem, eu chamar esse método para quebrar o ciclo serve_forever ():

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

(self.httpd é o exemplo de AppHTTPServer () que implementa o servidor web)

Se você usar setDaemon () corretamente sobre os tópicos de fundo, e interromper corretamente todos os loops no serviço, então a instrução

exit(0)

em SvcStop () não deve ser necessário

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top