---
title: Run one task iteration
summary: Invokes the consumer's task and routes any exception to error handling.
status: draft
owner: SAIF Framework Platform Team
last_reviewed: 2026-10-02
library: SAIF.NetCore.WindowsService
reference_type: package
operation_id: OP-06
trigger: OP-05 step 2
---

# Run one task iteration

| Field | Value |
| --- | --- |
| **Operation ID** | OP-06 |
| **Trigger** | [Execute the worker loop](op-05-execute-worker-loop.md) step 2 |
| **Inputs** | `stoppingToken` |
| **Outputs** | None on success; task-runner exceptions are caught and delegated to the error handler, which may itself throw and propagate out of this operation |
| **Primary components** | `ServiceWorker<T>.RunTaskAsync` |
| **Entry point** | `src/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/SAIF.NetCore.WindowsService/ServiceWorker.cs` |

## Steps

1. Invoke the consumer task with `await TaskRunner.Run(stoppingToken)`.
   - Delegation -> consumer code implementing `SAIF.NetCore.ServiceContracts`'s `IServiceTaskRunner.Run(CancellationToken)`. ServiceContracts defines no steps of its own; the consumer supplies the business logic.
2. Catch every exception (`catch (Exception ex)`) and call `await HandleTaskError(ex)` (see [Handle a task error](op-07-handle-task-error.md)) ([WS-BR-08](../business-rules.md#ws-br-08-every-task-exception-goes-through-error-handling)).
   - Branch: an `OperationCanceledException` thrown by a runner that honors `stoppingToken` during shutdown is **also** treated as a task error — it is logged as an error and, unless exempted, triggers another `StopAsync`*.
   - Branch: `HandleTaskError` itself is not guarded by a further try/catch here — an exception raised while evaluating the exemption predicate, building the message, calling `ErrorHandler.HandleError`, or calling `ServiceHost.StopAsync` propagates out of `RunTaskAsync` and out of the worker's `ExecuteAsync`; it is not absorbed (see [Handle a task error](op-07-handle-task-error.md) failure branches).

## Process flow

```mermaid
flowchart TD
	Start([RunTaskAsync]) --> Invoke[await TaskRunner.Run stoppingToken]
	Invoke --> Threw{Exception thrown?}
	Threw -->|No| Done([Return normally])
	Threw -->|Yes| Handle[HandleTaskError ex]
	Handle --> HandleThrew{HandleTaskError threw?}
	HandleThrew -->|No| Done
	HandleThrew -->|Yes| Propagate(["Exception propagates out of RunTaskAsync and ExecuteAsync"])
```

## Failure and edge-case behavior
- A `NullReferenceException` from a `null` `TaskRunner` (see [Construct a service worker](op-04-construct-worker.md)) is caught here, like any other exception.
- A cooperative-cancellation `OperationCanceledException` during shutdown is treated identically to an unexpected error and may trigger an additional `StopAsync` call, even though the host is already stopping*.
- An exception thrown inside `HandleTaskError` is not absorbed by this operation; it propagates out of `RunTaskAsync` and the worker's `ExecuteAsync`, skipping whatever shutdown step would otherwise have run.

## Related documentation
- [Operations and processes](../operations-processes.md)
- [Business rules](../business-rules.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/ServiceWorker.cs`
