Browse Source

Allow slow service startup again.

Previously we enforced a maximum delay in reporting to the service
manager that the service was started, and waited for the application to
become unthrottled in the background.

Users may prefer that the service not report a started state until the
application is unthrottled.  Therefore we now loop and increment the
status checkpoint and wait hint to satisfy the service manager that we
aren't hung.

Thanks Tom Saul.
Iain Patterson 7 years ago
parent
commit
85fe241fc7
2 changed files with 38 additions and 10 deletions
  1. 37 10
      service.cpp
  2. 1 0
      service.h

+ 37 - 10
service.cpp

@@ -1394,6 +1394,7 @@ void WINAPI service_main(unsigned long argc, TCHAR **argv) {
     if (services) {
       service->handle = open_service(services, service->name, SERVICE_CHANGE_CONFIG, 0, 0);
       set_service_recovery(service);
+
       CloseServiceHandle(services);
     }
   }
@@ -1687,16 +1688,7 @@ int start_service(nssm_service_t *service) {
     but be mindful of the fact that we are blocking the service control manager
     so abandon the wait before too much time has elapsed.
   */
-  unsigned long delay = service->throttle_delay;
-  if (delay > NSSM_SERVICE_STATUS_DEADLINE) {
-    TCHAR delay_milliseconds[16];
-    _sntprintf_s(delay_milliseconds, _countof(delay_milliseconds), _TRUNCATE, _T("%lu"), delay);
-    TCHAR deadline_milliseconds[16];
-    _sntprintf_s(deadline_milliseconds, _countof(deadline_milliseconds), _TRUNCATE, _T("%lu"), NSSM_SERVICE_STATUS_DEADLINE);
-    log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_STARTUP_DELAY_TOO_LONG, service->name, delay_milliseconds, NSSM, deadline_milliseconds, 0);
-    delay = NSSM_SERVICE_STATUS_DEADLINE;
-  }
-  unsigned long deadline = WaitForSingleObject(service->process_handle, delay);
+  await_startup(service);
 
   /* Signal successful start */
   service->status.dwCurrentState = SERVICE_RUNNING;
@@ -1985,3 +1977,38 @@ awaited:
 
   return ret;
 }
+
+int await_startup(nssm_service_t *service) {
+  unsigned long interval;
+  unsigned long waithint;
+  unsigned long waited;
+
+  waithint = service->status.dwWaitHint;
+  waited = 0;
+  while (waited < service->throttle_delay) {
+    interval = service->throttle_delay - waited;
+    if (interval > NSSM_SERVICE_STATUS_DEADLINE) interval = NSSM_SERVICE_STATUS_DEADLINE;
+
+    service->status.dwCurrentState = SERVICE_START_PENDING;
+    service->status.dwWaitHint += interval;
+    service->status.dwCheckPoint++;
+    SetServiceStatus(service->status_handle, &service->status);
+
+    switch (WaitForSingleObject(service->process_handle, interval)) {
+      case WAIT_OBJECT_0:
+        return 1;
+
+      case WAIT_TIMEOUT:
+      break;
+
+      default:
+        return -1;
+    }
+
+    waited += interval;
+  }
+
+  service->throttle = 0;
+
+  return 0;
+}

+ 1 - 0
service.h

@@ -146,5 +146,6 @@ int stop_service(nssm_service_t *, unsigned long, bool, bool);
 void CALLBACK end_service(void *, unsigned char);
 void throttle_restart(nssm_service_t *);
 int await_shutdown(nssm_service_t *, TCHAR *, unsigned long);
+int await_startup(nssm_service_t *);
 
 #endif