I am sketching the architecture for a set of programs that share various interrelated objects stored in a database. I want one of the programs to act as a service which provides a higher level interface for operations on these objects, and the other programs to access the objects through that service.
I am currently aiming for Python and the Django framework as the technologies to implement that service with. I'm pretty sure I figure how to daemonize the Python program in Linux. However, it is an optional spec item that the system should support Windows. I have little experience with Windows programming and no experience at all with Windows services.
Is it possible to run a Python programs as a Windows service (i. e. run it automatically without user login)? I won't necessarily have to implement this part, but I need a rough idea how it would be done in order to decide whether to design along these lines.
Edit: Thanks for all the answers so far, they are quite comprehensive. I would like to know one more thing: How is Windows aware of my service? Can I manage it with the native Windows utilities? What is the equivalent of putting a start/stop script in /etc/init.d?
Yes you can. I do it using the pythoncom libraries that come included with ActivePython or can be installed with pywin32 (Python for Windows extensions).
This is a basic skeleton for a simple service:
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
class AppServerSvc (win32serviceutil.ServiceFramework):
_svc_name_ = "TestService"
_svc_display_name_ = "Test Service"
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):
pass
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(AppServerSvc)
Your code would go in the main() method—usually with some kind of infinite loop that might be interrupted by checking a flag, which you set in the SvcStop method
The simplest way is to use the: NSSM - the Non-Sucking Service Manager. Just download and unzip to a location of your choosing. It's a self-contained utility, around 300KB (much less than installing the entire pywin32 suite just for this purpose) and no "installation" is needed. The zip contains a 64-bit and a 32-bit version of the utility. Either should work well on current systems (you can use the 32-bit version to manage services on 64-bit systems).
GUI approach
1 - install the python program as a service. Open a Win prompt as admin
c:\>nssm.exe install WinService
2 - On NSSM´s GUI console:
path: C:\Python27\Python27.exe
Startup directory: C:\Python27
Arguments: c:\WinService.py
3 - check the created services on services.msc
Scripting approach (no GUI)
This is handy if your service should be part of an automated, non-interactive procedure, that may be beyond your control, such as a batch or installer script. It is assumed that the commands are executed with administrative privileges.
For convenience the commands are described here by simply referring to the utility as nssm.exe. It is advisable, however, to refer to it more explicitly in scripting with its full path c:\path\to\nssm.exe, since it's a self-contained executable that may be located in a private path that the system is not aware of.
1. Install the service
You must specify a name for the service, the path to the proper Python executable, and the path to the script:
nssm.exe install ProjectService "c:\path\to\python.exe" "c:\path\to\project\app\main.py"
More explicitly:
nssm.exe install ProjectService
nssm.exe set ProjectService Application "c:\path\to\python.exe"
nssm.exe set ProjectService AppParameters "c:\path\to\project\app\main.py"
Alternatively you may want your Python app to be started as a Python module. One easy approach is to tell nssm that it needs to change to the proper starting directory, as you would do yourself when launching from a command shell:
nssm.exe install ProjectService "c:\path\to\python.exe" "-m app.main"
nssm.exe set ProjectService AppDirectory "c:\path\to\project"
This approach works well with virtual environments and self-contained (embedded) Python installs. Just make sure to have properly resolved any path issues in those environments with the usual methods. nssm has a way to set environment variables (e.g. PYTHONPATH) if needed, and can also launch batch scripts.
2. To start the service
nssm.exe start ProjectService
3. To stop the service
nssm.exe stop ProjectService
4. To remove the service, specify the confirm parameter to skip the interactive confirmation.
nssm.exe remove ProjectService confirm
Although I upvoted the chosen answer a couple of weeks back, in the meantime I struggled a lot more with this topic. It feels like having a special Python installation and using special modules to run a script as a service is simply the wrong way. What about portability and such?
I stumbled across the wonderful Non-sucking Service Manager, which made it really simple and sane to deal with Windows Services. I figured since I could pass options to an installed service, I could just as well select my Python executable and pass my script as an option.
I have not yet tried this solution, but I will do so right now and update this post along the process. I am also interested in using virtualenvs on Windows, so I might come up with a tutorial sooner or later and link to it here.
The simplest way to achieve this is to use native command sc.exe:
sc create PythonApp binPath= "C:\Python34\Python.exe --C:\tmp\pythonscript.py"
References:
https://technet.microsoft.com/en-us/library/cc990289(v=ws.11).aspx
When creating a service with sc.exe how to pass in context parameters?
There are a couple alternatives for installing as a service virtually any Windows executable.
Method 1: Use instsrv and srvany from rktools.exe
For Windows Home Server or Windows Server 2003 (works with WinXP too), the Windows Server 2003 Resource Kit Tools comes with utilities that can be used in tandem for this, called instsrv.exe and srvany.exe. See this Microsoft KB article KB137890 for details on how to use these utils.
For Windows Home Server, there is a great user friendly wrapper for these utilities named aptly "Any Service Installer".
Method 2: Use ServiceInstaller for Windows NT
There is another alternative using ServiceInstaller for Windows NT (download-able here) with python instructions available. Contrary to the name, it works with both Windows 2000 and Windows XP as well. Here are some instructions for how to install a python script as a service.
Installing a Python script
Run ServiceInstaller to create a new
service. (In this example, it is
assumed that python is installed at
c:\python25)
Service Name : PythonTest
Display Name : PythonTest
Startup : Manual (or whatever you like)
Dependencies : (Leave blank or fill to fit your needs)
Executable : c:\python25\python.exe
Arguments : c:\path_to_your_python_script\test.py
Working Directory : c:\path_to_your_python_script
After installing, open the Control
Panel's Services applet, select and
start the PythonTest service.
After my initial answer, I noticed there were closely related Q&A already posted on SO. See also:
Can I run a Python script as a service (in Windows)? How?
How do I make Windows aware of a service I have written in Python?
Step by step explanation how to make it work :
1- First create a python file according to the basic skeleton mentioned above. And save it to a path for example : "c:\PythonFiles\AppServerSvc.py"
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
class AppServerSvc (win32serviceutil.ServiceFramework):
_svc_name_ = "TestService"
_svc_display_name_ = "Test Service"
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):
# Your business logic or call to any class should be here
# this time it creates a text.txt and writes Test Service in a daily manner
f = open('C:\\test.txt', 'a')
rc = None
while rc != win32event.WAIT_OBJECT_0:
f.write('Test Service \n')
f.flush()
# block for 24*60*60 seconds and wait for a stop event
# it is used for a one-day loop
rc = win32event.WaitForSingleObject(self.hWaitStop, 24 * 60 * 60 * 1000)
f.write('shut down \n')
f.close()
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(AppServerSvc)
2 - On this step we should register our service.
Run command prompt as administrator and type as:
sc create TestService binpath= "C:\Python36\Python.exe c:\PythonFiles\AppServerSvc.py" DisplayName= "TestService" start= auto
the first argument of binpath is the path of python.exe
second argument of binpath is the path of your python file that we created already
Don't miss that you should put one space after every "=" sign.
Then if everything is ok, you should see
[SC] CreateService SUCCESS
Now your python service is installed as windows service now. You can see it in Service Manager and registry under :
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TestService
3- Ok now. You can start your service on service manager.
You can execute every python file that provides this service skeleton.
pysc: Service Control Manager on Python
Example script to run as a service taken from pythonhosted.org:
from xmlrpc.server import SimpleXMLRPCServer
from pysc import event_stop
class TestServer:
def echo(self, msg):
return msg
if __name__ == '__main__':
server = SimpleXMLRPCServer(('127.0.0.1', 9001))
#event_stop
def stop():
server.server_close()
server.register_instance(TestServer())
server.serve_forever()
Create and start service
import os
import sys
from xmlrpc.client import ServerProxy
import pysc
if __name__ == '__main__':
service_name = 'test_xmlrpc_server'
script_path = os.path.join(
os.path.dirname(__file__), 'xmlrpc_server.py'
)
pysc.create(
service_name=service_name,
cmd=[sys.executable, script_path]
)
pysc.start(service_name)
client = ServerProxy('http://127.0.0.1:9001')
print(client.echo('test scm'))
Stop and delete service
import pysc
service_name = 'test_xmlrpc_server'
pysc.stop(service_name)
pysc.delete(service_name)
pip install pysc
nssm in python 3+
(I converted my .py file to .exe with pyinstaller)
nssm:
as said before
run nssm install {ServiceName}
On NSSM´s console:
path: path\to\your\program.exe
Startup directory: path\to\your\ #same as the path but without your program.exe
Arguments: empty
If you don't want to convert your project to .exe
create a .bat file with python {{your python.py file name}}
and set the path to the .bat file
I started hosting as a service with pywin32.
Everything was well but I met the problem that service was not able to start within 30 seconds (default timeout for Windows) on system startup. It was critical for me because Windows startup took place simultaneous on several virtual machines hosted on one physical machine, and IO load was huge.
Error messages were:
Error 1053: The service did not respond to the start or control request in a timely fashion.
Error 7009: Timeout (30000 milliseconds) waiting for the <ServiceName> service to connect.
I fought a lot with pywin, but ended up with using NSSM as it was proposed in this answer. It was very easy to migrate to it.
A complete pywin32 example using loop or subthread
After working on this on and off for a few days, here is the answer I would have wished to find, using pywin32 to keep it nice and self contained.
This is complete working code for one loop-based and one thread-based solution.
It may work on both python 2 and 3, although I've only tested the latest version on 2.7 and Win7. The loop should be good for polling code, and the tread should work with more server-like code. It seems to work nicely with the waitress wsgi server that does not have a standard way to shut down gracefully.
I would also like to note that there seems to be loads of examples out there, like this that are almost useful, but in reality misleading, because they have cut and pasted other examples blindly. I could be wrong. but why create an event if you never wait for it?
That said I still feel I'm on somewhat shaky ground here, especially with regards to how clean the exit from the thread version is, but at least I believe there are nothing misleading here.
To run simply copy the code to a file and follow the instructions.
update:
Use a simple flag to terminate thread. The important bit is that "thread done" prints.
For a more elaborate example exiting from an uncooperative server thread see my post about the waitress wsgi server.
# uncomment mainthread() or mainloop() call below
# run without parameters to see HandleCommandLine options
# install service with "install" and remove with "remove"
# run with "debug" to see print statements
# with "start" and "stop" watch for files to appear
# check Windows EventViever for log messages
import socket
import sys
import threading
import time
from random import randint
from os import path
import servicemanager
import win32event
import win32service
import win32serviceutil
# see http://timgolden.me.uk/pywin32-docs/contents.html for details
def dummytask_once(msg='once'):
fn = path.join(path.dirname(__file__),
'%s_%s.txt' % (msg, randint(1, 10000)))
with open(fn, 'w') as fh:
print(fn)
fh.write('')
def dummytask_loop():
global do_run
while do_run:
dummytask_once(msg='loop')
time.sleep(3)
class MyThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global do_run
do_run = True
print('thread start\n')
dummytask_loop()
print('thread done\n')
def exit(self):
global do_run
do_run = False
class SMWinservice(win32serviceutil.ServiceFramework):
_svc_name_ = 'PyWinSvc'
_svc_display_name_ = 'Python Windows Service'
_svc_description_ = 'An example of a windows service in Python'
#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) # create generic event
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) # raise event
def SvcDoRun(self):
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
# UNCOMMENT ONE OF THESE
# self.mainthread()
# self.mainloop()
# Wait for stopEvt indefinitely after starting thread.
def mainthread(self):
print('main start')
self.server = MyThread()
self.server.start()
print('wait for win32event')
win32event.WaitForSingleObject(self.stopEvt, win32event.INFINITE)
self.server.exit()
print('wait for thread')
self.server.join()
print('main done')
# Wait for stopEvt event in loop.
def mainloop(self):
print('loop start')
rc = None
while rc != win32event.WAIT_OBJECT_0:
dummytask_once()
rc = win32event.WaitForSingleObject(self.stopEvt, 3000)
print('loop done')
if __name__ == '__main__':
SMWinservice.parse_command_line()
This answer is plagiarizer from several sources on StackOverflow - most of them above, but I've forgotten the others - sorry. It's simple and scripts run "as is". For releases you test you script, then copy it to the server and Stop/Start the associated service. And it should work for all scripting languages (Python, Perl, node.js), plus batch scripts such as GitBash, PowerShell, even old DOS bat scripts.
pyGlue is the glue that sits between Windows Services and your script.
'''
A script to create a Windows Service, which, when started, will run an executable with the specified parameters.
Optionally, you can also specify a startup directory
To use this script you MUST define (in class Service)
1. A name for your service (short - preferably no spaces)
2. A display name for your service (the name visibile in Windows Services)
3. A description for your service (long details visible when you inspect the service in Windows Services)
4. The full path of the executable (usually C:/Python38/python.exe or C:WINDOWS/System32/WindowsPowerShell/v1.0/powershell.exe
5. The script which Python or PowerShell will run(or specify None if your executable is standalone - in which case you don't need pyGlue)
6. The startup directory (or specify None)
7. Any parameters for your script (or for your executable if you have no script)
NOTE: This does not make a portable script.
The associated '_svc_name.exe' in the dist folder will only work if the executable,
(and any optional startup directory) actually exist in those locations on the target system
Usage: 'pyGlue.exe [options] install|update|remove|start [...]|stop|restart [...]|debug [...]'
Options for 'install' and 'update' commands only:
--username domain\\username : The Username the service is to run under
--password password : The password for the username
--startup [manual|auto|disabled|delayed] : How the service starts, default = manual
--interactive : Allow the service to interact with the desktop.
--perfmonini file: .ini file to use for registering performance monitor data
--perfmondll file: .dll file to use when querying the service for performance data, default = perfmondata.dll
Options for 'start' and 'stop' commands only:
--wait seconds: Wait for the service to actually start or stop.
If you specify --wait with the 'stop' option, the service and all dependent services will be stopped,
each waiting the specified period.
'''
# Import all the modules that make life easy
import servicemanager
import socket
import sys
import win32event
import win32service
import win32serviceutil
import win32evtlogutil
import os
from logging import Formatter, Handler
import logging
import subprocess
# Define the win32api class
class Service (win32serviceutil.ServiceFramework):
# The following variable are edited by the build.sh script
_svc_name_ = "TestService"
_svc_display_name_ = "Test Service"
_svc_description_ = "Test Running Python Scripts as a Service"
service_exe = 'c:/Python27/python.exe'
service_script = None
service_params = []
service_startDir = None
# Initialize the service
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
self.configure_logging()
socket.setdefaulttimeout(60)
# Configure logging to the WINDOWS Event logs
def configure_logging(self):
self.formatter = Formatter('%(message)s')
self.handler = logHandler()
self.handler.setFormatter(self.formatter)
self.logger = logging.getLogger()
self.logger.addHandler(self.handler)
self.logger.setLevel(logging.INFO)
# Stop the service
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
# Run the service
def SvcDoRun(self):
self.main()
# This is the service
def main(self):
# Log that we are starting
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
# Fire off the real process that does the real work
logging.info('%s - about to call Popen() to run %s %s %s', self._svc_name_, self.service_exe, self.service_script, self.service_params)
self.process = subprocess.Popen([self.service_exe, self.service_script] + self.service_params, shell=False, cwd=self.service_startDir)
logging.info('%s - started process %d', self._svc_name_, self.process.pid)
# Wait until WINDOWS kills us - retrigger the wait for stop every 60 seconds
rc = None
while rc != win32event.WAIT_OBJECT_0:
rc = win32event.WaitForSingleObject(self.hWaitStop, (1 * 60 * 1000))
# Shut down the real process and exit
logging.info('%s - is terminating process %d', self._svc_name_, self.process.pid)
self.process.terminate()
logging.info('%s - is exiting', self._svc_name_)
class logHandler(Handler):
'''
Emit a log record to the WINDOWS Event log
'''
def emit(self, record):
servicemanager.LogInfoMsg(record.getMessage())
# The main code
if __name__ == '__main__':
'''
Create a Windows Service, which, when started, will run an executable with the specified parameters.
'''
# Check that configuration contains valid values just in case this service has accidentally
# been moved to a server where things are in different places
if not os.path.isfile(Service.service_exe):
print('Executable file({!s}) does not exist'.format(Service.service_exe), file=sys.stderr)
sys.exit(0)
if not os.access(Service.service_exe, os.X_OK):
print('Executable file({!s}) is not executable'.format(Service.service_exe), file=sys.stderr)
sys.exit(0)
# Check that any optional startup directory exists
if (Service.service_startDir is not None) and (not os.path.isdir(Service.service_startDir)):
print('Start up directory({!s}) does not exist'.format(Service.service_startDir), file=sys.stderr)
sys.exit(0)
if len(sys.argv) == 1:
servicemanager.Initialize()
servicemanager.PrepareToHostSingle(Service)
servicemanager.StartServiceCtrlDispatcher()
else:
# install/update/remove/start/stop/restart or debug the service
# One of those command line options must be specified
win32serviceutil.HandleCommandLine(Service)
Now there's a bit of editing and you don't want all your services called 'pyGlue'. So there's a script (build.sh) to plug in the bits and create a customized 'pyGlue' and create an '.exe'. It is this '.exe' which gets installed as a Windows Service. Once installed you can set it to run automatically.
#!/bin/sh
# This script build a Windows Service that will install/start/stop/remove a service that runs a script
# That is, executes Python to run a Python script, or PowerShell to run a PowerShell script, etc
if [ $# -lt 6 ]; then
echo "Usage: build.sh Name Display Description Executable Script StartupDir [Params]..."
exit 0
fi
name=$1
display=$2
desc=$3
exe=$4
script=$5
startDir=$6
shift; shift; shift; shift; shift; shift
params=
while [ $# -gt 0 ]; do
if [ "${params}" != "" ]; then
params="${params}, "
fi
params="${params}'$1'"
shift
done
cat pyGlue.py | sed -e "s/pyGlue/${name}/g" | \
sed -e "/_svc_name_ =/s?=.*?= '${name}'?" | \
sed -e "/_svc_display_name_ =/s?=.*?= '${display}'?" | \
sed -e "/_svc_description_ =/s?=.*?= '${desc}'?" | \
sed -e "/service_exe =/s?=.*?= '$exe'?" | \
sed -e "/service_script =/s?=.*?= '$script'?" | \
sed -e "/service_params =/s?=.*?= [${params}]?" | \
sed -e "/service_startDir =/s?=.*?= '${startDir}'?" > ${name}.py
cxfreeze ${name}.py --include-modules=win32timezone
Installation - copy the '.exe' the server and the script to the specified folder. Run the '.exe', as Administrator, with the 'install' option. Open Windows Services, as Adminstrator, and start you service. For upgrade, just copy the new version of the script and Stop/Start the service.
Now every server is different - different installations of Python, different folder structures. I maintain a folder for every server, with a copy of pyGlue.py and build.sh. And I create a 'serverBuild.sh' script for rebuilding all the service on that server.
# A script to build all the script based Services on this PC
sh build.sh AutoCode 'AutoCode Medical Documents' 'Autocode Medical Documents to SNOMED_CT and AIHW codes' C:/Python38/python.exe autocode.py C:/Users/russell/Documents/autocoding -S -T
The accepted answer using win32serviceutil works but is complicated and makes debugging and changes harder. It is far easier to use NSSM (the Non-Sucking Service Manager). You write and comfortably debug a normal python program and when it finally works you use NSSM to install it as a service in less than a minute:
From an elevated (admin) command prompt you run nssm.exe install NameOfYourService and you fill-in these options:
path: (the path to python.exe e.g. C:\Python27\Python.exe)
Arguments: (the path to your python script, e.g. c:\path\to\program.py)
By the way, if your program prints useful messages that you want to keep in a log file NSSM can also handle this and a lot more for you.
This doesn't answer the original question, but might help other people that want to automatically start a Python script at Windows startup:
Have a look at the Windows Task Scheduler instead, it is way easier if you just want to start a script after boot without all the service functionality of a Windows Service.
Create a new task, select "At startup" as trigger, "Start program" as action with "C:\Python39\python.exe" as the program (or wherever your python.exe is) and the full path to your script ("C:...\my_dir\xyz.py") as argument (you can use " if the path contains spaces).
You can also select the path of your script (without the .py file, e.g. "C:...\my_dir") for "start in" if you use relative paths in your script, e.g. for logging.
https://www.chrisumbel.com/article/windows_services_in_python
Follow up the PySvc.py
changing the dll folder
I know this is old but I was stuck on this forever. For me, this specific problem was solved by copying this file - pywintypes36.dll
From -> Python36\Lib\site-packages\pywin32_system32
To -> Python36\Lib\site-packages\win32
setx /M PATH "%PATH%;C:\Users\user\AppData\Local\Programs\Python\Python38-32;C:\Users\user\AppData\Local\Programs\Python\Python38-32\Scripts;C:\Users\user\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\pywin32_system32;C:\Users\user\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\win32
changing the path to python folder by
cd C:\Users\user\AppData\Local\Programs\Python\Python38-32
NET START PySvc
NET STOP PySvc
Related
I am sketching the architecture for a set of programs that share various interrelated objects stored in a database. I want one of the programs to act as a service which provides a higher level interface for operations on these objects, and the other programs to access the objects through that service.
I am currently aiming for Python and the Django framework as the technologies to implement that service with. I'm pretty sure I figure how to daemonize the Python program in Linux. However, it is an optional spec item that the system should support Windows. I have little experience with Windows programming and no experience at all with Windows services.
Is it possible to run a Python programs as a Windows service (i. e. run it automatically without user login)? I won't necessarily have to implement this part, but I need a rough idea how it would be done in order to decide whether to design along these lines.
Edit: Thanks for all the answers so far, they are quite comprehensive. I would like to know one more thing: How is Windows aware of my service? Can I manage it with the native Windows utilities? What is the equivalent of putting a start/stop script in /etc/init.d?
Yes you can. I do it using the pythoncom libraries that come included with ActivePython or can be installed with pywin32 (Python for Windows extensions).
This is a basic skeleton for a simple service:
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
class AppServerSvc (win32serviceutil.ServiceFramework):
_svc_name_ = "TestService"
_svc_display_name_ = "Test Service"
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):
pass
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(AppServerSvc)
Your code would go in the main() method—usually with some kind of infinite loop that might be interrupted by checking a flag, which you set in the SvcStop method
The simplest way is to use the: NSSM - the Non-Sucking Service Manager. Just download and unzip to a location of your choosing. It's a self-contained utility, around 300KB (much less than installing the entire pywin32 suite just for this purpose) and no "installation" is needed. The zip contains a 64-bit and a 32-bit version of the utility. Either should work well on current systems (you can use the 32-bit version to manage services on 64-bit systems).
GUI approach
1 - install the python program as a service. Open a Win prompt as admin
c:\>nssm.exe install WinService
2 - On NSSM´s GUI console:
path: C:\Python27\Python27.exe
Startup directory: C:\Python27
Arguments: c:\WinService.py
3 - check the created services on services.msc
Scripting approach (no GUI)
This is handy if your service should be part of an automated, non-interactive procedure, that may be beyond your control, such as a batch or installer script. It is assumed that the commands are executed with administrative privileges.
For convenience the commands are described here by simply referring to the utility as nssm.exe. It is advisable, however, to refer to it more explicitly in scripting with its full path c:\path\to\nssm.exe, since it's a self-contained executable that may be located in a private path that the system is not aware of.
1. Install the service
You must specify a name for the service, the path to the proper Python executable, and the path to the script:
nssm.exe install ProjectService "c:\path\to\python.exe" "c:\path\to\project\app\main.py"
More explicitly:
nssm.exe install ProjectService
nssm.exe set ProjectService Application "c:\path\to\python.exe"
nssm.exe set ProjectService AppParameters "c:\path\to\project\app\main.py"
Alternatively you may want your Python app to be started as a Python module. One easy approach is to tell nssm that it needs to change to the proper starting directory, as you would do yourself when launching from a command shell:
nssm.exe install ProjectService "c:\path\to\python.exe" "-m app.main"
nssm.exe set ProjectService AppDirectory "c:\path\to\project"
This approach works well with virtual environments and self-contained (embedded) Python installs. Just make sure to have properly resolved any path issues in those environments with the usual methods. nssm has a way to set environment variables (e.g. PYTHONPATH) if needed, and can also launch batch scripts.
2. To start the service
nssm.exe start ProjectService
3. To stop the service
nssm.exe stop ProjectService
4. To remove the service, specify the confirm parameter to skip the interactive confirmation.
nssm.exe remove ProjectService confirm
Although I upvoted the chosen answer a couple of weeks back, in the meantime I struggled a lot more with this topic. It feels like having a special Python installation and using special modules to run a script as a service is simply the wrong way. What about portability and such?
I stumbled across the wonderful Non-sucking Service Manager, which made it really simple and sane to deal with Windows Services. I figured since I could pass options to an installed service, I could just as well select my Python executable and pass my script as an option.
I have not yet tried this solution, but I will do so right now and update this post along the process. I am also interested in using virtualenvs on Windows, so I might come up with a tutorial sooner or later and link to it here.
The simplest way to achieve this is to use native command sc.exe:
sc create PythonApp binPath= "C:\Python34\Python.exe --C:\tmp\pythonscript.py"
References:
https://technet.microsoft.com/en-us/library/cc990289(v=ws.11).aspx
When creating a service with sc.exe how to pass in context parameters?
There are a couple alternatives for installing as a service virtually any Windows executable.
Method 1: Use instsrv and srvany from rktools.exe
For Windows Home Server or Windows Server 2003 (works with WinXP too), the Windows Server 2003 Resource Kit Tools comes with utilities that can be used in tandem for this, called instsrv.exe and srvany.exe. See this Microsoft KB article KB137890 for details on how to use these utils.
For Windows Home Server, there is a great user friendly wrapper for these utilities named aptly "Any Service Installer".
Method 2: Use ServiceInstaller for Windows NT
There is another alternative using ServiceInstaller for Windows NT (download-able here) with python instructions available. Contrary to the name, it works with both Windows 2000 and Windows XP as well. Here are some instructions for how to install a python script as a service.
Installing a Python script
Run ServiceInstaller to create a new
service. (In this example, it is
assumed that python is installed at
c:\python25)
Service Name : PythonTest
Display Name : PythonTest
Startup : Manual (or whatever you like)
Dependencies : (Leave blank or fill to fit your needs)
Executable : c:\python25\python.exe
Arguments : c:\path_to_your_python_script\test.py
Working Directory : c:\path_to_your_python_script
After installing, open the Control
Panel's Services applet, select and
start the PythonTest service.
After my initial answer, I noticed there were closely related Q&A already posted on SO. See also:
Can I run a Python script as a service (in Windows)? How?
How do I make Windows aware of a service I have written in Python?
Step by step explanation how to make it work :
1- First create a python file according to the basic skeleton mentioned above. And save it to a path for example : "c:\PythonFiles\AppServerSvc.py"
import win32serviceutil
import win32service
import win32event
import servicemanager
import socket
class AppServerSvc (win32serviceutil.ServiceFramework):
_svc_name_ = "TestService"
_svc_display_name_ = "Test Service"
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):
# Your business logic or call to any class should be here
# this time it creates a text.txt and writes Test Service in a daily manner
f = open('C:\\test.txt', 'a')
rc = None
while rc != win32event.WAIT_OBJECT_0:
f.write('Test Service \n')
f.flush()
# block for 24*60*60 seconds and wait for a stop event
# it is used for a one-day loop
rc = win32event.WaitForSingleObject(self.hWaitStop, 24 * 60 * 60 * 1000)
f.write('shut down \n')
f.close()
if __name__ == '__main__':
win32serviceutil.HandleCommandLine(AppServerSvc)
2 - On this step we should register our service.
Run command prompt as administrator and type as:
sc create TestService binpath= "C:\Python36\Python.exe c:\PythonFiles\AppServerSvc.py" DisplayName= "TestService" start= auto
the first argument of binpath is the path of python.exe
second argument of binpath is the path of your python file that we created already
Don't miss that you should put one space after every "=" sign.
Then if everything is ok, you should see
[SC] CreateService SUCCESS
Now your python service is installed as windows service now. You can see it in Service Manager and registry under :
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\TestService
3- Ok now. You can start your service on service manager.
You can execute every python file that provides this service skeleton.
pysc: Service Control Manager on Python
Example script to run as a service taken from pythonhosted.org:
from xmlrpc.server import SimpleXMLRPCServer
from pysc import event_stop
class TestServer:
def echo(self, msg):
return msg
if __name__ == '__main__':
server = SimpleXMLRPCServer(('127.0.0.1', 9001))
#event_stop
def stop():
server.server_close()
server.register_instance(TestServer())
server.serve_forever()
Create and start service
import os
import sys
from xmlrpc.client import ServerProxy
import pysc
if __name__ == '__main__':
service_name = 'test_xmlrpc_server'
script_path = os.path.join(
os.path.dirname(__file__), 'xmlrpc_server.py'
)
pysc.create(
service_name=service_name,
cmd=[sys.executable, script_path]
)
pysc.start(service_name)
client = ServerProxy('http://127.0.0.1:9001')
print(client.echo('test scm'))
Stop and delete service
import pysc
service_name = 'test_xmlrpc_server'
pysc.stop(service_name)
pysc.delete(service_name)
pip install pysc
nssm in python 3+
(I converted my .py file to .exe with pyinstaller)
nssm:
as said before
run nssm install {ServiceName}
On NSSM´s console:
path: path\to\your\program.exe
Startup directory: path\to\your\ #same as the path but without your program.exe
Arguments: empty
If you don't want to convert your project to .exe
create a .bat file with python {{your python.py file name}}
and set the path to the .bat file
I started hosting as a service with pywin32.
Everything was well but I met the problem that service was not able to start within 30 seconds (default timeout for Windows) on system startup. It was critical for me because Windows startup took place simultaneous on several virtual machines hosted on one physical machine, and IO load was huge.
Error messages were:
Error 1053: The service did not respond to the start or control request in a timely fashion.
Error 7009: Timeout (30000 milliseconds) waiting for the <ServiceName> service to connect.
I fought a lot with pywin, but ended up with using NSSM as it was proposed in this answer. It was very easy to migrate to it.
A complete pywin32 example using loop or subthread
After working on this on and off for a few days, here is the answer I would have wished to find, using pywin32 to keep it nice and self contained.
This is complete working code for one loop-based and one thread-based solution.
It may work on both python 2 and 3, although I've only tested the latest version on 2.7 and Win7. The loop should be good for polling code, and the tread should work with more server-like code. It seems to work nicely with the waitress wsgi server that does not have a standard way to shut down gracefully.
I would also like to note that there seems to be loads of examples out there, like this that are almost useful, but in reality misleading, because they have cut and pasted other examples blindly. I could be wrong. but why create an event if you never wait for it?
That said I still feel I'm on somewhat shaky ground here, especially with regards to how clean the exit from the thread version is, but at least I believe there are nothing misleading here.
To run simply copy the code to a file and follow the instructions.
update:
Use a simple flag to terminate thread. The important bit is that "thread done" prints.
For a more elaborate example exiting from an uncooperative server thread see my post about the waitress wsgi server.
# uncomment mainthread() or mainloop() call below
# run without parameters to see HandleCommandLine options
# install service with "install" and remove with "remove"
# run with "debug" to see print statements
# with "start" and "stop" watch for files to appear
# check Windows EventViever for log messages
import socket
import sys
import threading
import time
from random import randint
from os import path
import servicemanager
import win32event
import win32service
import win32serviceutil
# see http://timgolden.me.uk/pywin32-docs/contents.html for details
def dummytask_once(msg='once'):
fn = path.join(path.dirname(__file__),
'%s_%s.txt' % (msg, randint(1, 10000)))
with open(fn, 'w') as fh:
print(fn)
fh.write('')
def dummytask_loop():
global do_run
while do_run:
dummytask_once(msg='loop')
time.sleep(3)
class MyThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
def run(self):
global do_run
do_run = True
print('thread start\n')
dummytask_loop()
print('thread done\n')
def exit(self):
global do_run
do_run = False
class SMWinservice(win32serviceutil.ServiceFramework):
_svc_name_ = 'PyWinSvc'
_svc_display_name_ = 'Python Windows Service'
_svc_description_ = 'An example of a windows service in Python'
#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) # create generic event
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) # raise event
def SvcDoRun(self):
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
# UNCOMMENT ONE OF THESE
# self.mainthread()
# self.mainloop()
# Wait for stopEvt indefinitely after starting thread.
def mainthread(self):
print('main start')
self.server = MyThread()
self.server.start()
print('wait for win32event')
win32event.WaitForSingleObject(self.stopEvt, win32event.INFINITE)
self.server.exit()
print('wait for thread')
self.server.join()
print('main done')
# Wait for stopEvt event in loop.
def mainloop(self):
print('loop start')
rc = None
while rc != win32event.WAIT_OBJECT_0:
dummytask_once()
rc = win32event.WaitForSingleObject(self.stopEvt, 3000)
print('loop done')
if __name__ == '__main__':
SMWinservice.parse_command_line()
This answer is plagiarizer from several sources on StackOverflow - most of them above, but I've forgotten the others - sorry. It's simple and scripts run "as is". For releases you test you script, then copy it to the server and Stop/Start the associated service. And it should work for all scripting languages (Python, Perl, node.js), plus batch scripts such as GitBash, PowerShell, even old DOS bat scripts.
pyGlue is the glue that sits between Windows Services and your script.
'''
A script to create a Windows Service, which, when started, will run an executable with the specified parameters.
Optionally, you can also specify a startup directory
To use this script you MUST define (in class Service)
1. A name for your service (short - preferably no spaces)
2. A display name for your service (the name visibile in Windows Services)
3. A description for your service (long details visible when you inspect the service in Windows Services)
4. The full path of the executable (usually C:/Python38/python.exe or C:WINDOWS/System32/WindowsPowerShell/v1.0/powershell.exe
5. The script which Python or PowerShell will run(or specify None if your executable is standalone - in which case you don't need pyGlue)
6. The startup directory (or specify None)
7. Any parameters for your script (or for your executable if you have no script)
NOTE: This does not make a portable script.
The associated '_svc_name.exe' in the dist folder will only work if the executable,
(and any optional startup directory) actually exist in those locations on the target system
Usage: 'pyGlue.exe [options] install|update|remove|start [...]|stop|restart [...]|debug [...]'
Options for 'install' and 'update' commands only:
--username domain\\username : The Username the service is to run under
--password password : The password for the username
--startup [manual|auto|disabled|delayed] : How the service starts, default = manual
--interactive : Allow the service to interact with the desktop.
--perfmonini file: .ini file to use for registering performance monitor data
--perfmondll file: .dll file to use when querying the service for performance data, default = perfmondata.dll
Options for 'start' and 'stop' commands only:
--wait seconds: Wait for the service to actually start or stop.
If you specify --wait with the 'stop' option, the service and all dependent services will be stopped,
each waiting the specified period.
'''
# Import all the modules that make life easy
import servicemanager
import socket
import sys
import win32event
import win32service
import win32serviceutil
import win32evtlogutil
import os
from logging import Formatter, Handler
import logging
import subprocess
# Define the win32api class
class Service (win32serviceutil.ServiceFramework):
# The following variable are edited by the build.sh script
_svc_name_ = "TestService"
_svc_display_name_ = "Test Service"
_svc_description_ = "Test Running Python Scripts as a Service"
service_exe = 'c:/Python27/python.exe'
service_script = None
service_params = []
service_startDir = None
# Initialize the service
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
self.configure_logging()
socket.setdefaulttimeout(60)
# Configure logging to the WINDOWS Event logs
def configure_logging(self):
self.formatter = Formatter('%(message)s')
self.handler = logHandler()
self.handler.setFormatter(self.formatter)
self.logger = logging.getLogger()
self.logger.addHandler(self.handler)
self.logger.setLevel(logging.INFO)
# Stop the service
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.hWaitStop)
# Run the service
def SvcDoRun(self):
self.main()
# This is the service
def main(self):
# Log that we are starting
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE, servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
# Fire off the real process that does the real work
logging.info('%s - about to call Popen() to run %s %s %s', self._svc_name_, self.service_exe, self.service_script, self.service_params)
self.process = subprocess.Popen([self.service_exe, self.service_script] + self.service_params, shell=False, cwd=self.service_startDir)
logging.info('%s - started process %d', self._svc_name_, self.process.pid)
# Wait until WINDOWS kills us - retrigger the wait for stop every 60 seconds
rc = None
while rc != win32event.WAIT_OBJECT_0:
rc = win32event.WaitForSingleObject(self.hWaitStop, (1 * 60 * 1000))
# Shut down the real process and exit
logging.info('%s - is terminating process %d', self._svc_name_, self.process.pid)
self.process.terminate()
logging.info('%s - is exiting', self._svc_name_)
class logHandler(Handler):
'''
Emit a log record to the WINDOWS Event log
'''
def emit(self, record):
servicemanager.LogInfoMsg(record.getMessage())
# The main code
if __name__ == '__main__':
'''
Create a Windows Service, which, when started, will run an executable with the specified parameters.
'''
# Check that configuration contains valid values just in case this service has accidentally
# been moved to a server where things are in different places
if not os.path.isfile(Service.service_exe):
print('Executable file({!s}) does not exist'.format(Service.service_exe), file=sys.stderr)
sys.exit(0)
if not os.access(Service.service_exe, os.X_OK):
print('Executable file({!s}) is not executable'.format(Service.service_exe), file=sys.stderr)
sys.exit(0)
# Check that any optional startup directory exists
if (Service.service_startDir is not None) and (not os.path.isdir(Service.service_startDir)):
print('Start up directory({!s}) does not exist'.format(Service.service_startDir), file=sys.stderr)
sys.exit(0)
if len(sys.argv) == 1:
servicemanager.Initialize()
servicemanager.PrepareToHostSingle(Service)
servicemanager.StartServiceCtrlDispatcher()
else:
# install/update/remove/start/stop/restart or debug the service
# One of those command line options must be specified
win32serviceutil.HandleCommandLine(Service)
Now there's a bit of editing and you don't want all your services called 'pyGlue'. So there's a script (build.sh) to plug in the bits and create a customized 'pyGlue' and create an '.exe'. It is this '.exe' which gets installed as a Windows Service. Once installed you can set it to run automatically.
#!/bin/sh
# This script build a Windows Service that will install/start/stop/remove a service that runs a script
# That is, executes Python to run a Python script, or PowerShell to run a PowerShell script, etc
if [ $# -lt 6 ]; then
echo "Usage: build.sh Name Display Description Executable Script StartupDir [Params]..."
exit 0
fi
name=$1
display=$2
desc=$3
exe=$4
script=$5
startDir=$6
shift; shift; shift; shift; shift; shift
params=
while [ $# -gt 0 ]; do
if [ "${params}" != "" ]; then
params="${params}, "
fi
params="${params}'$1'"
shift
done
cat pyGlue.py | sed -e "s/pyGlue/${name}/g" | \
sed -e "/_svc_name_ =/s?=.*?= '${name}'?" | \
sed -e "/_svc_display_name_ =/s?=.*?= '${display}'?" | \
sed -e "/_svc_description_ =/s?=.*?= '${desc}'?" | \
sed -e "/service_exe =/s?=.*?= '$exe'?" | \
sed -e "/service_script =/s?=.*?= '$script'?" | \
sed -e "/service_params =/s?=.*?= [${params}]?" | \
sed -e "/service_startDir =/s?=.*?= '${startDir}'?" > ${name}.py
cxfreeze ${name}.py --include-modules=win32timezone
Installation - copy the '.exe' the server and the script to the specified folder. Run the '.exe', as Administrator, with the 'install' option. Open Windows Services, as Adminstrator, and start you service. For upgrade, just copy the new version of the script and Stop/Start the service.
Now every server is different - different installations of Python, different folder structures. I maintain a folder for every server, with a copy of pyGlue.py and build.sh. And I create a 'serverBuild.sh' script for rebuilding all the service on that server.
# A script to build all the script based Services on this PC
sh build.sh AutoCode 'AutoCode Medical Documents' 'Autocode Medical Documents to SNOMED_CT and AIHW codes' C:/Python38/python.exe autocode.py C:/Users/russell/Documents/autocoding -S -T
The accepted answer using win32serviceutil works but is complicated and makes debugging and changes harder. It is far easier to use NSSM (the Non-Sucking Service Manager). You write and comfortably debug a normal python program and when it finally works you use NSSM to install it as a service in less than a minute:
From an elevated (admin) command prompt you run nssm.exe install NameOfYourService and you fill-in these options:
path: (the path to python.exe e.g. C:\Python27\Python.exe)
Arguments: (the path to your python script, e.g. c:\path\to\program.py)
By the way, if your program prints useful messages that you want to keep in a log file NSSM can also handle this and a lot more for you.
This doesn't answer the original question, but might help other people that want to automatically start a Python script at Windows startup:
Have a look at the Windows Task Scheduler instead, it is way easier if you just want to start a script after boot without all the service functionality of a Windows Service.
Create a new task, select "At startup" as trigger, "Start program" as action with "C:\Python39\python.exe" as the program (or wherever your python.exe is) and the full path to your script ("C:...\my_dir\xyz.py") as argument (you can use " if the path contains spaces).
You can also select the path of your script (without the .py file, e.g. "C:...\my_dir") for "start in" if you use relative paths in your script, e.g. for logging.
https://www.chrisumbel.com/article/windows_services_in_python
Follow up the PySvc.py
changing the dll folder
I know this is old but I was stuck on this forever. For me, this specific problem was solved by copying this file - pywintypes36.dll
From -> Python36\Lib\site-packages\pywin32_system32
To -> Python36\Lib\site-packages\win32
setx /M PATH "%PATH%;C:\Users\user\AppData\Local\Programs\Python\Python38-32;C:\Users\user\AppData\Local\Programs\Python\Python38-32\Scripts;C:\Users\user\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\pywin32_system32;C:\Users\user\AppData\Local\Programs\Python\Python38-32\Lib\site-packages\win32
changing the path to python folder by
cd C:\Users\user\AppData\Local\Programs\Python\Python38-32
NET START PySvc
NET STOP PySvc
I currently have a Python file that when run using python file_name.py installs a Windows service that is viewable in Event Viewer under application logs and stoppable using sc stop service_name. However, when converted into an executable using cx_Freeze, the executable runs with no errors but the service no longer installs. This happens if I run just the executable by itself, if I run service_name.exe --install service_name, or if I run sc create service_name binPath=service_path
My setup.py file looks something like:
from cx_Freeze import setup, Executable
options = {
'build_exe': {
'packages': ['packagename'],
'includes': ['ServiceHandler', 'cx_Logging']}
}
setup(name='cx_FreezeSampleService',
version='0.1',
description='Sample cx_Freeze Windows serice',
executables=Executable('Config.py', base='Win32Service',
targetName='cx_FreezeSampleService.exe'),
options=options
)
My Config.py looks something like:
NAME = 'cx_FreezeSampleService%s'
DISPLAY_NAME = 'cx_Freeze Sample Service - %s'
MODULE_NAME = 'ServiceHandler'
CLASS_NAME = 'Handler'
DESCRIPTION = 'Sample service description'
AUTO_START = True
SESSION_CHANGES = False
And finally, my ServiceHandler.py looks something like:
class Handler(object):
def Initialize(self, Config):
pass
def Run(self):
#code to run service
def Stop(self):
#code to stop service
This code follows the example at the cx_Freeze source code here (https://bitbucket.org/anthony_tuininga/cx_freeze/src/1282b6b6ee637738210113dd88c3c198d475340f/cx_Freeze/samples/service/?at=default) almost exactly, but neither this nor the example seem to work in actually installing a service.
Thank you in advance!
This is an old question, but I manage to get it working as a window service for a simple flask application with the help of the developers.
[https://github.com/marcelotduarte/cx_Freeze/tree/master/cx_Freeze/samples/service]
You have to set up all the windows service actions you want performance.
this is how the ServiceHandler.py should look like as a template you still need to adapt to run your application.
"""
Implements a simple service using cx_Freeze.
See below for more information on what methods must be implemented and how they
are called.
"""
import threading
import os
import sys
import cx_Logging
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, "teste.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.stopRequestedEvent.wait()
self.stopEvent.set()
# called when the service is being stopped by the service manager GUI
def stop(self):
self.stopRequestedEvent.set()
self.stopEvent.wait()
I'm writing python unit tests that test against a REST API that needs to be running as another process.
The REST server is a tomcat application that I call from the shell to run in development mode, so what I am looking to do in the python test is:
Start the server, return when the server is up.
Run unit tests
Send the server Ctrl+D so it shuts down gracefully.
Is there a way to use a single point of entry for python so that the server starts and unit tests run all from one python script call?
I've look around at python subprocess and multithreading in python, but I still don't quite see how to get there from here.
For those that are familiar, this is an Atlassian JIRA plugin we are developing, so the actual shell command is "atlas-run".
Since no one has offered any code to help with this problem, I would do something like the following. Turns out pexpect is very powerful and you don't need the signal module.
import os
import sys
import pexpect
def run_server():
server_dir = '/path/to/server/root'
current_dir = os.path.abspath(os.curdir)
os.chdir(server_dir)
server_call = pexpect.spawn('atlas-run')
server_response = server_call.expect(['Server Error!', 'Sever is running!'])
os.chdir(current_dir)
if server_response:
return server_call #return server spawn object so we can shutdown later
else:
print 'Error starting the server: %s'%server_response.after
sys.exit(1)
def run_unittests():
# several ways to do this. either make a unittest.TestSuite or run command line
# here is the second option
unittest_dir = '/path/to/tests'
pexpect.spawn('python -m unittest discover -s %s -p "*test.py"'%unittest_dir)
test_response = pexpect.expect('Ran [0-9]+ tests in [0-9\.]+s') #catch end
print test_response.before #print output of unittests before ending.
return
def main():
server = run_sever()
run_unittests()
server.sendcontrol('d') #shutdown server
if __name__ == "__main__":
main()
I have a minimal python win32 service service.py that does nothing special:
import win32serviceutil
import win32service
import win32event
class SmallestPythonService(win32serviceutil.ServiceFramework):
_svc_name_ = "SmallestPythonService"
_svc_display_name_ = "display service"
# _svc_description_='ddd'
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):
win32event.WaitForSingleObject(self.hWaitStop, win32event.INFINITE)
if __name__=='__main__':
win32serviceutil.HandleCommandLine(SmallestPythonService)
When I run:
service.py install
service.py start
it works fine but when I compile the service.py file with py2exe to service.exe and run the following:
service.exe install
service.exe start [or trying to restart the service from the Services.msc]
I get this message:
Could not start the service name service on Local Computer.
Error 1053: The service did not respond to the start or control request in a timely fashion
How can I resolve this problem?
Also here the distutil code:
from distutils.core import setup
import py2exe
py2exe_options = {"includes": ['decimal'],'bundle_files': 1}
setup(console=[{"script":'Service.py'}],
options={"py2exe": py2exe_options},
zipfile = None,
},
)
Replace your: setup(console=[{"script":'Service.py'}] with setup(service=[{"script":'Service.py'}]. Instead of console use service.
try this setup:
py2exe_options = {"includes": ['decimal'],'bundle_files': 1}
setup(
service=[{'modules':'Service.py','cmdline_style':'pywin32','description':'your service description'}],
options={'py2exe':py2exe_options},
zipfile=None)
A quick google came up with this: http://islascruz.org/html/index.php?gadget=StaticPage&action=Page&id=6
It has Italian comments, but I can help you translate some stuff if you don't know Italian.
To truly debug your problem, I guess we will need to see your setup.py distutils script...
You probably might be missing the right PATH for finding all the DLLs required by the service. Usually the service gets installed as a 'LocalSystem' service so you need to add the PATH to the System (and not to User).
Try adding c:\python27 (or whatever the path to your python dlls is) to the SYSTEM PATH, restart the computer and check if it now starts fine.
I have written a Python script that checks a certain e-mail address and passes new e-mails to an external program. How can I get this script to execute 24/7, such as turning it into daemon or service in Linux. Would I also need a loop that never ends in the program, or can it be done by just having the code re executed multiple times?
You have two options here.
Make a proper cron job that calls your script. Cron is a common name for a GNU/Linux daemon that periodically launches scripts according to a schedule you set. You add your script into a crontab or place a symlink to it into a special directory and the daemon handles the job of launching it in the background. You can read more at Wikipedia. There is a variety of different cron daemons, but your GNU/Linux system should have it already installed.
Use some kind of python approach (a library, for example) for your script to be able to daemonize itself. Yes, it will require a simple event loop (where your events are timer triggering, possibly, provided by sleep function).
I wouldn't recommend you to choose 2., because you would be, in fact, repeating cron functionality. The Linux system paradigm is to let multiple simple tools interact and solve your problems. Unless there are additional reasons why you should make a daemon (in addition to trigger periodically), choose the other approach.
Also, if you use daemonize with a loop and a crash happens, no one will check the mail after that (as pointed out by Ivan Nevostruev in comments to this answer). While if the script is added as a cron job, it will just trigger again.
Here's a nice class that is taken from here:
#!/usr/bin/env python
import sys, os, time, atexit
from signal import SIGTERM
class Daemon:
"""
A generic daemon class.
Usage: subclass the Daemon class and override the run() method
"""
def __init__(self, pidfile, stdin='/dev/null', stdout='/dev/null', stderr='/dev/null'):
self.stdin = stdin
self.stdout = stdout
self.stderr = stderr
self.pidfile = pidfile
def daemonize(self):
"""
do the UNIX double-fork magic, see Stevens' "Advanced
Programming in the UNIX Environment" for details (ISBN 0201563177)
http://www.erlenstar.demon.co.uk/unix/faq_2.html#SEC16
"""
try:
pid = os.fork()
if pid > 0:
# exit first parent
sys.exit(0)
except OSError, e:
sys.stderr.write("fork #1 failed: %d (%s)\n" % (e.errno, e.strerror))
sys.exit(1)
# decouple from parent environment
os.chdir("/")
os.setsid()
os.umask(0)
# do second fork
try:
pid = os.fork()
if pid > 0:
# exit from second parent
sys.exit(0)
except OSError, e:
sys.stderr.write("fork #2 failed: %d (%s)\n" % (e.errno, e.strerror))
sys.exit(1)
# redirect standard file descriptors
sys.stdout.flush()
sys.stderr.flush()
si = file(self.stdin, 'r')
so = file(self.stdout, 'a+')
se = file(self.stderr, 'a+', 0)
os.dup2(si.fileno(), sys.stdin.fileno())
os.dup2(so.fileno(), sys.stdout.fileno())
os.dup2(se.fileno(), sys.stderr.fileno())
# write pidfile
atexit.register(self.delpid)
pid = str(os.getpid())
file(self.pidfile,'w+').write("%s\n" % pid)
def delpid(self):
os.remove(self.pidfile)
def start(self):
"""
Start the daemon
"""
# Check for a pidfile to see if the daemon already runs
try:
pf = file(self.pidfile,'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None
if pid:
message = "pidfile %s already exist. Daemon already running?\n"
sys.stderr.write(message % self.pidfile)
sys.exit(1)
# Start the daemon
self.daemonize()
self.run()
def stop(self):
"""
Stop the daemon
"""
# Get the pid from the pidfile
try:
pf = file(self.pidfile,'r')
pid = int(pf.read().strip())
pf.close()
except IOError:
pid = None
if not pid:
message = "pidfile %s does not exist. Daemon not running?\n"
sys.stderr.write(message % self.pidfile)
return # not an error in a restart
# Try killing the daemon process
try:
while 1:
os.kill(pid, SIGTERM)
time.sleep(0.1)
except OSError, err:
err = str(err)
if err.find("No such process") > 0:
if os.path.exists(self.pidfile):
os.remove(self.pidfile)
else:
print str(err)
sys.exit(1)
def restart(self):
"""
Restart the daemon
"""
self.stop()
self.start()
def run(self):
"""
You should override this method when you subclass Daemon. It will be called after the process has been
daemonized by start() or restart().
"""
You should use the python-daemon library, it takes care of everything.
From PyPI: Library to implement a well-behaved Unix daemon process.
Assuming that you would really want your loop to run 24/7 as a background service
For a solution that doesn't involve injecting your code with libraries, you can simply create a service template, since you are using linux:
[Unit]
Description = <Your service description here>
After = network.target # Assuming you want to start after network interfaces are made available
[Service]
Type = simple
ExecStart = python <Path of the script you want to run>
User = # User to run the script as
Group = # Group to run the script as
Restart = on-failure # Restart when there are errors
SyslogIdentifier = <Name of logs for the service>
RestartSec = 5
TimeoutStartSec = infinity
[Install]
WantedBy = multi-user.target # Make it accessible to other users
Place that file in your daemon service folder (usually /etc/systemd/system/), in a *.service file, and install it using the following systemctl commands (will likely require sudo privileges):
systemctl enable <service file name without .service extension>
systemctl daemon-reload
systemctl start <service file name without .service extension>
You can then check that your service is running by using the command:
systemctl | grep running
You can use fork() to detach your script from the tty and have it continue to run, like so:
import os, sys
fpid = os.fork()
if fpid!=0:
# Running as daemon now. PID is fpid
sys.exit(0)
Of course you also need to implement an endless loop, like
while 1:
do_your_check()
sleep(5)
Hope this get's you started.
You can also make the python script run as a service using a shell script. First create a shell script to run the python script like this (scriptname arbitary name)
#!/bin/sh
script='/home/.. full path to script'
/usr/bin/python $script &
now make a file in /etc/init.d/scriptname
#! /bin/sh
PATH=/bin:/usr/bin:/sbin:/usr/sbin
DAEMON=/home/.. path to shell script scriptname created to run python script
PIDFILE=/var/run/scriptname.pid
test -x $DAEMON || exit 0
. /lib/lsb/init-functions
case "$1" in
start)
log_daemon_msg "Starting feedparser"
start_daemon -p $PIDFILE $DAEMON
log_end_msg $?
;;
stop)
log_daemon_msg "Stopping feedparser"
killproc -p $PIDFILE $DAEMON
PID=`ps x |grep feed | head -1 | awk '{print $1}'`
kill -9 $PID
log_end_msg $?
;;
force-reload|restart)
$0 stop
$0 start
;;
status)
status_of_proc -p $PIDFILE $DAEMON atd && exit 0 || exit $?
;;
*)
echo "Usage: /etc/init.d/atd {start|stop|restart|force-reload|status}"
exit 1
;;
esac
exit 0
Now you can start and stop your python script using the command /etc/init.d/scriptname start or stop.
A simple and supported version is Daemonize.
Install it from Python Package Index (PyPI):
$ pip install daemonize
and then use like:
...
import os, sys
from daemonize import Daemonize
...
def main()
# your code here
if __name__ == '__main__':
myname=os.path.basename(sys.argv[0])
pidfile='/tmp/%s' % myname # any name
daemon = Daemonize(app=myname,pid=pidfile, action=main)
daemon.start()
Ubuntu has a very simple way to manage a service.
For python the difference is that ALL the dependencies (packages) have to be in the same directory, where the main file is run from.
I just manage to create such a service to provide weather info to my clients.
Steps:
Create your python application project as you normally do.
Install all dependencies locally like:
sudo pip3 install package_name -t .
Create your command line variables and handle them in code (if you need any)
Create the service file. Something (minimalist) like:
[Unit]
Description=1Droid Weather meddleware provider
[Service]
Restart=always
User=root
WorkingDirectory=/home/ubuntu/weather
ExecStart=/usr/bin/python3 /home/ubuntu/weather/main.py httpport=9570 provider=OWMap
[Install]
WantedBy=multi-user.target
Save the file as myweather.service (for example)
Make sure that your app runs if started in the current directory
python3 main.py httpport=9570 provider=OWMap
The service file produced above and named myweather.service (important to have the extension .service) will be treated by the system as the name of your service. That is the name that you will use to interact with your service.
Copy the service file:
sudo cp myweather.service /lib/systemd/system/myweather.service
Refresh demon registry:
sudo systemctl daemon-reload
Stop the service (if it was running)
sudo service myweather stop
Start the service:
sudo service myweather start
Check the status (log file with where your print statements go):
tail -f /var/log/syslog
Or check the status with:
sudo service myweather status
Back to the start with another iteration if needed
This service is now running and even if you log out it will not be affected.
And YES if the host is shutdown and restarted this service will be restarted...
cron is clearly a great choice for many purposes. However it doesn't create a service or daemon as you requested in the OP. cron just runs jobs periodically (meaning the job starts and stops), and no more often than once / minute. There are issues with cron -- for example, if a prior instance of your script is still running the next time the cron schedule comes around and launches a new instance, is that OK? cron doesn't handle dependencies; it just tries to start a job when the schedule says to.
If you find a situation where you truly need a daemon (a process that never stops running), take a look at supervisord. It provides a simple way to wrapper a normal, non-daemonized script or program and make it operate like a daemon. This is a much better way than creating a native Python daemon.
how about using $nohup command on linux?
I use it for running my commands on my Bluehost server.
Please advice if I am wrong.
If you are using terminal(ssh or something) and you want to keep a long-time script working after you log out from the terminal, you can try this:
screen
apt-get install screen
create a virtual terminal inside( namely abc): screen -dmS abc
now we connect to abc: screen -r abc
So, now we can run python script: python keep_sending_mails.py
from now on, you can directly close your terminal, however, the python script will keep running rather than being shut down
Since this keep_sending_mails.py's PID is a child process of the virtual screen rather than the
terminal(ssh)
If you want to go back check your script running status, you can use screen -r abc again
First, read up on mail aliases. A mail alias will do this inside the mail system without you having to fool around with daemons or services or anything of the sort.
You can write a simple script that will be executed by sendmail each time a mail message is sent to a specific mailbox.
See http://www.feep.net/sendmail/tutorial/intro/aliases.html
If you really want to write a needlessly complex server, you can do this.
nohup python myscript.py &
That's all it takes. Your script simply loops and sleeps.
import time
def do_the_work():
# one round of polling -- checking email, whatever.
while True:
time.sleep( 600 ) # 10 min.
try:
do_the_work()
except:
pass
I would recommend this solution. You need to inherit and override method run.
import sys
import os
from signal import SIGTERM
from abc import ABCMeta, abstractmethod
class Daemon(object):
__metaclass__ = ABCMeta
def __init__(self, pidfile):
self._pidfile = pidfile
#abstractmethod
def run(self):
pass
def _daemonize(self):
# decouple threads
pid = os.fork()
# stop first thread
if pid > 0:
sys.exit(0)
# write pid into a pidfile
with open(self._pidfile, 'w') as f:
print >> f, os.getpid()
def start(self):
# if daemon is started throw an error
if os.path.exists(self._pidfile):
raise Exception("Daemon is already started")
# create and switch to daemon thread
self._daemonize()
# run the body of the daemon
self.run()
def stop(self):
# check the pidfile existing
if os.path.exists(self._pidfile):
# read pid from the file
with open(self._pidfile, 'r') as f:
pid = int(f.read().strip())
# remove the pidfile
os.remove(self._pidfile)
# kill daemon
os.kill(pid, SIGTERM)
else:
raise Exception("Daemon is not started")
def restart(self):
self.stop()
self.start()
to creating some thing that is running like service you can use this thing :
The first thing that you must do is installing the Cement framework:
Cement frame work is a CLI frame work that you can deploy your application on it.
command line interface of the app :
interface.py
from cement.core.foundation import CementApp
from cement.core.controller import CementBaseController, expose
from YourApp import yourApp
class Meta:
label = 'base'
description = "your application description"
arguments = [
(['-r' , '--run'],
dict(action='store_true', help='Run your application')),
(['-v', '--version'],
dict(action='version', version="Your app version")),
]
(['-s', '--stop'],
dict(action='store_true', help="Stop your application")),
]
#expose(hide=True)
def default(self):
if self.app.pargs.run:
#Start to running the your app from there !
YourApp.yourApp()
if self.app.pargs.stop:
#Stop your application
YourApp.yourApp.stop()
class App(CementApp):
class Meta:
label = 'Uptime'
base_controller = 'base'
handlers = [MyBaseController]
with App() as app:
app.run()
YourApp.py class:
import threading
class yourApp:
def __init__:
self.loger = log_exception.exception_loger()
thread = threading.Thread(target=self.start, args=())
thread.daemon = True
thread.start()
def start(self):
#Do every thing you want
pass
def stop(self):
#Do some things to stop your application
Keep in mind that your app must run on a thread to be daemon
To run the app just do this in command line
python interface.py --help
Use whatever service manager your system offers - for example under Ubuntu use upstart. This will handle all the details for you such as start on boot, restart on crash, etc.
You can run a process as a subprocess inside a script or in another script like this
subprocess.Popen(arguments, close_fds=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, stdin=subprocess.DEVNULL)
Or use a ready-made utility
https://github.com/megashchik/d-handler