Question

I'm using the template found here: Is it possible to run a Python script as a service in Windows? If possible, how?

Here's my run.py, which i've installed as a service following the instructions in the above link.

from app import app

import win32serviceutil
import win32service
import win32event
import servicemanager
import socket


class AppServerSvc (win32serviceutil.ServiceFramework):
    _svc_name_ = "Flask App"
    _svc_display_name_ = "Flask App"

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

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)

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

    def main(self):
        app.run(host = '192.168.1.6')

if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(AppServerSvc)

However, when I try to start the service i get the message:

"The Flask App service on Local Computer started and then stopped. Some services stop automatically if they are not in use by other services or programs."

Any idea what I'm doing wrong? I have tried various user accounts--i don't think it's a permission problem.

Thanks!

Was it helpful?

Solution

I can't access WSGIRequestHandler in Flask outside request, so I use Process.

import win32serviceutil
import win32service
import win32event
import servicemanager
from multiprocessing import Process

from app import app


class Service(win32serviceutil.ServiceFramework):
    _svc_name_ = "TestService"
    _svc_display_name_ = "Test Service"
    _svc_description_ = "Tests Python service framework by receiving and echoing messages over a named pipe"

    def __init__(self, *args):
        super().__init__(*args)

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        self.process.terminate()
        self.ReportServiceStatus(win32service.SERVICE_STOPPED)

    def SvcDoRun(self):
        self.process = Process(target=self.main)
        self.process.start()
        self.process.run()

    def main(self):
        app.run()


if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(Service)

OTHER TIPS

Figured it out--I'd left the debug option on in the app.run(). Once i removed that, it's good to go!

While the service starts and runs correctly (I can access my flask app from another computer on the network), it is unable to stop. In the thread with the posted template i used, the author mentions something about setting a flag to properly stop the service.

Anyone know what he means by this and how to code it to properly stop the service?

Flask is not suitable for serving. Please check flask docs out.

Flask application object is the actual WSGI application

So, we need a WSGI container to serve. It is simple to implement Flask windows service with gevent in the code level. e.g.

# app.py
from flask import Flask

app = Flask(__name__)


@app.route('/')
def hello():
    return 'hello world'
# server.py
import win32serviceutil
from gevent.pywsgi import WSGIServer

from app import app


class Service(win32serviceutil.ServiceFramework):
    _svc_name_ = "flask_gevent_service_test"
    _svc_display_name_ = "flask gevent service test display name"
    _svc_description_ = "flask gevent service test description"

    def __init__(self, *args):
        super().__init__(*args)
        self.http_server = WSGIServer(('127.0.0.1', 9854), app)

        self.SvcStop = self.http_server.stop
        self.SvcDoRun = self.http_server.serve_forever


if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(Service)

I appended my code in SvcStop() last line. "self.ReportServiceStatus(win32service.SERVICE_STOPPED)"

In my case, It's works for stopping service.

from app import app

import win32serviceutil
import win32service
import win32event
import servicemanager
import socket


class AppServerSvc (win32serviceutil.ServiceFramework):
    _svc_name_ = "Flask App"
    _svc_display_name_ = "Flask App"

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

    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)
        # !important! to report "SERVICE_STOPPED"
        self.ReportServiceStatus(win32service.SERVICE_STOPPED)

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

    def main(self):
        app.run(host = '192.168.1.6')

if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(AppServerSvc)
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top