Allow configuring throttling threshold.
authorIain Patterson <me@iain.cx>
Sat, 26 Feb 2011 12:39:43 +0000 (12:39 +0000)
committerIain Patterson <me@iain.cx>
Sat, 26 Feb 2011 12:39:43 +0000 (12:39 +0000)
Tweak minimum time for which a service must run by setting the threshold
number of milliseconds in AppThrottle (REG_DWORD).

README.txt
messages.mc
nssm.h
registry.cpp
registry.h
service.cpp

index 1bf8ab9..3b8f25c 100644 (file)
@@ -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\r
 NSSM and it will retry within a few seconds.\r
 \r
+By default, NSSM defines "a timely manner" to be within 1500 milliseconds.\r
+You can change the threshold for the service by setting the number of\r
+milliseconds as a REG_DWORD value in the registry at\r
+HKLM\SYSTEM\CurrentControlSet\Services\<service>\Parameters\AppThrottle.\r
+\r
 NSSM will look in the registry under\r
 HKLM\SYSTEM\CurrentControlSet\Services\<service>\Parameters\AppExit for\r
 string (REG_EXPAND_SZ) values corresponding to the exit code of the application.\r
index 5e5f184..41586ba 100644 (file)
@@ -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.
+.
+
diff --git a/nssm.h b/nssm.h
index 602c0c9..e10ee5c 100644 (file)
--- a/nssm.h
+++ b/nssm.h
@@ -35,7 +35,7 @@ int str_equiv(const char *, const char *);
 \r
 /*\r
   Throttle the restart of the service if it stops before this many\r
-  milliseconds have elapsed since startup.\r
+  milliseconds have elapsed since startup.  Override in registry.\r
 */\r
 #define NSSM_RESET_THROTTLE_RESTART 1500\r
 \r
index 15ee152..1be5f4d 100644 (file)
@@ -142,7 +142,9 @@ int expand_parameter(HKEY key, char *value, char *data, unsigned long datalen, b
   return 0;\r
 }\r
 \r
-int get_parameters(char *service_name, char *exe, int exelen, char *flags, int flagslen, char *dir, int dirlen) {\r
+int get_parameters(char *service_name, char *exe, int exelen, char *flags, int flagslen, char *dir, int dirlen, unsigned long *throttle_delay) {\r
+  unsigned long ret;\r
+\r
   /* Get registry */\r
   char registry[KEY_LENGTH];\r
   if (_snprintf(registry, sizeof(registry), NSSM_REGISTRY, service_name) < 0) {\r
@@ -180,7 +182,7 @@ int get_parameters(char *service_name, char *exe, int exelen, char *flags, int f
     }\r
     else {\r
       /* Help! */\r
-      unsigned long ret = GetWindowsDirectory(dir, dirlen);\r
+      ret = GetWindowsDirectory(dir, dirlen);\r
       if (! ret || ret > dirlen) {\r
         log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_NO_DIR_AND_NO_FALLBACK, NSSM_REG_DIR, service_name, 0);\r
         RegCloseKey(key);\r
@@ -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);\r
   }\r
 \r
+  /* Try to get throttle restart delay */\r
+  unsigned long type = REG_DWORD;\r
+  unsigned long buflen = sizeof(*throttle_delay);\r
+  bool throttle_ok = false;\r
+  ret = RegQueryValueEx(key, NSSM_REG_THROTTLE, 0, &type, (unsigned char *) throttle_delay, &buflen);\r
+  if (ret != ERROR_SUCCESS) {\r
+    if (ret != ERROR_FILE_NOT_FOUND) {\r
+      if (type != REG_DWORD) {\r
+        char milliseconds[16];\r
+        _snprintf(milliseconds, sizeof(milliseconds), "%lu", NSSM_RESET_THROTTLE_RESTART);\r
+        log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_BOGUS_THROTTLE, service_name, NSSM_REG_THROTTLE, milliseconds, 0);\r
+      }\r
+      else log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_QUERYVALUE_FAILED, NSSM_REG_THROTTLE, error_string(GetLastError()), 0);\r
+    }\r
+  }\r
+  else throttle_ok = true;\r
+\r
+  if (! throttle_ok) *throttle_delay = NSSM_RESET_THROTTLE_RESTART;\r
+\r
   /* Close registry */\r
   RegCloseKey(key);\r
 \r
index 9f5eaf1..261b0e9 100644 (file)
@@ -6,12 +6,13 @@
 #define NSSM_REG_FLAGS "AppParameters"\r
 #define NSSM_REG_DIR "AppDirectory"\r
 #define NSSM_REG_EXIT "AppExit"\r
+#define NSSM_REG_THROTTLE "AppThrottle"\r
 \r
 int create_messages();\r
 int create_parameters(char *, char *, char *, char *);\r
 int create_exit_action(char *, const char *);\r
 int expand_parameter(HKEY, char *, char *, unsigned long, bool);\r
-int get_parameters(char *, char *, int, char *, int, char *, int);\r
+int get_parameters(char *, char *, int, char *, int, char *, int, unsigned long *);\r
 int get_exit_action(char *, unsigned long *, unsigned char *, bool *);\r
 \r
 #endif\r
index 6292698..283cbea 100644 (file)
@@ -10,6 +10,7 @@ char exe[EXE_LENGTH];
 char flags[CMD_LENGTH];\r
 char dir[MAX_PATH];\r
 bool stopping;\r
+unsigned long throttle_delay;\r
 CRITICAL_SECTION throttle_section;\r
 CONDITION_VARIABLE throttle_condition;\r
 \r
@@ -199,7 +200,7 @@ void WINAPI service_main(unsigned long argc, char **argv) {
   }\r
 \r
   service_status.dwCurrentState = SERVICE_START_PENDING;\r
-  service_status.dwWaitHint = NSSM_RESET_THROTTLE_RESTART + NSSM_WAITHINT_MARGIN;\r
+  service_status.dwWaitHint = throttle_delay + NSSM_WAITHINT_MARGIN;\r
   SetServiceStatus(service_handle, &service_status);\r
 \r
   /* Try to create the exit action parameters; we don't care if it fails */\r
@@ -294,7 +295,7 @@ int start_service() {
   ZeroMemory(&pi, sizeof(pi));\r
 \r
   /* Get startup parameters */\r
-  int ret = get_parameters(service_name, exe, sizeof(exe), flags, sizeof(flags), dir, sizeof(dir));\r
+  int ret = get_parameters(service_name, exe, sizeof(exe), flags, sizeof(flags), dir, sizeof(dir), &throttle_delay);\r
   if (ret) {\r
     log_event(EVENTLOG_ERROR_TYPE, NSSM_EVENT_GET_PARAMETERS_FAILED, service_name, 0);\r
     return stop_service(2, true, true);\r
@@ -321,7 +322,7 @@ int start_service() {
   SetServiceStatus(service_handle, &service_status);\r
 \r
   /* Wait for a clean startup. */\r
-  if (WaitForSingleObject(process_handle, NSSM_RESET_THROTTLE_RESTART) == WAIT_TIMEOUT) throttle = 0;\r
+  if (WaitForSingleObject(process_handle, throttle_delay) == WAIT_TIMEOUT) throttle = 0;\r
 \r
   return 0;\r
 }\r
@@ -449,7 +450,7 @@ void throttle_restart() {
   if (throttle > 7) throttle = 8;\r
 \r
   char threshold[8], milliseconds[8];\r
-  _snprintf(threshold, sizeof(threshold), "%d", NSSM_RESET_THROTTLE_RESTART);\r
+  _snprintf(threshold, sizeof(threshold), "%d", throttle_delay);\r
   _snprintf(milliseconds, sizeof(milliseconds), "%d", ms);\r
   log_event(EVENTLOG_WARNING_TYPE, NSSM_EVENT_THROTTLED, service_name, threshold, milliseconds, 0);\r
 \r