Browse Source

Allow configuring throttling threshold.

Tweak minimum time for which a service must run by setting the threshold
number of milliseconds in AppThrottle (REG_DWORD).
Iain Patterson 11 years ago
parent
commit
8d855fdbce
6 changed files with 43 additions and 8 deletions
  1. 5 0
      README.txt
  2. 7 0
      messages.mc
  3. 1 1
      nssm.h
  4. 23 2
      registry.cpp
  5. 2 1
      registry.h
  6. 5 4
      service.cpp

+ 5 - 0
README.txt

@@ -79,6 +79,11 @@ of the failure and don't want to wait you can use the Windows service console
 (where the service will be shown in Paused state) to send a continue signal to
 NSSM and it will retry within a few seconds.
 
+By default, NSSM defines "a timely manner" to be within 1500 milliseconds.
+You can change the threshold for the service by setting the number of
+milliseconds as a REG_DWORD value in the registry at
+HKLM\SYSTEM\CurrentControlSet\Services\<service>\Parameters\AppThrottle.
+
 NSSM will look in the registry under
 HKLM\SYSTEM\CurrentControlSet\Services\<service>\Parameters\AppExit for
 string (REG_EXPAND_SZ) values corresponding to the exit code of the application.

+ 7 - 0
messages.mc

@@ -274,3 +274,10 @@ Language = English
 Request to resume service %1.  Throttling of restart attempts will be reset.
 .
 
+MessageId = +1
+SymbolicName = NSSM_EVENT_BOGUS_THROTTLE
+Severity = Warning
+Language = English
+The registry value %2, used to specify the minimum number of milliseconds which must elapse before service %1 is considered to have started successfully, was not of type REG_DWORD.  The default time of %3 milliseconds will be used.
+.
+

+ 1 - 1
nssm.h

@@ -35,7 +35,7 @@ int str_equiv(const char *, const char *);
 
 /*
   Throttle the restart of the service if it stops before this many
-  milliseconds have elapsed since startup.
+  milliseconds have elapsed since startup.  Override in registry.
 */
 #define NSSM_RESET_THROTTLE_RESTART 1500
 

+ 23 - 2
registry.cpp

@@ -142,7 +142,9 @@ int expand_parameter(HKEY key, char *value, char *data, unsigned long datalen, b
   return 0;
 }
 
-int get_parameters(char *service_name, char *exe, int exelen, char *flags, int flagslen, char *dir, int dirlen) {
+int get_parameters(char *service_name, char *exe, int exelen, char *flags, int flagslen, char *dir, int dirlen, unsigned long *throttle_delay) {
+  unsigned long ret;
+
   /* Get registry */
   char registry[KEY_LENGTH];
   if (_snprintf(registry, sizeof(registry), NSSM_REGISTRY, service_name) < 0) {
@@ -180,7 +182,7 @@ int get_parameters(char *service_name, char *exe, int exelen, char *flags, int f
     }
     else {
       /* Help! */
-      unsigned long ret = GetWindowsDirectory(dir, dirlen);
+      ret = GetWindowsDirectory(dir, dirlen);
       if (! ret || ret > dirlen) {
         log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_NO_DIR_AND_NO_FALLBACK, NSSM_REG_DIR, service_name, 0);
         RegCloseKey(key);
@@ -190,6 +192,25 @@ int get_parameters(char *service_name, char *exe, int exelen, char *flags, int f
     log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_NO_DIR, NSSM_REG_DIR, service_name, dir, 0);
   }
 
+  /* Try to get throttle restart delay */
+  unsigned long type = REG_DWORD;
+  unsigned long buflen = sizeof(*throttle_delay);
+  bool throttle_ok = false;
+  ret = RegQueryValueEx(key, NSSM_REG_THROTTLE, 0, &type, (unsigned char *) throttle_delay, &buflen);
+  if (ret != ERROR_SUCCESS) {
+    if (ret != ERROR_FILE_NOT_FOUND) {
+      if (type != REG_DWORD) {
+        char milliseconds[16];
+        _snprintf(milliseconds, sizeof(milliseconds), "%lu", NSSM_RESET_THROTTLE_RESTART);
+        log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_BOGUS_THROTTLE, service_name, NSSM_REG_THROTTLE, milliseconds, 0);
+      }
+      else log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_QUERYVALUE_FAILED, NSSM_REG_THROTTLE, error_string(GetLastError()), 0);
+    }
+  }
+  else throttle_ok = true;
+
+  if (! throttle_ok) *throttle_delay = NSSM_RESET_THROTTLE_RESTART;
+
   /* Close registry */
   RegCloseKey(key);
 

+ 2 - 1
registry.h

@@ -6,12 +6,13 @@
 #define NSSM_REG_FLAGS "AppParameters"
 #define NSSM_REG_DIR "AppDirectory"
 #define NSSM_REG_EXIT "AppExit"
+#define NSSM_REG_THROTTLE "AppThrottle"
 
 int create_messages();
 int create_parameters(char *, char *, char *, char *);
 int create_exit_action(char *, const char *);
 int expand_parameter(HKEY, char *, char *, unsigned long, bool);
-int get_parameters(char *, char *, int, char *, int, char *, int);
+int get_parameters(char *, char *, int, char *, int, char *, int, unsigned long *);
 int get_exit_action(char *, unsigned long *, unsigned char *, bool *);
 
 #endif

+ 5 - 4
service.cpp

@@ -10,6 +10,7 @@ char exe[EXE_LENGTH];
 char flags[CMD_LENGTH];
 char dir[MAX_PATH];
 bool stopping;
+unsigned long throttle_delay;
 CRITICAL_SECTION throttle_section;
 CONDITION_VARIABLE throttle_condition;
 
@@ -199,7 +200,7 @@ void WINAPI service_main(unsigned long argc, char **argv) {
   }
 
   service_status.dwCurrentState = SERVICE_START_PENDING;
-  service_status.dwWaitHint = NSSM_RESET_THROTTLE_RESTART + NSSM_WAITHINT_MARGIN;
+  service_status.dwWaitHint = throttle_delay + NSSM_WAITHINT_MARGIN;
   SetServiceStatus(service_handle, &service_status);
 
   /* Try to create the exit action parameters; we don't care if it fails */
@@ -294,7 +295,7 @@ int start_service() {
   ZeroMemory(&pi, sizeof(pi));
 
   /* Get startup parameters */
-  int ret = get_parameters(service_name, exe, sizeof(exe), flags, sizeof(flags), dir, sizeof(dir));
+  int ret = get_parameters(service_name, exe, sizeof(exe), flags, sizeof(flags), dir, sizeof(dir), &throttle_delay);
   if (ret) {
     log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_GET_PARAMETERS_FAILED, service_name, 0);
     return stop_service(2, true, true);
@@ -321,7 +322,7 @@ int start_service() {
   SetServiceStatus(service_handle, &service_status);
 
   /* Wait for a clean startup. */
-  if (WaitForSingleObject(process_handle, NSSM_RESET_THROTTLE_RESTART) == WAIT_TIMEOUT) throttle = 0;
+  if (WaitForSingleObject(process_handle, throttle_delay) == WAIT_TIMEOUT) throttle = 0;
 
   return 0;
 }
@@ -449,7 +450,7 @@ void throttle_restart() {
   if (throttle > 7) throttle = 8;
 
   char threshold[8], milliseconds[8];
-  _snprintf(threshold, sizeof(threshold), "%d", NSSM_RESET_THROTTLE_RESTART);
+  _snprintf(threshold, sizeof(threshold), "%d", throttle_delay);
   _snprintf(milliseconds, sizeof(milliseconds), "%d", ms);
   log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_THROTTLED, service_name, threshold, milliseconds, 0);