From 8d855fdbce4ba0b8cfeda551f137434731385c23 Mon Sep 17 00:00:00 2001 From: Iain Patterson Date: Sat, 26 Feb 2011 12:39:43 +0000 Subject: [PATCH] Allow configuring throttling threshold. Tweak minimum time for which a service must run by setting the threshold number of milliseconds in AppThrottle (REG_DWORD). --- README.txt | 5 +++++ messages.mc | 7 +++++++ nssm.h | 2 +- registry.cpp | 25 +++++++++++++++++++++++-- registry.h | 3 ++- service.cpp | 9 +++++---- 6 files changed, 43 insertions(+), 8 deletions(-) diff --git a/README.txt b/README.txt index 1bf8ab9..3b8f25c 100644 --- a/README.txt +++ b/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\\Parameters\AppThrottle. + NSSM will look in the registry under HKLM\SYSTEM\CurrentControlSet\Services\\Parameters\AppExit for string (REG_EXPAND_SZ) values corresponding to the exit code of the application. diff --git a/messages.mc b/messages.mc index 5e5f184..41586ba 100644 --- a/messages.mc +++ b/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. +. + diff --git a/nssm.h b/nssm.h index 602c0c9..e10ee5c 100644 --- a/nssm.h +++ b/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 diff --git a/registry.cpp b/registry.cpp index 15ee152..1be5f4d 100644 --- a/registry.cpp +++ b/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); diff --git a/registry.h b/registry.h index 9f5eaf1..261b0e9 100644 --- a/registry.h +++ b/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 diff --git a/service.cpp b/service.cpp index 6292698..283cbea 100644 --- a/service.cpp +++ b/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); -- 2.7.4