Question

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?

Was it helpful?

Solution

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

OTHER TIPS

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.

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?

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:

  1. https://technet.microsoft.com/en-us/library/cc990289(v=ws.11).aspx
  2. When creating a service with sc.exe how to pass in context parameters?

The simplest way is to use the: NSSM - the Non-Sucking Service Manager:

1 - make download on https://nssm.cc/download

2 - install the python program as a service: Win prompt as admin

c:>nssm.exe install WinService

3 - On NSSM´s console:

path: C:\Python27\Python27.exe

Startup directory: C:\Python27

Arguments: c:\WinService.py

4 - check the created services on services.msc

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.

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.

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.

For anyone who want to create service in VENV or Pycharm !!!!!!!

After reading all the anwsers and create some scripts, if you can run python service.py install and python service.py debug, but python service.py start has no response.

Maybe it's caused by venv problem, because windows service start your service by exec PROJECT\venv\Lib\site-packages\win32\pythonservice.exe.

You can use powershell or cmd to test your service to find more error's details.

PS C:\Users\oraant> E:

PS E:\> cd \Software\PythonService\venv\Lib\site-packages\win32

PS E:\Software\PythonService\venv\Lib\site-packages\win32> .\pythonservice.exe -debug ttttt
Debugging service ttttt - press Ctrl+C to stop.
Error 0xC0000004 - Python could not import the service's module

Traceback (most recent call last):
  File "E:\Software\PythonService\my_service.py", line 2, in <module>
    import win32serviceutil
ModuleNotFoundError: No module named 'win32serviceutil'

(null): (null)

If you get some error like me, then you can check my answer in another question, I fixed it and post my code here.

nssm on 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

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top