---
title: SAIF.NetCore.WindowsService operations and processes
summary: Business and technical operations supported by this library.
status: draft
owner: SAIF Framework Platform Team
last_reviewed: 2026-10-02
library: SAIF.NetCore.WindowsService
reference_type: package
---

# 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](operations/op-01-run-program.md) | 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](business-rules.md#ws-br-01-host-is-created-once-per-process) |
| [Create and configure the host](operations/op-02-create-host.md) | 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](business-rules.md#ws-br-02-optional-startup-delay-blocks-before-hooks-and-run), [WS-BR-04](business-rules.md#ws-br-04-error-handler-hook-runs-before-the-logger-is-configured), [WS-BR-05](business-rules.md#ws-br-05-required-hosting-services-must-be-registered) |
| [Create the default host builder](operations/op-03-create-host-builder.md) | Assemble the `IHostBuilder` with the configuration-source stack and Windows Service hosting | OP-02 step 1 | `args` | `IHostBuilder` | [WS-BR-03](business-rules.md#ws-br-03-configuration-source-stack-is-altered-by-re-added-providers) |
| [Construct a service worker](operations/op-04-construct-worker.md) | 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](business-rules.md#ws-br-13-task-runner-must-implement-the-worker's-type-parameter) |
| [Execute the worker loop](operations/op-05-execute-worker-loop.md) | 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](business-rules.md#ws-br-06-worker-loop-is-fixed-delay%2C-not-fixed-rate), [WS-BR-07](business-rules.md#ws-br-07-loop-stops-when-the-host's-stopping-token-is-cancelled) |
| [Run one task iteration](operations/op-06-run-task-iteration.md) | 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](business-rules.md#ws-br-08-every-task-exception-goes-through-error-handling) |
| [Handle a task error](operations/op-07-handle-task-error.md) | 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](business-rules.md#ws-br-09-shutdown-exemption-requires-an-exact-type-match-and-an-allowing-predicate), [WS-BR-10](business-rules.md#ws-br-10-non-exempt-errors-shut-down-the-whole-service), [WS-BR-11](business-rules.md#ws-br-11-error-messages-follow-a-fixed-format), [WS-BR-12](business-rules.md#ws-br-12-every-error-is-reported-before-any-shutdown) |

## Process flow diagram
The following diagram visualizes the primary operational flow across all seven operations.

```mermaid
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`, or `IHttpJsonClient` registration throws `InvalidOperationException` during [Create and configure the host](operations/op-02-create-host.md), before the host runs ([WS-BR-05](business-rules.md#ws-br-05-required-hosting-services-must-be-registered)).
- A non-exempt task error allows `ShutdownTimeoutSeconds` (default 30) for graceful stop; the code verifiably calls `ServiceHost.StopAsync(ShutdownTimeoutSeconds)`, which links that caller-supplied timeout with the host's own, independently configured `HostOptions.ShutdownTimeout` into a single token, then visits every registered hosted service (via `Host.StopAsync`) and calls each one's `StopAsync`. Only a hosted service that is actually a `BackgroundService` cancels its own stopping token and returns as soon as **either** that service's own `ExecuteAsync` task completes **or** the linked token is cancelled -- which happens when **either** budget (`ShutdownTimeoutSeconds` or `HostOptions.ShutdownTimeout`) elapses first; an arbitrary `IHostedService` need not implement this pattern at all. For the worker whose own task error triggered this call, its `ExecuteTask` is 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 before `StartAsync` sets 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 in `Task.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 configured `HostOptions`** (see [Handle a task error](operations/op-07-handle-task-error.md) and open question OQ-02 below).
- An exception thrown anywhere inside the error-handling path itself — predicate evaluation, message construction, `ErrorHandler.HandleError`, or the `StopAsync` call — is not absorbed; it propagates out of [Run one task iteration](operations/op-06-run-task-iteration.md) and out of the worker's `ExecuteAsync`, skipping the intended shutdown.
- A `ServiceWorker<T>` hosted by anything other than `ServiceProgramRunnerBase` fails with `NullReferenceException` on its first non-exempt error, because `ServiceHost` is a static reference owned by `ServiceProgramRunnerBase`.
- The re-added `appsettings.json`/environment-variable providers invert standard .NET configuration precedence; see [Configuration](configuration.md) 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's `ShutdownTimeoutSeconds` or the host's own `HostOptions.ShutdownTimeout` elapses first -- not by its own `ExecuteTask` completing first (confirmed from the inherited `BackgroundService`/`Host` source). What is not confirmed is the end-to-end duration and ordering effect of other hosted services registered in the same host during `Host.StopAsync`'s sequential visit, nor the configured value of `HostOptions.ShutdownTimeout` in any specific deployment -- that would need a host-level test against a concrete host configuration to observe*.

## Related documentation
- [Index](index.md)
- [Overview](overview.md)
- [Architecture](architecture.md)
- [Dependencies](dependencies.md)
- [Configuration](configuration.md)
- [Business rules](business-rules.md)
- [Service registration](service-registration.md)
- [API reference](api/index.md)

> **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.csproj`
- `src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceProgramRunnerBase.cs`
- `src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceWorker.cs`
