Skip to content

[Improvements] ServiceManager.cs — ServiceStopTimeoutSeconds hardcoded as a local const, should live in AppConfig #809

@Christophe-Rogiers

Description

@Christophe-Rogiers

Severity: Info

Summary

ServiceManager declares ServiceStopTimeoutSeconds = 60 as a private file-local constant. Every other timeout threshold in the service lifecycle (Min/Max/Default for start and stop, heartbeat, pre-launch, etc.) lives in AppConfig, so this one constant is an outlier that forces a code edit + rebuild to tune.

File and lines

src/Servy.Core/Services/ServiceManager.cs:29:

private const int ServiceStopTimeoutSeconds = 60;

Uses (lines 397, 398, 399, 578):

var totalWaitTime    = (options.StopTimeout      ?? ServiceStopTimeoutSeconds) + AppConfig.ScmTimeoutBufferSeconds;
var previousWaitTime = (serviceDto?.PreviousStopTimeout ?? ServiceStopTimeoutSeconds) + AppConfig.ScmTimeoutBufferSeconds;
totalWaitTime        = Math.Max(Math.Max(totalWaitTime, previousWaitTime), ServiceStopTimeoutSeconds);
...
while (sc.Status != ServiceControllerStatus.Stopped && sw.Elapsed.TotalSeconds < ServiceStopTimeoutSeconds)

Note that the first three uses already reach into AppConfig.ScmTimeoutBufferSeconds on the same line — the constant right next to them is the only one not in AppConfig.

Explanation

Closed #522 ("Multiple files — Magic numbers without named constants (batch)") cleaned up several similar cases, but this one remains. It's the default upper bound for how long ServiceManager waits for SCM-reported Stopped, used as the fallback when per-service StopTimeout is null. That's the kind of value operators want to tune without a rebuild: on slow disks / heavy teardown hooks, 60 seconds can be too short; conversely, on embedded hosts, 60 seconds is too patient.

Suggested fix

Move the value into AppConfig.cs alongside the existing stop-timeout family:

// AppConfig.cs
public const int DefaultServiceStopTimeoutSeconds = 60;

Then update ServiceManager.cs to reference it:

// line 29 — remove the local const, replace all four uses
var totalWaitTime    = (options.StopTimeout              ?? AppConfig.DefaultServiceStopTimeoutSeconds) + AppConfig.ScmTimeoutBufferSeconds;
var previousWaitTime = (serviceDto?.PreviousStopTimeout  ?? AppConfig.DefaultServiceStopTimeoutSeconds) + AppConfig.ScmTimeoutBufferSeconds;
totalWaitTime        = Math.Max(Math.Max(totalWaitTime, previousWaitTime), AppConfig.DefaultServiceStopTimeoutSeconds);
...
while (sc.Status != ServiceControllerStatus.Stopped
       && sw.Elapsed.TotalSeconds < AppConfig.DefaultServiceStopTimeoutSeconds)

Pure refactor — no behavior change.

Metadata

Metadata

Assignees

Labels

enhancementNew feature or request

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions