Running Python web server as a service on Windows

I have a small web server application written in Python that goes and gets some data from a database system and returns it to the user as XML. This part works fine - I can start the Python web server application from the command line, and I can connect clients to it and return the data. At the moment, to start the web server I must be registered on our server as an administrator user, and I need to manually start the web server. I want the web server to start automatically when the system starts as a service and run in the background.

Using the ActiveState code and https://stackoverflow.com/a/3/21211/ ... , I have a good idea on how to start creating a service, and I think I have this bit sorted - I can install and run my web server as Windows services. However, I cannot figure out how to stop the service again. My web server is created with BaseHTTPServer:

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

Calling serve_forever () naturally makes the web server sit in an endless loop and wait for HTTP connections (or ctrl-break keys not useful for the service). I get the idea from the above code example that your main () function should sit in an infinite loop and only exit it when it comes to the “stop condition”. My main calls to serve_forever (). I have a SvcStop function:

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

It seems to be called when I start the "python myservice stop" from the command line (I can put a debug line there that outputs the output to a file), but actually does not exit the whole service - subsequent calls to the "python myservice start" give me an error :

Startup error: The service instance is already running.

and subsequent stop calls give me:

Error Stop Service: The service cannot receive control messages at this time. (1061)

It seems to me that I need some kind of replacement for serve_forever (serve_until_stop_received or something else), or I need some way to change SvcStop so that it stops the whole service.

Here's the full list (I clipped includes / comments to save space):

 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) 
+6
python windows webserver
source share
1 answer

This is what I do:

Instead of directly running the BaseHTTPServer.HTTPServer class, I am writing a new descendant from it that publishes the "stop" method:

 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 

And then, in the SvcStop method that you already have, I call this method to break the serve_forever () loop:

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

(self.httpd is an instance of AppHTTPServer () that implements the web server)

If you use setDaemon () in background threads correctly and terminate all loops in the service correctly, then the instruction

 exit(0) 

in SvcStop () is not required

+3
source share

All Articles