2014-09-10 17 views
15

Ich habe einen Windows-Dienst in Python geschrieben. Wenn ich mein Skript von der Eingabeaufforderung aus ausführenPython Windows Service Pyinstaller ausführbare Fehler 1053

Wenn ich dies tue, wird der Dienst ordnungsgemäß installiert und gestartet. Ich habe versucht, eine ausführbare Datei mit pyinstaller zu erstellen, weil ich das gleiche Problem mit py2exe gesehen habe. Wenn ich die .exe, aber der Service installiert startet nicht und ich erhalte die folgende Fehler

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

Ich habe gesehen, dass viele Leute dieses Problem gehabt haben, aber ich kann keine definitive Antwort auf die Frage, wie zu finden scheinen um das zu beheben.

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

Ich löste dieses Problem, indem py2exe verwenden, aber die gleichen Änderungen für pyinstaller zu können funktionieren. Ich hatte keine Zeit, das selbst zu überprüfen.

Ich musste die instart Funktion entfernen. Unten ist, wie meine winservice.py jetzt liest.

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 

Unten ist die setup.py Datei i mit py2exe verwendet. Dies wurde durch das Beispiel aus der py2exe Installation enthalten:

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] 
    ) 

, sobald Sie die exe erstellen können Sie den Dienst von Befehl mit dem folgenden Befehl

winservice_py2exe.exe -install 
installieren

dann, um den Dienst zu starten, den Sie verwenden können:

net start aTest 

oder vom Windows Service Manager. Alle anderen Windows-Befehlszeilenfunktionen funktionieren jetzt sowohl für den Dienst als auch für den Windows Service Manager.

Antwort

19

Versuchen Sie, die letzten paar Zeilen

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

Das funktionierte für mich mit Pyinstaller. Aber warum funktioniert es ohne das wenn wenn als Python-Datei installiert ?? – enthus1ast

+0

Weil PythonService.exe das erledigt. – MrTorture

+2

OP sollten Sie diese Antwort akzeptieren – arminb

2

MrTorture hatte den Schlüssel zu dieser Antwort zu ändern, aber ich würde auf das hier bauen möchte. Zu beachten ist, dass selbst bei Verwendung der Funktionen von win32serviceutil zur programmgesteuerten Verwaltung des Diensts (im Gegensatz zur Installation, zum Starten usw. über die Eingabeaufforderung) die Eingabeaufforderung für die Befehlszeile eingeschlossen werden muss, damit sie in einem eigenständigen Kontext funktioniert beim Erstellen einer exe mit pyinstaller oder py2exe). Wenn Sie dies nicht tun, kann Windows den Dienst nicht starten. Sie werden den gefürchteten Fehler 1053 bekommen!

Beachten Sie außerdem, dass Sie, wenn Sie einen Dienst als Teil eines größeren Projekts erstellen, eine exe für den Dienst erstellen müssen.Sie können es nicht als Sub-Komponente innerhalb einer größeren exe ausführen (zumindest hatte ich kein Glück zu versuchen!). Ich habe meine Installationsfunktion hinzugefügt, um das zu demonstrieren.

Auch bei der Verwendung von .py-Skripts, die über pythonservice.exe verwaltet werden, ist keines dieser Probleme vorhanden, dies betrifft nur Standalone-Exes.

Hier sind einige INCOMPLETE Schnipsel meines funktionalen Code, aber sie könnten Sie eine Menge Ärger sparen:

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   

Im Modul, in dem Sie Ihren Dienst zu definieren (von win32serviceutil.ServiceFramework abgeleitet), sind dies bei das Ende davon:

if __name__ == "__main__": 
    WinServiceManager(MyServiceClass, "MyServiceBinary.exe").dispatch() 
+0

Sie könnten eine vollständige Code-Liste teilen? – mafrosis

+0

Es ist schwer zu wissen, wo genau mit dieser ganzen Sache zu beginnen und zu enden ist. Es gibt eine Grenze bezüglich ziemlich, wieviel proprietärer Code ich verschenken möchte. Bitte sag mir, welche Teile du aufgehängt hast und ich helfe dir weiter. – BuvinJ

+0

Hinweis: Ich habe einige Änderungen an dem bereits enthaltenen Code gepostet, der pyInstaller v3-Tweaks behandelt. – BuvinJ

Verwandte Themen