Запуск веб-сервера Python как службы в Windows - PullRequest
6 голосов
/ 30 сентября 2008

У меня есть небольшое приложение веб-сервера, которое я написал на Python, которое получает и получает некоторые данные из системы баз данных и возвращает их пользователю в виде XML. Эта часть работает отлично - я могу запустить приложение веб-сервера Python из командной строки, и у меня могут быть клиенты, подключенные к нему и получающие данные обратно. На данный момент, чтобы запустить веб-сервер, я должен войти на наш сервер как пользователь с правами администратора и вручную запустить веб-сервер. Я хочу, чтобы веб-сервер автоматически запускался при запуске системы в качестве службы и работал в фоновом режиме.

Используя код с сайта ActiveState и StackOverflow , у меня есть довольно хорошее представление о том, как приступить к созданию службы, и я думаю, что этот бит отсортирован - Я могу установить и запустить свой веб-сервер в качестве службы Windows. Однако я не могу понять, как снова остановить службу. Мой веб-сервер создан из BaseHTTPServer:

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

Вызов serve_forever (), естественно, заставляет веб-сервер сидеть в бесконечном цикле и ожидать HTTP-соединений (или нажатия клавиши ctrl-break, не полезной для службы). Из приведенного выше примера кода я понял, что ваша функция main () должна находиться в бесконечном цикле и выходить из нее только тогда, когда она попадает в состояние «остановки». Мои основные вызовы serve_forever (). У меня есть функция SvcStop:

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

Который, кажется, вызывается, когда я делаю "остановку python myservice" из командной строки (я могу поместить туда строку отладки, которая производит вывод в файл), но фактически не завершает работу всей службы - последующие вызовы " Python myservice start "выдает ошибку:

Ошибка запуска службы: экземпляр служба уже запущена.

и последующие вызовы на остановку дают мне:

Ошибка остановки службы: служба не может принимать управляющие сообщения на этом время. (1061)

Я думаю, что мне нужна либо какая-то замена для serve_forever (serve_until_stop_received или что-то еще), либо мне нужен какой-то способ изменить SvcStop, чтобы он остановил весь сервис.

Вот полный список (я обрезал, включает / комментарии, чтобы сэкономить место):

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)

1 Ответ

3 голосов
/ 30 сентября 2008

Вот что я делаю:

Вместо непосредственного создания экземпляра класса BaseHTTPServer.HTTPServer я пишу из него нового потомка, который публикует метод "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

И затем, в методе SvcStop, который у вас уже есть, я вызываю этот метод, чтобы разорвать цикл serve_forever ():

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

(self.httpd является экземпляром AppHTTPServer (), который реализует веб-сервер)

Если вы правильно используете setDaemon () в фоновых потоках и правильно прерываете все циклы в сервисе, то инструкция

exit(0)

в SvcStop () не должно быть необходимо

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...