Python Windows service pyinstaller executables error 1053

17,002

Solution 1

Try changing the last few lines to

if __name__ == '__main__':
    if len(sys.argv) == 1:
        servicemanager.Initialize()
        servicemanager.PrepareToHostSingle(Service)
        servicemanager.StartServiceCtrlDispatcher()
    else:
        win32serviceutil.HandleCommandLine(Service)

Solution 2

MrTorture had the key to this answer, but I'd like to build upon that here. Something critical to note is that even when using the win32serviceutil functions to manage the service programmatically (vs installing, starting, etc. via the command prompt), you must include the entry point command line dispatch for this to work in a standalone context (i.e. when building an exe with pyinstaller or py2exe). If you don't, Windows will not be able to start the service. You'll get the dreaded 1053 error!

In addition to that, note that if you are creating a service as part of a larger project, you will need to build an exe dedicated to the service. You cannot run it as a sub component within a larger exe (at least I didn't have luck trying to!). I've included my install function to demonstrate that.

Again, when using .py scripts, managed via pythonservice.exe, neither of these issues are present, these are only concerns for standalone exes.

Here are some INCOMPLETE snippets of my functional code, but they might save you a lot of trouble:

SUCCESS = winerror.ERROR_SUCCESS
FAILURE = -1

class WinServiceManager():  

    # pass the class, not an instance of it!
    def __init__( self, serviceClass, serviceExeName=None ):
        self.serviceClass_ = serviceClass
        # Added for pyInstaller v3
        self.serviceExeName_ = serviceExeName

    def isStandAloneContext( self ) : 
        # Changed for pyInstaller v3
        #return sys.argv[0].endswith( ".exe" ) 
        return not( sys.argv[0].endswith( ".py" ) )

    def dispatch( self ):
        if self.isStandAloneContext() :
            servicemanager.Initialize()
            servicemanager.PrepareToHostSingle( self.serviceClass_ )
            servicemanager.Initialize( self.serviceClass_._svc_name_, 
                os.path.abspath( servicemanager.__file__ ) )
            servicemanager.StartServiceCtrlDispatcher()        
        else :
            win32api.SetConsoleCtrlHandler(lambda x: True, True)  
            win32serviceutil.HandleCommandLine( self.serviceClass_ )        

    # Service management functions
    #            
    # Note: all of these functions return:
    # SUCCESS when explicitly successful
    # FAILURE when explicitly not successful at their specific purpose
    # winerror.XXXXXX when win32service (or related class) 
    # throws an error of that nature
    #------------------------------------------------------------------------

    # Note: an "auto start" service is not auto started upon installation!
    # To install and start simultaneously, use start( autoInstall=True ).
    # That performs both actions for manual start services as well.
    def install( self ):
        win32api.SetConsoleCtrlHandler(lambda x: True, True)        
        result = self.verifyInstall()
        if result == SUCCESS or result != FAILURE: return result
        thisExePath = os.path.realpath( sys.argv[0] )
        thisExeDir  = os.path.dirname( thisExePath )        
        # Changed for pyInstaller v3 - which now incorrectly reports the calling exe
        # as the serviceModPath (v2 worked correctly!)
        if self.isStandAloneContext() :
            serviceModPath = self.serviceExeName_
        else :
            serviceModPath = sys.modules[ self.serviceClass_.__module__ ].__file__        
        serviceModPath = os.path.splitext(os.path.abspath( serviceModPath ))[0] 
        serviceClassPath = "%s.%s" % ( serviceModPath, self.serviceClass_.__name__ )
        self.serviceClass_._svc_reg_class_ = serviceClassPath
        # Note: in a "stand alone context", a dedicated service exe is expected 
        # within this directory (important for cases where a separate master exe 
        # is managing services).  
        serviceExePath = (serviceModPath + ".exe") if self.isStandAloneContext() else None        
        isAutoStart = self.serviceClass_._svc_is_auto_start_
        startOpt = (win32service.SERVICE_AUTO_START if isAutoStart else 
                    win32service.SERVICE_DEMAND_START)        
        try :      
            win32serviceutil.InstallService(
                pythonClassString = self.serviceClass_._svc_reg_class_,
                serviceName       = self.serviceClass_._svc_name_,
                displayName       = self.serviceClass_._svc_display_name_,
                description       = self.serviceClass_._svc_description_,
                exeName           = serviceExePath,
                startType         = startOpt
            ) 
        except win32service.error as e: return e[0]
        except Exception as e: raise e        
        win32serviceutil.SetServiceCustomOption( 
            self.serviceClass_._svc_name_, WORKING_DIR_OPT_NAME, thisExeDir )
        for i in range( 0, MAX_STATUS_CHANGE_CHECKS ) :
            result = self.verifyInstall()
            if result == SUCCESS: return SUCCESS
            time.sleep( STATUS_CHANGE_CHECK_DELAY )            
        return result         

In the module where you define your service (derived from win32serviceutil.ServiceFramework), include this at the end of it:

if __name__ == "__main__":   
    WinServiceManager( MyServiceClass, "MyServiceBinary.exe" ).dispatch()
Share:
17,002

Related videos on Youtube

user1385894
Author by

user1385894

Updated on June 06, 2022

Comments

  • user1385894
    user1385894 almost 2 years

    I have written a Windows service in python. If I run my script from the command prompt

    python runService.py 
    

    When I do this the service installs and starts correctly. I have been trying to create an executable using pyinstaller because i've seen the same issue with py2exe. When I run the .exe the service installs but does not start and I get the following error

    error 1053 the service did not respond to the start or control request in a timely fashion 
    

    I have seen that many people have had this issue but I can't seem to find a definitive answer as to how to fix this.

    winservice.py

    from os.path import splitext, abspath
    from sys import modules, executable
    from time import *
    import win32serviceutil
    import win32service
    import win32event
    import win32api
    
    class Service(win32serviceutil.ServiceFramework):
        _svc_name_ = '_unNamed'
        _svc_display_name_ = '_Service Template'
        _svc_description_ = '_Description template'
        def __init__(self, *args):
            win32serviceutil.ServiceFramework.__init__(self, *args)
            self.log('init')
            self.stop_event = win32event.CreateEvent(None, 0, 0, None)
    
        #logs into the system event log
    def log(self, msg):
        import servicemanager
        servicemanager.LogInfoMsg(str(msg))
    
    def sleep(self, minute):
            win32api.Sleep((minute*1000), True)
    def SvcDoRun(self):
        self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
        try:
            self.ReportServiceStatus(win32service.SERVICE_RUNNING)
            self.log('start')
            self.start()
            self.log('wait')
            win32event.WaitForSingleObject(self.stop_event, win32event.INFINITE)
            self.log('done')
        except Exception, x:
            self.log('Exception : %s' % x)
            self.SvcStop()
    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        #self.log('stopping')
        self.stop()
        #self.log('stopped')
        win32event.SetEvent(self.stop_event)
        self.ReportServiceStatus(win32service.SERVICE_STOPPED)
    # to be overridden
    def start(self): pass
    # to be overridden
    def stop(self): pass
    
    def instart(cls, name, description, display_name=None, stay_alive=True):
        ''' Install and  Start (auto) a Service
    
            cls : the class (derived from Service) that implement the Service
            name : Service name
            display_name : the name displayed in the service manager
            decription: the description 
            stay_alive : Service will stop on logout if False
        '''
        cls._svc_name_ = name
        cls._svc_display_name_ = display_name or name
        cls._svc_desciption_ = description
        try:
            module_path=modules[cls.__module__].__file__
        except AttributeError:
    
            module_path=executable
        module_file = splitext(abspath(module_path))[0]
        cls._svc_reg_class_ = '%s.%s' % (module_file, cls.__name__)
        if stay_alive: win32api.SetConsoleCtrlHandler(lambda x: True, True)
        try:
            win32serviceutil.InstallService(
                cls._svc_reg_class_,
                cls._svc_name_,
                cls._svc_display_name_,
                startType = win32service.SERVICE_AUTO_START,
                description = cls._svc_desciption_
            )
            print 'Install ok'
            win32serviceutil.StartService(
            cls._svc_name_
        )
        print 'Start ok'
    except Exception, x:
        print str(x)
    

    UPDATE

    I resolved this issue by using py2exe but the same changes may work for pyinstaller too. I haven't had time to check this out myself.

    I had to remove the instart function. Below is how my winservice.py reads now.

    winservice_py2exe.py

    from os.path import splitext, abspath
    from sys import modules, executable
    from time import *
    import win32serviceutil
    import win32service
    import win32event
    import win32api
    
    class Service(win32serviceutil.ServiceFramework):
        _svc_name_ = 'actualServiceName' #here is now the name you would input as an arg for instart
        _svc_display_name_ = 'actualDisplayName' #arg for instart
        _svc_description_ = 'actualDescription'# arg from instart
        def __init__(self, *args):
            win32serviceutil.ServiceFramework.__init__(self, *args)
            self.log('init')
            self.stop_event = win32event.CreateEvent(None, 0, 0, None)
    
        #logs into the system event log
    def log(self, msg):
        import servicemanager
        servicemanager.LogInfoMsg(str(msg))
    
    def sleep(self, minute):
            win32api.Sleep((minute*1000), True)
    def SvcDoRun(self):
        self.ReportServiceStatus(win32service.SERVICE_START_PENDING)
        try:
            self.ReportServiceStatus(win32service.SERVICE_RUNNING)
            self.log('start')
            self.start()
            self.log('wait')
            win32event.WaitForSingleObject(self.stop_event, win32event.INFINITE)
            self.log('done')
        except Exception, x:
            self.log('Exception : %s' % x)
            self.SvcStop()
    def SvcStop(self):
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        #self.log('stopping')
        self.stop()
        #self.log('stopped')
        win32event.SetEvent(self.stop_event)
        self.ReportServiceStatus(win32service.SERVICE_STOPPED)
    # to be overridden
    def start(self): pass
    # to be overridden
    def stop(self): pass
    
    if __name__ == '__main__':
         # Note that this code will not be run in the 'frozen' exe-file!!!
         win32serviceutil.HandleCommandLine(VidiagService) #added from example included with py2exe
    

    Below is the setup.py file i used with py2exe. This was taken from the example included with the py2exe installation:

    setup.py

    from distutils.core import setup
    import py2exe
    import sys
    if len(sys.argv) == 1:
        sys.argv.append("py2exe")
        sys.argv.append("-q")
    
    class Target:
        def __init__(self, **kw):
        self.__dict__.update(kw)
         # for the versioninfo resources
         self.version = "0.5.0"
         self.company_name = "No Company"
         self.copyright = "no copyright"
         self.name = "py2exe sample files"
    
     myservice = Target(
         # used for the versioninfo resource
         description = "A sample Windows NT service",
         # what to build.  For a service, the module name (not the
         # filename) must be specified!
         modules = ["winservice_py2exe"]
         )
    
     setup(
         options = {"py2exe": {"typelibs":
                          # typelib for WMI
                           [('{565783C6-CB41-11D1-8B02-00600806D9B6}', 0, 1, 2)],
                           # create a compressed zip archive
                           "compressed": 1,
                           "optimize": 2}},
         # The lib directory contains everything except the executables and the python dll.
         # Can include a subdirectory name.
         zipfile = "lib/shared.zip",
    
         service = [myservice]
        )
    

    once you create the exe you can install the service from command using the following command

    winservice_py2exe.exe -install
    

    then to start the service you can use:

     net start aTest
    

    or from windows service manager. All other windows command line functionality now works on the service as well as from windows service manager.

    • programmer
      programmer over 2 years
      what is use of setup.py ?
    • programmer
      programmer over 2 years
      when i give install command i get the error Failed to execute script
  • enthus1ast
    enthus1ast over 9 years
    This worked for me using pyinstaller. But why is it working withouth the if when installed as python file??
  • MrTorture
    MrTorture over 9 years
    Because PythonService.exe takes care of that.
  • Icode4food
    Icode4food almost 8 years
    When I use this with pyinstaller, the service starts and then immediately exits. Looking at the code, I would expect servicemanager.StartServiceCtrlDispatcher() to be a blocking call and to keep the process running, but this doesn't appear to be what is happening.
  • std''OrgnlDave
    std''OrgnlDave over 7 years
    Fixed it for me! Thanks!
  • mafrosis
    mafrosis over 6 years
    Any chance you could share a complete code listing?
  • BuvinJ
    BuvinJ over 6 years
    It's hard to know exactly where to start and end with this whole thing. There is a limit as to quite how much proprietary code I wish to give away. Please tell me what specific parts you are hung up and I'll help you along.
  • BuvinJ
    BuvinJ over 6 years
    Note: I posted some revisions to the code I already included, which handles pyInstaller v3 tweaks.
  • mafrosis
    mafrosis over 6 years
    Thanks for the updates. The constants WORKING_DIR_OPT_NAME, MAX_STATUS_CHANGE_CHECKS and STATUS_CHANGE_CHECK_DELAY are not defined. I can guess the value for the last two - but what is WORKING_DIR_OPT_NAME set to?
  • BuvinJ
    BuvinJ over 6 years
    Yeah the ones you are guessing at are arbitrary loop controls. I set WORKING_DIR_OPT_NAME = "workingDir". That's just a custom name. It's key shared between the win32serviceutil.ServiceFramework class and this WinServiceManager class. The service reads that value during init and sets the working directory it will use. Ultimately, I think that gets read from / written to the registry by some magic involved with Windows services.
  • BuvinJ
    BuvinJ over 6 years
    The other end of this (the service) includes these lines: (sorry I don't how to put a line break in an SO comment): servicename = args[0][0] followed by workingDir = win32serviceutil.GetServiceCustomOption( servicename, WORKING_DIR_OPT_NAME ) followed by os.chdir( workingDir )
  • BuvinJ
    BuvinJ over 6 years
    Since the function being invoke to retrieve the value is GetServiceCustomOption, that explains why I named the constant as I did.
  • BuvinJ
    BuvinJ over 6 years
    I realized I was missing another little pyInstaller v3 tweak, where the exe name is passed to this manager class, so I updated my post again. That whole part is really gross, but I must have needed that for some reason in my use case. This is another example of why my exact code is hard to post as a perfect generic solution.
  • mafrosis
    mafrosis over 6 years
    Thank you for this! I will try in the next few hours and let you know how it turns out.
  • mafrosis
    mafrosis over 6 years
    Can you explain why the whole isStandAloneContext stuff exists in there?
  • mafrosis
    mafrosis over 6 years
  • BuvinJ
    BuvinJ over 6 years
    @mafrosis in case you weren't aware, I posted another message to you in the chat yesterday, which might be of use.
  • programmer
    programmer over 2 years
    @MrTorture when i give install command i get the error Failed to execute script???