17 August 2010 25 Comments

Running Python script(s) as a Windows Service – Keep your Python Mojo Engines Running while you Sleep!

Now any Python duct-taper integrate-anything junkie like me has a need to schedule their things (in production) every once in awhile. Usually this is not a problem - Unix / Linux cron jobs handle this nicely - but for a client or job that runs on a Windows server - the built-in "Scheduled Tasks" just never really cut it for me - in fact, I've always though that it was pretty Mickey-Mouse and not super reliable (just my opinion - don't flame me, you wily Windows Dudes - I know that there are 1,000 ways to skin a cat, here's mine!)...

It honestly gave me the creeps to put production stuff on there that NEEDED to be run every X minutes, hours, etc. Besides, making a batch file to fire off a python scripts feels so... well, unpolished - and pretty much of a lazy hack that made it into prod...

Disclaimer: Hey, I love hacks - they make the IT world go around, but I don't like delivering shit to clients that have loose feeling triggers like that. Especially, if some smart ass IT dickface (who COULDN'T pull off what I did, or else I wouldn't have been paid to do it) is going to dig into them one day and bad mouth me about it (rightfully so).

Besides, I'll find you! :)

Enough blather - here is the whole script. Modify and distribute where you see fit - parts of it were written by others that I can't recall (so if its you - please accept my apology and an expired gift card).

### Run Python scripts as a service example (ryrobes.com)
### Usage : python aservice.py install (or / then start, stop, remove)

import win32service
import win32serviceutil
import win32api
import win32con
import win32event
import win32evtlogutil
import os, sys, string, time

class aservice(win32serviceutil.ServiceFramework):
   
   _svc_name_ = "MyServiceShortName"
   _svc_display_name_ = "My Serivce Long Fancy Name!"
   _svc_description_ = "THis is what my crazy little service does - aka a DESCRIPTION! WHoa!"
         
   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):
      import servicemanager      
      servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,servicemanager.PYS_SERVICE_STARTED,(self._svc_name_, ''))
     
      #self.timeout = 640000    #640 seconds / 10 minutes (value is in milliseconds)
      self.timeout = 120000     #120 seconds / 2 minutes
      # This is how long the service will wait to run / refresh itself (see script below)

      while 1:
         # Wait for service stop signal, if I timeout, loop again
         rc = win32event.WaitForSingleObject(self.hWaitStop, self.timeout)
         # Check to see if self.hWaitStop happened
         if rc == win32event.WAIT_OBJECT_0:
            # Stop signal encountered
            servicemanager.LogInfoMsg("SomeShortNameVersion - STOPPED!")  #For Event Log
            break
         else:

                 #Ok, here's the real money shot right here.
                 #[actual service code between rests]
                 try:
                     file_path = "C:\whereever\my_REAL_py_work_to_be_done.py"
                     execfile(file_path)             #Execute the script

                     inc_file_path2 = "C:\whereever\MORE_REAL_py_work_to_be_done.py"
                     execfile(inc_file_path2)        #Execute the script
                 except:
                     pass
                 #[actual service code between rests]


def ctrlHandler(ctrlType):
   return True
                 
if __name__ == '__main__':  
   win32api.SetConsoleCtrlHandler(ctrlHandler, True)  
   win32serviceutil.HandleCommandLine(aservice)

# Done! Lets go out and get some dinner, bitches!

As you can see above between the [actual service code between rests] text - THAT'S the real meat of this script - since that is the ACTION that will be executed within the service with each iteration (regardless of the timing).

So it doesn't matter if you're:

  • Running some Python ETL processes
  • Scraping some data off the web
  • Sending emails and reading IMAP accounts
  • Updating a Data warehouse
  • EMail your Grandmother the latest news from Blabbermouth.net

Hell, it can be and do virtually anything! Hey, its YOUR service after all.

Don't want to Cut-N-Paste? I don't blame you - download the whole she-bang here.

Questions, Comments, Corrections? Comment me below!

(especially corrections - sometimes things get mangled in cut-n-paste)

  • priti

    Not able to execute this code.
    When i run this code like:
    python aservice.py install –> It show following messsage on command prompt

    Usage: ‘aservice.py [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] : 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.

    Please help me to execute this code(create window service)

    • http://www.michalgonda.dk Michal Gonda

      You have to write install as argument:
      python aservice.py -install

    • Jyothi Naidu

      Hello Every One,

      I Got the same information when i am trying to execute this code Can i know what is the sollution to come out from this…..

    • Phoenix619

      what is the solution for this guys?

  • Pingback: Need to run a Python program as a Windows Service? | Baggers on the Web()

  • Pingback: Simple web service in python – pywin32 : Note the Code()

  • Pingback: Some Metallica Setlist Analysis using Tableau Public Visualization Software and some Python Hacking | Ryan Robitaille()

  • http://www.facebook.com/people/Meester-Taco/100000072839431 Meester Taco

     Good shit. If I was a man of questionable morals (and I am!) I would jack your website’s tag line and use it as my own – but I won’t since I like the cut of your jib.

  • Constient

    Thanks for the info :)
    for more info : visit http://www.constient.com

  • hvalot

    Hello,

    I tried your script and installation is OK but when i try to start the service I get the following error :

    Error starting service 1053 : The service did not respond to the start or control request in a timely fashion.

    Running on Windows 7 Pro X64
    Python 2.6 pywin32 214

    Can you help me

    • http://ryrobes.com/ Ryan Robitaille

      Seems like it might be a service problem. Does the service start well on its own when you do it manually?

    • KAMION

      I also encountered the same problem, did anyone find out why?

      • Paul Marden

        I too was banging my head against this, but I found the missing link. Important question: like me, did you install pywin32 via pip?

        From the “Installing via PIP” section of the pywin32 readme on GitHub:

        Note that if you want to use pywin32 for “system wide” features, such as registering COM objects or implementing Windows Services, then you must run the following command from an elevated command prompt:

        python Scripts/pywin32_postinstall.py -install

    • Dieter

      Had the same problem with python3.6. i installed python 3.4 and it worked with pywin3.2.1. dont know why. the only problem is that i need to start my python programm which doesnt start

    • Kev Con

      The script above is fine- it’s the windows python bits that need help. It took two fixes for me to get this working

      1/ make sure your python has got an an entry in the registry. Mine didn’t. This is vital for step 2/ — See handy script here https://stackoverflow.com/questions/19169582/python-version-2-7-required-which-was-not-found-in-the-registry-error-when-at/23418442

      2 / install the windows compiled versions of pypi win libray – search for the right build for your version and bit size (32 or 64) https://sourceforge.net/projects/pywin32/files/pywin32/ . If you don’t do the first step, the installer will throw up, saying your python isn’t in the registry

      Once those two steps were done, the service ran happily.

  • http://ryrobes.com/ Ryan Robitaille

    Note: Since this is a popular post (and it’s damn old – like 3 years) I’m going to check that it works on Win 7 and Win 8, and update the script where needed.

  • cappy

    Should execfile be startfile ? couldn’t find execfile in any imported module.

  • Edward Chou

    I ran it well, but I need to change execfile into os.system. Subprocess didn’t work either.

    My Env:
    Win 7 32bit
    Portable Python 2.7.5

  • The Big Grey Sasquatch

    I had a problem where when I launched my “service” using “execfile”, then my “service” would spawn sub processes (restarting things), but everything would exit… so no happy ending. I worked around this by replacing the “execfile” line with one like this:

    os.spawnl(os.P_NOWAIT, “C:\Python27\python.exe”,
    “C:\Python27\python.exe”, file_path)

  • http://www.michalgonda.dk Michal Gonda

    You helped mi a lot since i am not good at windows dev and need to create one simple script to run as background ;-)
    Thank you a lot!

  • hector

    How can you make this script work on a windows server 2012. Is giving me problems is giving me access denied 5

  • KAMION

    As a hint to others, if you get a Windows API error 5: “Access is denied”, try running the cmd.exe as Administrator.

    Also, _svc_name_ must not contain spaces, or you’ll get some mysterious error code:

    Error 0xC00000F4 – Could not find the service’s PythonClass entry in the registry
    Error 1814 – The specified resource name cannot be found in the image file.
    Error 0xC0000080 – Could not locate the module name in the Python class string (ie, no ‘.’)

  • Utkarsh Sinha

    Working on windows 12 r2 server & python 3.6. Slight modification would be reqd. as execfile doesn’t work in python 3, there’s a replacement ‘exec’ though.

  • Haadia Raza

    I have learned a lot from this blog.
    Regards
    https://www.zainhosting.com/

  • NatalieSanelyte

    very detailed and clear, thanks
    Natalie | Blogger | easybuilder.pro