【问题标题】:Windows service startup : how to avoid Error 1053: The service did not respond to the start or control request in a timely fashionWindows服务启动:如何避免错误1053:服务没有及时响应启动或控制请求
【发布时间】:2017-12-13 15:56:59
【问题描述】:

我有一个 C++ 编写的 Windows 服务,在启动时,如果 SERVICE_STATUSSERVICE_START_PENDING 中停留的时间过长,我最终会出现此错误:

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

当进度条对话框保持打开状态时会发生这种情况。它不会影响服务启动本身。服务会在SERVICE_START_PENDING继续,直到工作完成,我设置SERVICE_RUNNING

dwWaitHint 上的 Windows 文档在这里:

https://msdn.microsoft.com/en-us/library/windows/desktop/ms685996(v=vs.85).aspx

声明服务必须在 dwWaitHint 时间过去之前以递增的 dwCheckPoint 调用 SetServiceStatus

例如,我将 dwWaitHint 设置为 5 分钟,并每隔 10 秒调用一次 SetServiceStatus,并增加 dwCheckPoint,但 5 分钟后我仍然收到 1053 错误。换句话说,SetServiceStatus 调用似乎没有做任何事情。 (我检查了这些电话并没有失败)。

通过上述操作,服务启动时间不能比dwWaitHint更长吗???

更新:我可以使用 Microsoft 的服务示例代码进行重现。这是一个sn-p。

{
    gSvcStatus.dwServiceType = SERVICE_WIN32_OWN_PROCESS; 
    gSvcStatus.dwServiceSpecificExitCode = 0;    

    // Report initial status to the SCM
    ReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 300000 );

    int limit = 6;  // 6 minutes total
    while(limit--)
    {
        Sleep(60000); // sleep 1 min
        ReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 300000 );  // 5 minute dwWaitHint
    }

    // We've completed startup, report RUNNING to SCM
    ReportSvcStatus( SERVICE_RUNNING, NO_ERROR, 0 );

}

VOID ReportSvcStatus( DWORD dwCurrentState, DWORD dwWin32ExitCode, DWORD dwWaitHint)
{
    static DWORD dwCheckPoint = 1;

    // Fill in the SERVICE_STATUS structure.

    gSvcStatus.dwCurrentState = dwCurrentState;
    gSvcStatus.dwWin32ExitCode = dwWin32ExitCode;
    gSvcStatus.dwWaitHint = dwWaitHint;

    if (dwCurrentState == SERVICE_START_PENDING)
        gSvcStatus.dwControlsAccepted = 0;
    else gSvcStatus.dwControlsAccepted = SERVICE_ACCEPT_STOP;

    if ( (dwCurrentState == SERVICE_RUNNING) ||
           (dwCurrentState == SERVICE_STOPPED) )
        gSvcStatus.dwCheckPoint = 0;
    else gSvcStatus.dwCheckPoint = dwCheckPoint++;

    // Report the status of the service to the SCM.
    SetServiceStatus( gSvcStatusHandle, &gSvcStatus );
}

【问题讨论】:

  • 请出示您的实际代码。我已经编写了几个服务,SetServiceStatus() 按文档说明工作,因此您实际上可能没有正确使用它。不要描述你的代码,展示它。
  • 我刚刚添加了一些代码。我可以用微软的示例服务代码重现。我将 dwWaitHint 设置为 5 分钟(每次调用 SetServiceStatus 时),但我总共工作了 6 分钟。 (1 分钟 x 6,每次在迭代之间调用 SetServiceStatus)。 5 分钟后我收到超时错误,即使服务一直运行到完成。也许解决方案是每次调用 SetServiceStatus 时增加 dwWaitHint
  • 一开始 - 为什么不简化代码呢?对于 2 用 SERVICE_START_PENDING 调用 ReportSvcStatus 而不是这个:do { ReportSvcStatus( SERVICE_START_PENDING, NO_ERROR, 4000 ); Sleep(2000); } while(--limit); i 进行测试的时间间隔相对较小 - 4 秒等待提示并每 2 秒更新一次状态。而是固定条件while(--limit) 甚至更好地用于测试集,例如while (!IsDebuggerPresent()); 在我的测试中所有正确的与services.exe 一起使用。 Error 1053: 仅显示 gui shell - mmc.exe 中的服务管理单元。
  • 但这只是这个实用程序的糟糕设计,并不重要。重要的是services.exe对此有何反应

标签: winapi windows-services


【解决方案1】:

您确定将 dwWaitHint 视为毫秒而不是秒? (即你的 dwWaitHint 是 300000?)

我的经验是文档在这一点上是正确的,等待提示仅适用于下一个 SetServiceStatus 调用。

虽然我也想说 5 分钟的服务启动时间太长了,即使加载或检查数据实际上需要很长时间。我之所以这么说,主要是因为服务控制界面一直卡住。例如,即使在需要数小时验证的系统崩溃之后,SQLServer 也能快速启动服务。

【讨论】:

  • 是的,它设置为 300000。如果我将其增加到更大的值,那么我就可以解决问题。但它并没有解决为什么 SetServiceStatus 没有按照文档所说的那样做的问题。至于漫长的开始时间,这是现实,应该不重要。
  • 是的,5 分钟的启动时间太长了。不要这样做。服务应尽快启动和关闭,不要长时间阻塞单片机。并且 SCM 在启动/停止服务时确实有它愿意等待的最大超时时间,即使在使用 dwWaitHintdwCheckPoint 时也是如此。因此,请快速报告您的服务报告SERVICE_RUNNING,并在单独的线程中进行长时间启动。
  • 我没有阻止 SCM。 SetServiceStatus 调用在单独的线程中进行。除了避免这些 SCM 超时问题外,没有任何正当理由要保持启动时间短。 (为什么说它正在运行,而实际上它不是......)再次,我正在做微软文档建议做的事情。我正在使用他们的“完整服务样本”组合一个测试用例,看看我是否也可以用它来重现。
  • "我没有阻止 SCM" - 是的,你是。 SCM 在启动服务时,会等待服务进入SERVICE_RUNNINGSERVICE_STOPPED 状态。只要您报告SERVICE_START_PENDING,它就会一直等待,直到最大超时(在您的情况下,这似乎是 5 分钟)。您不能让 SCM 无限期等待,它会超时并记录错误。 “初始化”和“运行”是有区别的。你不必在后者之前做前者,特别是如果前者需要很长时间。您可以在完成初始化之前进入“运行”状态
  • 因为我设置的 dwWaitTime 是 5 分钟。同样,从服务启动的角度来看,这很好用。进度条对话框在“填满”时会引发错误。如果我增加 dwWaitTime,它会延迟进度条填充并绕过错误。或者,如果我关闭进度条对话框,则没有问题。我仍然认为这是关于 dwCheckpoint 和 dwWaitHint 如何工作的 Windows 错误和/或文档错误 ....
【解决方案2】:

嗯,Microsoft 管理控制台 (MMC) 服务管理单元肯定有限制,特别是这里的对话框:

在此处查看 MS 的此链接:

https://support.microsoft.com/en-ca/help/307806/the-services-snap-in-times-out-with-error-1053

当启动任何控制操作时,服务管理单元会显示一个进度对话框,标题为“服务控制”。如果服务需要大量时间来处理操作,则进度条将随着服务管理单元等待操作完成而缓慢增加。 125 秒后,进度条将满,服务管理单元将显示错误 1053 (ERROR_SERVICE_REQUEST_TIMEOUT) 消息。即使出现错误消息,服务进程本身也会照常运行。

但是,好消息是我已经证明这个 125 秒的陈述是错误的,至少在 Windows 10 上是这样(没有尝试过其他 Windows 版本)。如我的问题所述,在设置SERVICE_START_PENDING 时,您可以将dwWaitHint 设置为更高的值,并且进度条会尊重这一点。但是,您只有 1 次机会,如果您随后通过将 SetServiceStatus 调用更高的 dwWaitHint 来更新 SERVICE_START_PENDING,则不会影响进度条对话框。

dwWaitHint设置得很高的唯一缺点是进度条会变慢,而当您设置SERVICE_RUNNING状态时,进度条可能只是一半。但没什么大不了的,只是美观而已。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-12-20
    • 2011-03-28
    • 2014-08-05
    • 2011-01-05
    • 2011-12-29
    • 2014-07-02
    • 1970-01-01
    相关资源
    最近更新 更多