SAIF.NetCore.WindowsService operations and processes¶
This page is the operation catalog and cross-operation hub for this library. Each operation's detailed, step-by-step logic lives in its own page under operations/.
Operation catalog¶
| Operation | Intent | Trigger | Inputs | Outputs | Rules |
|---|---|---|---|---|---|
| Run the Windows Service program | Build (once) and run the Generic Host, blocking until shutdown | Consumer's Main calls new Program().Run(args) |
Command-line args |
Blocks until host shutdown; sets static ServiceHost |
WS-BR-01 |
| Create and configure the host | Build the host, apply the optional startup delay, and run the error-handler/logger configuration hooks | OP-01 step 1, or a direct consumer call | args |
A built, configured IHost, stored in static ServiceHost |
WS-BR-02, WS-BR-04, WS-BR-05 |
| Create the default host builder | Assemble the IHostBuilder with the configuration-source stack and Windows Service hosting |
OP-02 step 1 | args |
IHostBuilder |
WS-BR-03 |
| Construct a service worker | Build a ServiceWorker<T> with its task runner and error handler |
DI activation of the consumer's ServiceWorker<T> subclass |
IServiceTaskRunner, IWindowsServiceErrorHandler |
A worker with TaskRunner/ErrorHandler set and default timing properties |
WS-BR-13 |
| Execute the worker loop | Run the task repeatedly, with a fixed delay after each run, until cancellation | BackgroundService.StartAsync during IHost.Run() |
stoppingToken |
Completes on cancellation | WS-BR-06, WS-BR-07 |
| Run one task iteration | Invoke the consumer's task and route any exception to error handling | OP-05 step 2 | stoppingToken |
None on success; task-runner exceptions are caught and delegated to the error handler, which may itself throw and propagate out of the operation | WS-BR-08 |
| Handle a task error | Decide shutdown exemption, log the error, and stop the host unless exempt | OP-06 step 2 | The exception | A logged error; host stop unless the exception is exempt | WS-BR-09, WS-BR-10, WS-BR-11, WS-BR-12 |
Process flow diagram¶
The following diagram visualizes the primary operational flow across all seven operations.
flowchart TD
Start([Consumer Main calls Run]) --> HostNull{ServiceHost == null?}
HostNull -->|Yes| Create[Create and configure the host]
HostNull -->|No| RunHost
Create --> Builder[Create the default host builder]
Builder --> Delay[Delay startup if DelayStart set]
Delay --> Hooks["Configure: error-handler hook, then logger"]
Hooks --> RunHost[ServiceHost.Run]
RunHost --> WorkerCtor[Construct a service worker]
WorkerCtor --> Loop[Execute the worker loop]
Loop --> Iter[Run one task iteration]
Iter --> Err{Exception thrown?}
Err -->|No| WaitDelay[Task.Delay TaskDelayMilliseconds]
Err -->|Yes| Handle[Handle a task error]
Handle --> Exempt{Shutdown-exempt?}
Exempt -->|Yes| WaitDelay
Exempt -->|No| Stop([ServiceHost.StopAsync])
WaitDelay --> Cancelled{Cancellation requested?}
Cancelled -->|No| Iter
Cancelled -->|Yes| Done([Loop exits])
Failure and edge-case behavior¶
- A missing
IWindowsServiceErrorHandler,ISaifWindowsServiceLogService,IEnvironmentClient, orIHttpJsonClientregistration throwsInvalidOperationExceptionduring Create and configure the host, before the host runs (WS-BR-05). - A non-exempt task error allows
ShutdownTimeoutSeconds(default 30) for graceful stop; the code verifiably callsServiceHost.StopAsync(ShutdownTimeoutSeconds), which links that caller-supplied timeout with the host's own, independently configuredHostOptions.ShutdownTimeoutinto a single token, then visits every registered hosted service (viaHost.StopAsync) and calls each one'sStopAsync. Only a hosted service that is actually aBackgroundServicecancels its own stopping token and returns as soon as either that service's ownExecuteAsynctask completes or the linked token is cancelled -- which happens when either budget (ShutdownTimeoutSecondsorHostOptions.ShutdownTimeout) elapses first; an arbitraryIHostedServiceneed not implement this pattern at all. For the worker whose own task error triggered this call, itsExecuteTaskis the very task suspended on this call chain (ExecuteAsync→RunTaskAsync→HandleTaskError→StopAsync), so that worker's own wait can only resolve once the linked token is cancelled, not by its task completing first* -- and only once its execute task has actually been assigned; a failure beforeStartAsyncsets that task is not subject to this wait. Other hosted services registered in the same host (or this worker during an externally initiated shutdown while idle inTask.Delay) are not subject to that same self-referential wait and can complete sooner once their stopping token is cancelled. Whether other hosted services registered alongside this worker extend the overall shutdown sequence further, and the resulting total duration, is unknown without inspecting the host's full service registration and configuredHostOptions** (see Handle a task error and open question OQ-02 below). - An exception thrown anywhere inside the error-handling path itself — predicate evaluation, message construction,
ErrorHandler.HandleError, or theStopAsynccall — is not absorbed; it propagates out of Run one task iteration and out of the worker'sExecuteAsync, skipping the intended shutdown. - A
ServiceWorker<T>hosted by anything other thanServiceProgramRunnerBasefails withNullReferenceExceptionon its first non-exempt error, becauseServiceHostis a static reference owned byServiceProgramRunnerBase. - The re-added
appsettings.json/environment-variable providers invert standard .NET configuration precedence; see Configuration for the full consequence list.
Open questions¶
- OQ-02:
BackgroundService.StopAsync's own-task-vs-linked-token wait means the worker whose task error triggered the shutdown can only unblock once the linked shutdown token is cancelled -- by whichever of the caller'sShutdownTimeoutSecondsor the host's ownHostOptions.ShutdownTimeoutelapses first -- not by its ownExecuteTaskcompleting first (confirmed from the inheritedBackgroundService/Hostsource). What is not confirmed is the end-to-end duration and ordering effect of other hosted services registered in the same host duringHost.StopAsync's sequential visit, nor the configured value ofHostOptions.ShutdownTimeoutin any specific deployment -- that would need a host-level test against a concrete host configuration to observe*.
Related documentation¶
- Index
- Overview
- Architecture
- Dependencies
- Configuration
- Business rules
- Service registration
- API reference
Note: Statements marked with * were inferred from code structure, naming conventions, or contextual evidence where direct confirmation was not available in source artifacts. Statements marked with ** could not be confirmed; treat as unknown until verified.
Sources¶
src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService.csprojsrc/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceProgramRunnerBase.cssrc/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceWorker.cs