Running python script as windows service - python

I have this which runs a python script as windows service and its working perfectly, is there a way to separate it into 2 files: one which is the main script in which the work is done and calls the serviceframework file and the other is the serviceframework
I tried doing it but it doesn't seem to work for me, any help would be much appreciated
import time
import win32serviceutil # ServiceFramework and commandline helper
import win32service # Events
import servicemanager # Simple setup and logging
class MyService:
"""Silly little application stub"""
def stop(self):
"""Stop the service"""
self.running = False
def run(self):
"""Main service loop. This is where work is done!"""
self.running = True
while self.running:
time.sleep(10) # Important work
servicemanager.LogInfoMsg("Service running...")
class MyServiceFramework(win32serviceutil.ServiceFramework):
_svc_name_ = 'MyService'
_svc_display_name_ = 'My Service display name'
def SvcStop(self):
"""Stop the service"""
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
self.service_impl.stop()
self.ReportServiceStatus(win32service.SERVICE_STOPPED)
def SvcDoRun(self):
"""Start the service; does not return until stopped"""
self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
self.service_impl = MyService()
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
# Run the service
self.service_impl.run()
def init():
if len(sys.argv) == 1:
servicemanager.Initialize()
servicemanager.PrepareToHostSingle(MyServiceFramework)
servicemanager.StartServiceCtrlDispatcher()
else:
win32serviceutil.HandleCommandLine(MyServiceFramework)
if __name__ == '__main__':
init()

Related

Pass argument in shellscript after creating exe with pyinstaller

Below is my shellscript:
& 'C:\files\service_file.exe' install
#Start the windows service
& 'C:\file\service_file.exe' start --env "D:\full_project\device\config\windows.env"
I used pyinstaller to create service_file.exe and 'start' arg is working fine but does not support env path if included
I get path not found error, even after giving the env.
below is my service_file.py
import os
import win32serviceutil
import win32service
import servicemanager
import argparse
class MyService:
def stop(self):
self.running = False
def run(self):
application_path = os.path.dirname(sys.executable)
os.chdir(application_path)
def load_env(envFile):
global env_obj
env_obj = Environment(envFile)
return env_obj
parser = argparse.ArgumentParser(description="testing")
parser.add_argument("--env")
parser.add_argument("--log")
args = parser.parse_args()
env_obj = load_env(args.env)
db_agent(env_obj)
db_agent_download(env_obj)
client_agent(env_obj)
init_scheduler()
app = rest_api(env_obj)
app.run(port=env_obj.rest_api_port, host="0.0.0.0")
class MyServiceFramework(win32serviceutil.ServiceFramework):
_svc_name_ = 'DeviceAgent'
_svc_display_name_ = 'Device Agent Service'
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
self.service_impl.stop()
self.ReportServiceStatus(win32service.SERVICE_STOPPED)
def SvcDoRun(self):
self.service_impl = MyService()
self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
self.service_impl.run()
def Main():
if len(sys.argv) == 1:
print("this is if")
servicemanager.Initialize()
servicemanager.PrepareToHostSingle(MyServiceFramework)
servicemanager.StartServiceCtrlDispatcher()
else:
print("this is else",sys.argv)
win32serviceutil.HandleCommandLine(MyServiceFramework)
if __name__ == '__main__':
Main()
What should i do ? how can i run the shellscript along with env.
I want to know how i should pass the argument for env

How to exit cleanly from Flask and 'waitress' running as a Windows pywin32 service

I have managed to cobble together a working demo of a pywin32 Windows service running Flask inside the Pylons waitress WSGI server (below). A niece self contained solution is the idea...
I have spent hours reviewing and testing ways of making waitress exit cleanly (like this and this), but the best I can do so far is a kind of suicidal SIGINT which makes Windows complain "the pipe has been ended" when stopping through the Services control panel, but at least it stops :-/ I guess the pythonservice.exe which pywin32 starts, should not terminate, just the waitress treads?
To be honest I'm still uncertain if this is a question about waitress, pywin32, or maybe it's just plain Python. I do have the feeling the answer is right in front of me, but right now I'm completely stumped.
import os
import random
import signal
import socket
from flask import Flask, escape, request
import servicemanager
import win32event
import win32service
import win32serviceutil
from waitress import serve
app = Flask(__name__)
#app.route('/')
def hello():
random.seed()
x = random.randint(1, 1000000)
name = request.args.get("name", "World")
return 'Hello, %s! - %s - %s' % (escape(name), x, os.getpid())
# based on https://www.thepythoncorner.com/2018/08/how-to-create-a-windows-service-in-python/
class SMWinservice(win32serviceutil.ServiceFramework):
'''Base class to create winservice in Python'''
_svc_name_ = 'WaitressService'
_svc_display_name_ = 'Waitress server'
_svc_description_ = 'Python waitress WSGI service'
#classmethod
def parse_command_line(cls):
'''
ClassMethod to parse the command line
'''
win32serviceutil.HandleCommandLine(cls)
def __init__(self, args):
'''
Constructor of the winservice
'''
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
socket.setdefaulttimeout(60)
def SvcStop(self):
'''
Called when the service is asked to stop
'''
self.stop()
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STOPPED,
(self._svc_name_, ''))
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
'''
Called when the service is asked to start
'''
self.start()
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
self.main()
def start(self):
pass
def stop(self):
print 'sigint'
os.kill(os.getpid(), signal.SIGINT)
def main(self):
print 'serve'
serve(app, listen='*:5000')
if __name__ == '__main__':
SMWinservice.parse_command_line()
I have found a solution using a sub-thread that seems to work. I am not quite sure if this may have possible unintended consequences yet...
I believe the updated version below, "injecting" a SystemExit into the waitress thread is as good as it gets.
I think thee original kills the thread hard, but this one prints "thread done" indicating a graceful shutdown.
Corrections or improvements welcome!
import ctypes
import os
import random
import socket
import threading
from flask import Flask, escape, request
import servicemanager
import win32event
import win32service
import win32serviceutil
from waitress import serve
app = Flask(__name__)
# waitress thread exit based on:
# https://www.geeksforgeeks.org/python-different-ways-to-kill-a-thread/
#app.route('/')
def hello():
random.seed()
x = random.randint(1, 1000000)
name = request.args.get("name", "World")
return 'Hello, %s! - %s - %s' % (escape(name), x, os.getpid())
class ServerThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
print('thread start\n')
serve(app, listen='*:5000') # blocking
print('thread done\n')
def get_id(self):
# returns id of the respective thread
if hasattr(self, '_thread_id'):
return self._thread_id
for id, thread in threading._active.items():
if thread is self:
return id
def exit(self):
thread_id = self.get_id()
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, ctypes.py_object(SystemExit))
if res > 1:
ctypes.pythonapi.PyThreadState_SetAsyncExc(thread_id, 0)
print('Exception raise failure')
class SMWinservice(win32serviceutil.ServiceFramework):
_svc_name_ = 'WaitressService'
_svc_display_name_ = 'Waitress server'
_svc_description_ = 'Python waitress WSGI service'
#classmethod
def parse_command_line(cls):
win32serviceutil.HandleCommandLine(cls)
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.stopEvt = win32event.CreateEvent(None, 0, 0, None)
socket.setdefaulttimeout(60)
def SvcStop(self):
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STOPPED,
(self._svc_name_, ''))
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.stopEvt)
def SvcDoRun(self):
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
self.main()
def main(self):
print('main start')
self.server = ServerThread()
self.server.start()
print('waiting on win32event')
win32event.WaitForSingleObject(self.stopEvt, win32event.INFINITE)
self.server.exit() # raise SystemExit in inner thread
print('waiting on thread')
self.server.join()
print('main done')
if __name__ == '__main__':
SMWinservice.parse_command_line()

Error 1053: "The service did not respond in a timely fashion"

I'm trying to make windows service in python.
I have three source files: add_to_startup.py (adding my service to windows startup), run_as_a_service.py (runs my program as a service) and test.py (my program).
First i create .exe with pyinstaller:
pyinstaller -F --onefile --hidden-import=win32timezone run_as_a_service.py test.py add_to_startup.py
When i trying to start service error occurs:
Error 1053: The service did not respond in a timely fashion.
If i delete strings with test import and test.service() function, service works.
run_as_service.py:
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
import sys
import time
import test
class AppServerSvc (win32serviceutil.ServiceFramework):
_svc_name_ = "test"
_svc_display_name_ = "Test"
_svc_description_ = "test test"
def __init__(self,args):
win32serviceutil.ServiceFramework.__init__(self,args)
self.hWaitStop = win32event.CreateEvent(None,0,0,None)
socket.setdefaulttimeout(60)
def SvcStop(self):
self.isAlive = False
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
self.isAlive = True
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_,''))
self.main()
def main(self):
while self.isAlive:
test.service()
time.sleep(5)
if __name__ == '__main__':
if len(sys.argv) == 1:
servicemanager.Initialize()
servicemanager.PrepareToHostSingle(AppServerSvc)
servicemanager.StartServiceCtrlDispatcher()
else:
win32serviceutil.HandleCommandLine(AppServerSvc)
test.py:
import add_to_startup
def service():
print("Hello world")

Having several issues with a Python service for Windows

I've checked at least a couple of dozen of similar cases to mine and still haven't come up with a solution, I hope someone can shed some light, there's gotta be something I'm missing here.
I'm using Python3.6 to make a Windows service, the service has to run a .exe file if it's not running. Here's the .py:
import win32service
import win32serviceutil
import win32api
import win32con
import win32event
import win32evtlogutil
import psutil
import subprocess
import os, sys, string, time
import servicemanager
class SLAAgent (win32serviceutil.ServiceFramework):
_svc_name_ = "SLAAgent"
_svc_display_name_ = "SLAAgent"
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
socket.setdefaulttimeout(60)
self.isAlive = True
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
self.isAlive = False
def SvcDoRun(self):
self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,servicemanager.PYS_SERVICE_STARTED,(self._svc_name_, ''))
self._logger.info("Service Is Starting")
main(self)
def main(self):
while self.isAlive:
rc = win32event.WaitForSingleObject(self.hWaitStop, self.timeout)
# Check to see if self.hWaitStop happened
if rc == win32event.WAIT_OBJECT_0:
servicemanager.LogInfoMsg("SLAAService has stopped") #For Event Log
break
else:
try:
s = subprocess.check_output('tasklist', shell=True)
if "SLA_Client.exe" in s:
pass
else:
pass
#execfile("SLA_Client.exe") #Execute the script
except:
pass
if __name__ == '__main__':
if len(sys.argv) == 1:
servicemanager.Initialize()
servicemanager.PrepareToHostSingle(SLAAgent)
servicemanager.StartServiceCtrlDispatcher()
else:
win32serviceutil.HandleCommandLine(SLAAgent)
I've installed the pywin32 package, added those to the PATH since it was suggested in several solutions, and also copied the .dll from pywin32_system32 to win32
Environment variables
Event Viewer Error
The Event Viewer prints this error every time I run it be it python service.py, or python service.py start, console also prints this:
python SLA_Agent.py
Traceback (most recent call last):
File "SLA_Agent.py", line 56, in <module>
servicemanager.StartServiceCtrlDispatcher()
pywintypes.error: (1063, 'StartServiceCtrlDispatcher', 'The service process
could not connect to the service controller.')
When trying to start the service from the Services tool this is the error that pop ups. I've seen the other error too, the oneabout the service not responding in time.
I've tried compiling it with pyinstaller and nuitka, the errors are the same. I'm unsure as to how to proceed, I've changed the code to fit examples and solutions I've found using google and SO, and have gained little understanding of the hows and whys.
If anyone has faced these issues before, I'd really appreciate the input, other answers haven't helped me so far.
Late edit: fixed the code indentation
This ended up working for me, other than the difference in the code I didn't really do anything special, after a few tries I got to compile with pyinstaller and run service.exe install without issues. There are some extra logging lines that people might not need, but they came in handy when debugging and testing.
Thanks a lot to the everyone who left comments, they were extremely helpful and couldn't have done it without you <3
import win32service, win32serviceutil, win32api, win32con, win32event, win32evtlogutil
import psutil
import subprocess
import os, sys, string, time, socket, signal
import servicemanager
class Service (win32serviceutil.ServiceFramework):
_svc_name_ = "Service"
_svc_display_name_ = "Service"
def __init__(self,args):
win32serviceutil.ServiceFramework.__init__(self, *args)
self.log('Service Initialized.')
self.stop_event = win32event.CreateEvent(None, 0, 0, None)
socket.setdefaulttimeout(60)
def log(self, msg):
servicemanager.LogInfoMsg(str(msg))
def sleep(self, sec):
win32api.Sleep(sec*1000, True)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
self.stop()
self.log('Service has stopped.')
win32event.SetEvent(self.stop_event)
self.ReportServiceStatus(win32service.SERVICE_STOPPED)
def SvcDoRun(self):
self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
try:
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
self.log('Service is starting.')
self.main()
win32event.WaitForSingleObject(self.stop_event, win32event.INFINITE)
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,servicemanager.PYS_SERVICE_STARTED,(self._svc_name_, ''))
except Exception as e:
s = str(e);
self.log('Exception :'+s)
self.SvcStop()
def stop(self):
self.runflag=False
try:
#logic
except Exception as e:
self.log(str(e))
def main(self):
self.runflag=True
while self.runflag:
rc = win32event.WaitForSingleObject(self.stop_event, 24*60*60)
# Check to see if self.hWaitStop happened
if rc == win32event.WAIT_OBJECT_0:
self.log("Service has stopped")
break
else:
try:
#logic
except Exception as e:
self.log(str(e))
if __name__ == '__main__':
if len(sys.argv) == 1:
servicemanager.Initialize()
servicemanager.PrepareToHostSingle(Service)
servicemanager.StartServiceCtrlDispatcher()
else:
win32serviceutil.HandleCommandLine(Service)

Python multithreading service

I'm trying to create windows service on python with several threads.
I wrote the code that works as I need, but I can't understand how it breaks the threads!
Why break in while loop break the threads which are not in the while loop?
import win32serviceutil
import win32service
import win32event
import servicemanager
import threading
from classifier import clf, refit
class AppServerSvc (win32serviceutil.ServiceFramework):
_svc_name_ = "MyService"
_svc_display_name_ = "My Service"
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)
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):
t1 = threading.Thread(target=clf)
t2 = threading.Thread(target=refit)
t1.start()
t2.start()
while True:
rc = win32event.WaitForSingleObject(self.hWaitStop, 100)
if rc == win32event.WAIT_OBJECT_0:
break
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(AppServerSvc)
The service process terminates when SvcDoRun returns. That brings the threads down with the rest of the process. If you wish your threads to continue to execute then you must keep the process alive. In other words don't return from SvcDoRun.

Categories