Using Python 3.7, Windows 10 Pro, Pywin32
I have a test script that starts a service and pushes some basic lines into a log file as the different commands are issued. Code is as follows:
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
import logging
class AppServerSvc(win32serviceutil.ServiceFramework):
_svc_name_ = "TestService"
_svc_display_name_ = "Test Service"
_svc_description_ = "New Test Service"
logging.basicConfig(filename='search_server.log', level=logging.INFO)
logging.info('Class opened')
def __init__(self, args):
logging.basicConfig(filename='search_server.log', level=logging.INFO)
logging.info('Init')
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
socket.setdefaulttimeout(60)
def SvcStop(self):
logging.basicConfig(filename='search_server.log', level=logging.INFO)
logging.info('Stop')
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
logging.basicConfig(filename='search_server.log', level=logging.INFO)
logging.info('Run')
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
self.main()
def main(self):
print("running")
logging.basicConfig(filename='search_server.log', level=logging.INFO)
logging.info('Main')
if __name__ == '__main__':
logging.basicConfig(filename='search_server.log', level=logging.INFO)
logging.info('Calling Handle Command Line')
win32serviceutil.HandleCommandLine(AppServerSvc)
I have gone through the basic trouble shooting with this, and the service is installing, starting, restarting and being removed without any errors. However I am expecting the log file to receive basic output to show the functions are being hit, and it isn't.
The calls I am making at the admin command prompt:
C:\PythonScripts\SearchServer>python servicetest.py install
Installing service TestService
Service installed
C:\PythonScripts\SearchServer>python servicetest.py start
Starting service TestService
C:\PythonScripts\SearchServer>python servicetest.py restart
Restarting service TestService
C:\PythonScripts\SearchServer>python servicetest.py remove
Removing service TestService
Service removed
C:\PythonScripts\SearchServer>
Contents of log file:
INFO:root:Class opened
INFO:root:Calling Handle Command Line
INFO:root:Class opened
INFO:root:Calling Handle Command Line
INFO:root:Class opened
INFO:root:Calling Handle Command Line
INFO:root:Class opened
INFO:root:Calling Handle Command Line
As you can see the service is being hit every time a command is issued, however I'd expect the internal functions to be called too. Being new to both services and Python I'm wondering if I've missed anything? I'm assuming the function names are predefined and don't need me to set up delegation to access them. Its not something I've seen in any of the questions I've come across.
I am of course assuming that these functions are supposed to be hit and they are being hit and are capable of creating logs?
Any help gratefully received.
There are a few problems with the code:
logging.basicConfig() should be called only once, if called again it won't have any effect.
Class definition will be called first in your code, even before block if __name__ == '__main__': because of natural flow of code. Due to this, whatever you set in logging.basicConfig() in class definition will become final for whole script. It is not an ideal place for this setting, so should be moved elsewhere (at the top, outside the class preferably).
filename parameter passed in the logging.basicConfig should be the absolute file path, because once service starts running, its current path won't be the same as the script, so logging won't be able to find out the log file. (current working directory for the service would become something like C:\Python37\lib\site-packages\win32).
(Optional): Try not to use root logging config at all, it's better to have an instance of logger for your own use.
After all these changes, the script will look like this:
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
import logging.handlers
log_file_path = "" # mention full path here
mylogger = logging.getLogger("TestLogger")
mylogger.setLevel(logging.INFO)
handler = logging.handlers.RotatingFileHandler(log_file_path)
mylogger.addHandler(handler)
class AppServerSvc(win32serviceutil.ServiceFramework):
_svc_name_ = "TestService"
_svc_display_name_ = "Test Service"
_svc_description_ = "New Test Service"
mylogger.info('Class opened')
def __init__(self, args):
mylogger.info('Init')
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
socket.setdefaulttimeout(60)
def SvcStop(self):
mylogger.info('Stop')
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
mylogger.info('Run')
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
self.main()
def main(self):
print("running")
mylogger.info('Main')
if __name__ == '__main__':
mylogger.info('Calling Handle Command Line')
win32serviceutil.HandleCommandLine(AppServerSvc)
Output:
Class opened
Init
Run
Main
Class opened
Calling Handle Command Line
I've had unexplainable problems with python logging, I solved them by setting up the logging right at the beginning of the program:
import logging
logging.basicConfig(filename='convert_st.log', level=logging.INFO)
logging.info('Started')
import all_other_packages
import...
...
def main:
# main comes here
...
if __name__ == '__main__':
main()
Related
I have created a test service file in pyhton:
import datetime
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
def writetofile():
DIR = "D:\prog\log.txt"
while True:
with open(DIR, 'a+') as file:
file.write(str(datetime.now()))
class AppServerSvc (win32serviceutil.ServiceFramework):
_svc_name_ = "TESTEST"
_svc_display_name_ = "TESTEST"
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):
writetofile()
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(AppServerSvc)
I've also installed it but when I want to start in win services it stops every time with 1053 error.
I have tried to overwrite the register file (ServicesPipeTimeout) not worked. I set it up 180000 and nothing. My program ran for a while then stopped again.
I've installed everthing in cmd as admin (pip install pywin32), not worked.
And I've installed the service too in cmd (python main.py install) and I see it, but thats all. I cant start it, cant delete it cant do anything with it.
I know this question was asked so many times. I read all those questions but i didn't find out my problem's solution. My issue is that i have created below window service with help of this link. How do you run a Python script as a service in Windows?
and I am running this service from command prompt.
Here is my python script that i need to run as a service.
import traceback
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
import getpass
import json
import pathlib
import urllib.request
import sys
from time import time , sleep
import uuid
from urllib.request import urlopen , Request
from urllib.parse import urlencode , quote_plus
import subprocess
import threading
import requests
from requests.sessions import session
import os
import cgitb
import logging
class PythonService(win32serviceutil.ServiceFramework):
_svc_name_ = "PCSIGN"
_svc_display_name_ = "PC SIGN"
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 ):
win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)
def main( ):
while True:
file = open ( 'geek.txt' , 'a+' )
file.write("hello world")
file.close()
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(PythonService)
PythonService.main()
As you can see in the main function there is an infinite loop in which I am opening a file and writing hello world in it.
I install & start my service from command prompt.
C:\wamp64\www\project\python\New folder>start /min python testing.py install
C:\wamp64\www\project\python\New folder>start /min python testing.py start
after that service installed and start working properly and another window appear.
It also makes an entry successfully in Services.
But the issue here is when i close the above window of python console it stop writing hello world in the file don't know why kindly how can i make it persistent so that whenever system restarted my script start working automatically and start writing hello world in the file
Just a few days back I have successfully sorted out my issue I just made some changes to my code and it started working properly. I am only posting these answers for someone like me who got this issue in the future he can easily sort it out.
This is the new code:
def WriteToFile():
while True:
file = open ( "C:\\file.txt" , "w" )
now = datetime.now()
now = now.strftime("%B %d, %y %H:%M:%S")
file.write(now)
class Pythonservice(win32serviceutil.ServiceFramework):
_svc_name_ = 'PC-Service'
_svc_display_name_ = 'PC-Service'
_svc_description_ = 'Freindly Service'
#classmethod
def parse_command_line(cls):
win32serviceutil.HandleCommandLine(cls)
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
socket.setdefaulttimeout(60)
def SvcStop(self):
self.stop()
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
self.start()
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
self.main()
def start(self):
self.isrunning = True
def stop(self):
self.isrunning = False
def main(self):
WriteToFile()
if __name__ == '__main__':
Pythonservice.parse_command_line()
After these changes, I opened up a command prompt as administrator and type this command to install my service.
C:\wamp64\www\project\python\New folder>python testing.py install
I got the success message. After successful installation, I started my service using this command
C:\wamp64\www\project\python\New folder>python testing.py start
and service started successfully I confirmed from service manager as well whether my service is running or not and it was running after restarting my pc service was still in running state.
Im pretty new to programming and Python and i have crated an API using FastAPI that i need to run on Windows, i want to run it as a service. The server will start and run fine, but when i try to stop it Windows throws an error and i think its because im not "stopping" uvicorn and i cant figure out how to. I've been googling and tried to run Uvicorn in a Daemon thread because i read that daemon threads will shutdown when the main thread exits, but that did not help either.
Im converting the app to exe using cx_Freeze. Could anyone point me in the right direction?
Im using this Template for cx_Freeze: https://github.com/marcelotduarte/cx_Freeze/tree/main/cx_Freeze/samples/service
Im on Windows 10, Python 3.9.1, Uvicorn 0.13.3, cx_Freeze 6.5
ServiceHandler.py
import os
import sys
import cx_Logging
import api
import logging
import threading
from uvicorn import Config, Server
logging.basicConfig(
filename = os.path.join(os.path.dirname(sys.executable), "log.txt"),
level = logging.DEBUG,
format = '[API] %(levelname)-7.7s %(message)s'
)
class Handler:
# no parameters are permitted; all configuration should be placed in the
# configuration file and handled in the initialize() method
def __init__(self):
self.stopEvent = threading.Event()
self.stopRequestedEvent = threading.Event()
# called when the service is starting
def initialize(self, configFileName):
self.directory = os.path.dirname(sys.executable)
cx_Logging.StartLogging(os.path.join(self.directory, "testing.log"), cx_Logging.DEBUG)
#pass
# called when the service is starting immediately after initialize()
# use this to perform the work of the service; don't forget to set or check
# for the stop event or the service GUI will not respond to requests to
# stop the service
def run(self):
cx_Logging.Debug("stdout=%r", sys.stdout)
sys.stdout = open(os.path.join(self.directory, "stdout.log"), "a")
sys.stderr = open(os.path.join(self.directory, "stderr.log"), "a")
self.main()
self.stopRequestedEvent.wait()
self.stopEvent.set()
# called when the service is being stopped by the service manager GUI
def stop(self):
try:
logging.debug("Stopping Service")
self.stopRequestedEvent.set()
self.stopEvent.wait()
# How to stop the server???
except Exception as e:
logging.error(e)
def main(self):
try:
self.config = Config(app=api.app, host="0.0.0.0", port=8004, reload=False)
self.app_server = Server(self.config)
self.app_server.install_signal_handlers = lambda: None # Need this line, or the server wont start
self.app_server.run()
except Exception as e:
logging.error(e)
setup.py
from cx_Freeze import setup, Executable
options = {
"build_exe": {
"packages": ["uvicorn", "fastapi", "pydantic", "threading"],
"includes": ["ServiceHandler", "cx_Logging", "ipaddress", "colorsys"],
"excludes": ["tkinter"],
}
}
executables = [
Executable(
"Config.py",
base="Win32Service",
target_name="api.exe",
)
]
setup(
name="TestService",
version="0.1",
description="Sample Windows serice",
executables=executables,
options=options,
)
I've also read this; https://github.com/encode/uvicorn/issues/742
But my knowledge is limited, so i dont quite understand how to implement it in my app?
So i got the service working.
Uvicorn/FastAPI will now start and stop as a Windows service, i dont know if there are any potential drawbacks, but here is the working code;
import os
import sys
import cx_Logging
import api
import logging
import threading
from uvicorn import Config, Server
logging.basicConfig(
filename = os.path.join(os.path.dirname(sys.executable), "log.txt"),
level = logging.DEBUG,
format = '[API] %(levelname)-7.7s %(message)s'
)
#My class for creating and running Uvicorn in a thread
class AppServer:
def __init__(self, app, host: str = "0.0.0.0", port: int = 8004, reload: bool = False):
self.config = Config(app=app, host=host, port=port, reload=reload)
self.server = Server(self.config)
self.server.install_signal_handlers = lambda: None # Need this line, or the server wont start
self.proc = None
def run(self):
self.server.run()
def start(self):
self.proc = threading.Thread(target=self.run, name="Test", args=())
self.proc.setDaemon(True)
self.proc.start()
def stop(self):
if self.proc:
self.proc.join(0.25)
class Handler:
# no parameters are permitted; all configuration should be placed in the
# configuration file and handled in the initialize() method
def __init__(self):
self.stopEvent = threading.Event()
self.stopRequestedEvent = threading.Event()
# called when the service is starting
def initialize(self, configFileName):
self.directory = os.path.dirname(sys.executable)
cx_Logging.StartLogging(os.path.join(self.directory, "testing.log"), cx_Logging.DEBUG)
#pass
# called when the service is starting immediately after initialize()
# use this to perform the work of the service; don't forget to set or check
# for the stop event or the service GUI will not respond to requests to
# stop the service
def run(self):
cx_Logging.Debug("stdout=%r", sys.stdout)
sys.stdout = open(os.path.join(self.directory, "stdout.log"), "a")
sys.stderr = open(os.path.join(self.directory, "stderr.log"), "a")
self.main()
self.stopRequestedEvent.wait()
self.stopEvent.set()
# called when the service is being stopped by the service manager GUI
def stop(self):
try:
logging.debug("Stopping Service")
self.server.stop()
self.stopRequestedEvent.set()
self.stopEvent.wait()
# How to stop the server???
except Exception as e:
logging.error(e)
def main(self):
try:
logging.debug("Starting server,,,")
self.server = AppServer(app=api.app)
self.server.start()
except Exception as e:
logging.error(e)
I got the answer here;
How to use FastAPI and uvicorn.run without blocking the thread?
If I try to do this it doesn't generate the warning:
Test.py install
Test.py start
Otherwise if I use pyinstaller:
pyinstaller -F --hidden-import=win32timezone Test.py
And then I try to do:
Test.exe install
Test.exe start
I see this warning in the event log:
A service process other than the one started by Service Control Manager connected when the TestService service started. Service Control Manager started process 5328 and connected process 1512.
Note that if the service is configured to start inside a debugger, this behavior is expected.
Script:
import servicemanager
import socket
import sys
import win32event
import win32service
import win32serviceutil
class TestService(win32serviceutil.ServiceFramework):
_svc_name_ = "TestService"
_svc_display_name_ = "Test Service"
_svc_description_ = "My service description"
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):
rc = None
while rc != win32event.WAIT_OBJECT_0:
with open('C:\\TestService.log', 'a') as f:
f.write('test service running...\n')
rc = win32event.WaitForSingleObject(self.hWaitStop, 5000)
if __name__ == '__main__':
if len(sys.argv) == 1:
servicemanager.Initialize()
servicemanager.PrepareToHostSingle(TestService)
servicemanager.StartServiceCtrlDispatcher()
else:
win32serviceutil.HandleCommandLine(TestService)
How can I start the service without this warning appearing?
This is only a warning of windows complaining that the service fired two process.
This is the normal behaviour of pyinstaller executables. You should ignore this kind of warning.
See the docs
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)