Python Windows服务“启动服务错误:服务没有及时响应启动或控制请求”

49

我正在运行以下代码:python win_service.py install,但在普通命令提示符中遇到“访问被拒绝”的错误。

正在安装服务 TestService

安装服务时出错:拒绝访问。(5)

当我以管理员身份启动命令提示符时,我能够解决这个问题。

我已经成功安装了该服务,但无法启动该服务。

服务已安装

正在启动服务 TestService

启动服务时发生错误:服务未能及时响应启动或控制请求。

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):
        print "running"

if __name__ == '__main__':
    win32serviceutil.HandleCommandLine(AppServerSvc)

我做错了什么?有没有其他安装服务的方法可以解决这个问题,并且如何以管理员身份动态运行它。

10个回答

38

我知道这个已经有点老了,但我一直被困扰着。对我来说,这个具体问题是通过复制这个文件得到解决的 - pywintypes36.dll

从 -> Python36\Lib\site-packages\pywin32_system32

到 -> Python36\Lib\site-packages\win32


1
我曾经遇到过同样的问题,而这个步骤解决了它。我之前也见过这种情况,但是没有记住。 - Dariva
老而确实经典 - CodeGuru

11

你的服务可能无法启动是因为找不到可执行文件。我曾经遇到过类似的问题,通过将一些与pywin32相关的目录添加到系统路径中解决了这个问题。您可以使用setx命令来完成此操作:

setx /M PATH "%PATH%;C:\Python27;C:\Python27\Scripts;C:\Python27\Lib\site-packages\pywin32_system32;C:\Python27\Lib\site-packages\win32"

请在具有管理员权限的cmd窗口中运行此命令,并调整路径以匹配您自己的Python安装。


2
如果您在开发中使用虚拟环境,并且主 Python 安装中未安装 pywin32_systemwin32 包,则还需要执行类似于此操作。 - Alice Heaton
将路径添加到pywin32_system32会阻止Python命令。 - Eli Borodach

7

终于,这个问题有了解决方案。

第一步:

使用pyinstaller创建一个独立的可执行文件,即:

  pip install pyinstaller

  pyinstaller yourproject.py

  cd dist\yourproject

  yourproject.exe install

第二步:

请注意,当Windows服务调用“你的程序”时,它会根据服务开发协议给出回答时间。以上所有代码都没有启动服务。请按照以下方式更改您的代码:

if __name__ == '__main__':
   if len(sys.argv) > 1:
       # Called by Windows shell. Handling arguments such as: Install, Remove, etc.
       win32serviceutil.HandleCommandLine(JobManager)
   else:
       # Called by Windows Service. Initialize the service to communicate with the system operator
       servicemanager.Initialize()
       servicemanager.PrepareToHostSingle(JobManager)
       servicemanager.StartServiceCtrlDispatcher()

1
嘿,陌生人,经过一天的困境后,这是解决方案 <3 - Freddy
非常感谢您的努力,经过三天的奋斗,终于…… - Mani
2
在这种情况下,“JobManager”是什么? - MrDysprosium
@MrDysprosium JobManager将是您实现逻辑的win32serviceutil.ServiceFramework子类。对于OP的片段,它应该是AppServerSvc - PythonPro

5
编辑:如我在下面的评论中所提到的,这在pyWin32 305及更高版本中不再需要,它会自动将pythonservice.exe复制到sys.exec_prefix(即:如果您有一个虚拟环境,则在其中)并从那里运行。
dsloskythis answer to a linked question所暗示的,pythonservice.exe将作为一个“系统”服务运行,因此它将拥有与您作为用户不同的环境。运行python service.py debug将正常运行,因为它仍然在您的用户环境下运行,但是如果您运行python service.py start,由于环境变量的差异,它很可能会失败。您的服务立即超时很可能是由于pythonservice.exe无法执行,并且如果缺少PythonXX.dllpywintypesXX.dll,它将无法执行。

PythonXX.dll很可能已经在您的系统路径中(取决于Python的安装方式),但是如果您在同一系统上使用多个Python版本并且尝试避免更改环境(就像我不幸的那样),那将是一个问题。我希望通过运行类似于.\.pyenv37\Scripts\python.exe service.py start的命令来使用venv,这对于定期运行的常规Python脚本是有效的,但是您必须记住service.py start只是命令Windows启动服务。实际的服务可执行文件pythonservice.exe将从PATH变量中解析Python37.dll,而不是我在运行service.py start时使用的venv。这意味着当pythonservice.exe作为系统服务开始运行时,Python37.dll将不再被识别,即使我在用户PATH中有Python37.dll,因为它现在正在使用系统PATH运行。由于pythonservice.exe无法在没有Python37.dll的情况下运行,这会导致立即的链接错误,并且Windows将其报告为即时超时。

同样适用于pywintypesXX.dll(如果找不到它,pythonservice.exe将立即超时),但与其在搜索路径中的某个位置安装它,更便携的解决方案是将其放在与pythonservice.exe相同的目录中,因为默认的DLL搜索路径包括它
编辑:这是我用来验证脚本安装/更新的内容:
# customOptionHandler will only run after service install/update
if __name__=='__main__':
    win32serviceutil.HandleCommandLine(AppServerSvc, customOptionHandler=post_service_update)

.

def post_service_update(*args):
    import win32api, win32con, win32profile, pywintypes
    from contextlib import closing

    env_reg_key = "SYSTEM\\CurrentControlSet\\Control\\Session Manager\\Environment"
    hkey = win32api.RegOpenKeyEx(win32con.HKEY_LOCAL_MACHINE, env_reg_key, 0, win32con.KEY_ALL_ACCESS)

    with closing(hkey):
        system_path = win32api.RegQueryValueEx(hkey, 'PATH')[0]
        # PATH may contain %SYSTEM_ROOT% or other env variables that must be expanded
        # ExpandEnvironmentStringsForUser(None) only expands System variables
        system_path = win32profile.ExpandEnvironmentStringsForUser(None, system_path)
        system_path_list = system_path.split(os.pathsep)

        core_dll_file = win32api.GetModuleFileName(sys.dllhandle)
        core_dll_name = os.path.basename(core_dll_file)

        for search_path_dir in system_path_list:
            try:
                dll_path = win32api.SearchPath(search_path_dir, core_dll_name)[0]
                print(f"System python DLL: {dll_path}")
                break
            except pywintypes.error as ex:
                if ex.args[1] != 'SearchPath': raise
                continue
        else:
            print("*** WARNING ***")
            print(f"Your current Python DLL ({core_dll_name}) is not in your SYSTEM PATH")
            print("The service is likely to not launch correctly.")

    from win32serviceutil import LocatePythonServiceExe
    pythonservice_exe = LocatePythonServiceExe()
    pywintypes_dll_file = pywintypes.__spec__.origin

    pythonservice_path = os.path.dirname(pythonservice_exe)
    pywintypes_dll_name = os.path.basename(pywintypes_dll_file)

    try:
        return win32api.SearchPath(pythonservice_path, pywintypes_dll_name)[0]
    except pywintypes.error as ex:
        if ex.args[1] != 'SearchPath': raise
        print("*** WARNING ***")
        print(f"{pywintypes_dll_name} is not is the same directory as pythonservice.exe")
        print(f'Copy "{pywintypes_dll_file}" to "{pythonservice_path}"')
        print("The service is likely to not launch correctly.")

虽然看起来很多,但至少可以避免在部署服务到新的机器/虚拟环境或更新Python时忘记执行这些步骤。

请注意,pyWin32 303(2021年12月)具有类似于此的内置检查,并且从pyWin32 305(2022年11月)开始,如果缺少正确的文件,则库存服务注册过程已进行了全面改进以自动复制它们。希望这意味着整个问题将不再出现。 - VLRoyrenn

2
在开始调试之前,我建议确保完成了以下两个步骤,详情请参考https://github.com/mhammond/pywin32
pip install pywin32

并且

python Scripts/pywin32_postinstall.py -install

完成了。

2
我也曾经遇到过同样的问题,但是在折腾了4天之后,最终我找到了解决方案
所以,以下是逐步指南:https://github.com/PushpenderIndia/PythonWindowsService 同时也在此发布相同的解决方案。

创建 Python Windows 服务的步骤

(1) 将这些代码复制粘贴到一个 Python 文件中(例如 server.py)

import servicemanager
import sys
import win32serviceutil
from mainserver import FlaskServer   # Import your code, I've written a module called mainserver which contains FlaskServer Code using OOPs
import threading
import concurrent.futures
import time

class workingthread(threading.Thread):
    def __init__(self, quitEvent):
        self.quitEvent = quitEvent
        self.waitTime = 1
        threading.Thread.__init__(self)

    def run(self):
        try:
            # Running start_flask() function on different thread, so that it doesn't blocks the code
            executor = concurrent.futures.ThreadPoolExecutor(max_workers=5)
            executor.submit(self.start_flask)
        except:
            pass

        # Following Lines are written so that, the program doesn't get quit
        # Will Run a Endless While Loop till Stop signal is not received from Windows Service API
        while not self.quitEvent.isSet():  # If stop signal is triggered, exit
            time.sleep(1)

    def start_flask(self):
        # This Function contains the actual logic, of windows service
        # This is case, we are running our flaskserver
        test = FlaskServer()
        test.start()

class FlaskService(win32serviceutil.ServiceFramework):
    _svc_name_ = "AA Testing"
    _svc_display_name_ = "AAA Testing"
    _svc_description_ = "This is my service"

    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.hWaitStop = threading.Event()
        self.thread = workingthread(self.hWaitStop)

    def SvcStop(self):
        self.hWaitStop.set()

    def SvcDoRun(self):
        self.thread.start()
        self.hWaitStop.wait()
        self.thread.join()


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

(2) 安装最新的pywin32.exe

  • 注意:如果您使用pip安装pywin32,则可能无法正确安装,从而会显示一些错误信息。
  • 请访问https://github.com/mhammond/pywin32/releases
  • 下载最新的exe文件,如果您正在使用Python 32位,则下载pywin32-302.win32-py3.x.exe
  • 如果使用Python 64位,则下载pywin32-302.win-amd64-py3.x.exe

(3) 使用pyinstaller编译您的server.py文件

  • 编译服务可执行文件
C:\Users\Pushpender\Desktop> python -m pip install servicemanager
C:\Users\Pushpender\Desktop> pyinstaller --onefile server.py --hidden-import=win32timezone --clean --uac-admin
  • 安装和运行服务可执行文件(以管理员身份运行CMD)
C:\WINDOWS\system32>cd C:\Users\Pushpender\Desktop>
C:\WINDOWS\system32>d:
C:\Users\Pushpender\Desktop>server.exe --startup=auto install       # Installing service with startup == Automatic    
C:\Users\Pushpender\Desktop>server.exe start    # For starting service (You can start from Windows Service or From Task Manager)
C:\Users\Pushpender\Desktop>server.exe stop     # For stopping service (You can stop from Windows Service or From Task Manager)
C:\Users\Pushpender\Desktop>server.exe remove   # For removing installed service

(4) 您可以直接运行server.py而无需编译(以管理员身份运行CMD)

C:\WINDOWS\system32>cd C:\Users\Pushpender\Desktop>
C:\WINDOWS\system32>d:
C:\Users\Pushpender\Desktop>python server.py --startup=auto install   # Installing service with startup == Automatic   
C:\Users\Pushpender\Desktop>python server.py start     # For starting service (You can start from Windows Service or From Task Manager)
C:\Users\Pushpender\Desktop>python server.py stop      # For stopping service (You can stop from Windows Service or From Task Manager)
C:\Users\Pushpender\Desktop>python server.py remove    # For removing installed service

注意:

  • You can tweak the above code, for example, you can change the following things

      _svc_display_name_ = "AAA Testing"
      _svc_description_ = "This is my service"
    
  • Also you can change the classes names of FlaskService , workingthread

  • Please change this line in your code from mainserver import FlaskServer

  • You can change the startup type to lots of things, type server.exe --help in order to know more about settings

  • If you want to set the StartUp= Manaull, then don't use --startup=auto, while installing service

  • If you want to set the StartUp= Automatic (Delayed), then use --startup=delayed, while installing service

  • Use --startup argument before install argument

(4) 将Windows服务器与Inno Setup Builder集成

  • 如果您想要创建一个安装程序,在安装过程中安装您的服务,并在卸载时删除它,则需要:
  • 将以下代码块添加到您的script.iss文件中:
[Run]
Filename: "{app}\{#MyAppExeName}"; StatusMsg: "Installing Windows Service ... "; Parameters: "--startup=delayed install";  Flags: runhidden waituntilterminated  
Filename: "{app}\{#MyAppExeName}"; StatusMsg: "Running Windows Service ... "; Parameters: "start";  Flags: runhidden waituntilterminated

[UninstallRun]
Filename: "{app}\{#MyAppExeName}"; Parameters: "remove";  Flags: runhidden

你能在这个里面运行一个套接字服务器吗? - Shashankh_

1
请确保您使用的是与默认本地系统用户不同的用户运行应用程序。将其替换为您成功运行调试命令的用户。
  • 要更改用户,请转到Windows服务(开始 > services.msc)
  • 右键单击创建的服务 > 属性 > 登录
  • 取消选中本地系统帐户并输入您自己的帐户。

所有Python Windows服务都无法启动{错误1053}对我有用。

因为我只为用户登录设置了PATH,而不是系统。您可以重新检查系统变量的PATH。


非常感谢,我使用管理员登录成功了,这对我有用。1053已经消失了。 - rogers.wang

1

完美运行。节省时间。 - Hammad Hassan

0
如果您在Windows上使用嵌入式Python(便携式Python),请将文件夹添加到路径中。
C:\[...]\python-3.9.5-embed-amd64

这在我的情况下解决了问题。


0
请确保以下路径已添加到您的系统变量路径中。以下路径适用于Python 3.7,请根据您安装的Python版本添加路径。
C:\Users\1022226\AppData\Local\Programs\Python\Python37\Scripts C:\Users\1022226\AppData\Local\Programs\Python\Python37

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接