Skip to content

[Robustness] ProcessLauncher.Start — TimeoutMs silently ignored when OnScmHeartbeat is null #860

@Christophe-Rogiers

Description

@Christophe-Rogiers

Severity: Info (latent — defensive callsites prevent it today)

File: src/Servy.Service/ProcessManagement/ProcessLauncher.cs, lines 94-100

The synchronous-mode timeout enforcement is gated on both TimeoutMs > 0 and the heartbeat delegate being set:

// Synchronous mode: Wait for exit while pulsing the SCM
if (options.TimeoutMs > 0 && (options.OnScmHeartbeat?.Target != null || options.OnScmHeartbeat?.Method != null))
{
    WaitForExitWithHeartbeat(process, options, logger);
}

// Ensure all async reads are finished
process.UnderlyingProcess.WaitForExit();

If a caller sets TimeoutMs but does not wire up OnScmHeartbeat, the heartbeat-loop block is skipped and execution falls through to the bare WaitForExit() on line 100, which has no timeout. The configured TimeoutMs is silently dropped — the process can hang the launcher indefinitely.

Today the only callers (Service.StartPreStopProcess, Service.RunSynchronousPreLaunch) always set both, so the bug is dormant. But:

Suggested fix:
Decouple timeout enforcement from heartbeat presence. Always honor TimeoutMs when it is positive; treat heartbeat as optional inside the wait loop:

if (options.TimeoutMs > 0)
{
    WaitForExitWithHeartbeat(process, options, logger); // pass null-safe heartbeat
}
else
{
    process.UnderlyingProcess.WaitForExit();
}

And inside WaitForExitWithHeartbeat, guard the pulse: options.OnScmHeartbeat?.Invoke(options.ScmAdditionalTimeMs); already does the right thing — the existing code is fine if the gate is loosened.

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