Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion docs/agent-reference/how-to-implement-custom-update-handler.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ See **ContentHandler** class definition in [content_handler.hpp](../../src/exte
| Install | Handles an 'install' task invoked by DU Agent workflow.<br/><br/>The install task usually includes a process where the handler invokes external tool or command to install the downloaded update payload file(s) to the desired target.<br/>For example, for 'microsoft/apt' update, the handler could invoke following command:<br/><br/> <b>`apt-get install <options> <list of packages to install>`</b> | For success cases, the **ResultCode** field of the **ADUC_Result** struct can be one of the following values:<br/><br/> ADUC_Result_Install_Success<br/>ADUC_Result_Install_InProgress<br/>ADUC_Result_Install_Skipped_UpdateAlreadyInstalled<br/>ADUC_Result_Install_Skipped_NoMatchingComponents <br/>ADUC_Result_Install_RequiredImmediateReboot <br/>ADUC_Result_Install_RequiredReboot<br/>ADUC_Result_Install_RequiredImmediateAgentRestart<br/>ADUC_Result_Install_RequiredAgentRestart<br/><br/>See [adu_core.h](../../src/adu_types/inc/aduc/types/adu_core.h) for more details |
| Apply | Handles an 'apply' task invoked by DU Agent workflow.<br/><br/>The apply task usually includes one or more additional steps after an 'install' task has completed. Such as, validating installed items, restart system service, update configuration files, persist some meta data related to the update process.<br/><br/> The DU Agent workflow will consider the update complete successfully only when an apply task returns ADUC_Result_Apply_Success | For success cases, the **ResultCode** field of the **ADUC_Result** struct can be one of the following values:<br/><br/> ADUC_Result_Apply_Success <br/>ADUC_Result_Apply_InProgress<br/>ADUC_Result_Apply_RequiredImmediateReboot<br/>ADUC_Result_Apply_RequiredReboot <br/>ADUC_Result_Apply_RequiredImmediateAgentRestart <br/>ADUC_Result_Apply_RequiredAgentRestart<br/><br/>See [adu_core.h](../../src/adu_types/inc/aduc/types/adu_core.h) for more details |
| Cancel | Handles a 'cancel' task invoked by DU Agent workflow.<br/><br/>The cancel task usually initiated by the Device Update Service. When an Agent received a cancel request, the Agent workflow will relay this request to an active Step Handler that's currently processing the deployment. The handler should try to gracefully cancelling current task, and return appropriate result. | For success cases, the **ResultCode** field of the **ADUC_Result** struct can be one of the following values:<br/><br/> ADUC_Result_Cancel_Success <br/>ADUC_Result_Cancel_UnableToCancel<br/<br/>See [adu_core.h](../../src/adu_types/inc/aduc/types/adu_core.h) for more details |
| IsInstalled | In some situation, an Agent workflow can invoke 'IsInstalled' function, to determine whether the current update (as specified in [**ADUC_WorkflowData**](../../src/adu_types/inc/aduc/types/workflow.h) object) is installed on the target device, or component. The Step Handler is responsible for evaluate the target state and return result accordingly. | The **ResultCode** field of the **ADUC_Result** struct can be one of the following values:<br/><br/> ADUC_Result_IsInstalled_Installed <br/>ADUC_Result_IsInstalled_NotInstalled<br/<br/>See [adu_core.h](../../src/adu_types/inc/aduc/types/adu_core.h) for more details |
| IsInstalled | Probe that lets the orchestrator (and the Steps Handler, when this handler is used as a step) decide whether the update described by [**ADUC_WorkflowData**](../../src/adu_types/inc/aduc/types/workflow.h) is already present on the target device or component, so it can skip work that has already been done. **Called multiple times per deployment** (see [IsInstalled call sites and authoring guidance](#isinstalled-call-sites-and-authoring-guidance) below) — must be cheap, side-effect-free, and idempotent. The handler compares the workflow's `installedCriteria` against handler-scoped state (e.g., installed package version for `microsoft/apt:1`, file hash on disk for `microsoft/swupdate:2`) and returns the result; it must **not** consult system-wide state outside the scope of this handler's content. | The **ResultCode** field of the **ADUC_Result** struct can be one of the following values:<br/><br/> ADUC_Result_IsInstalled_Installed <br/>ADUC_Result_IsInstalled_NotInstalled<br/><br/>A `ResultCode` of `0` is `ADUC_Result_Failure`; the Steps Handler converts a failure to `NotInstalled` so the workflow proceeds. See [adu_core.h](../../src/adu_types/inc/aduc/types/adu_core.h) for more details. |

## Consuming ADUC_WorkflowData

Expand Down Expand Up @@ -107,6 +107,29 @@ When a step targets selected components, the Steps Handler invokes your handler

If `selectedComponentsCount == 0` for an inline step at the parent level, the step is treated as **optional** and skipped (not failed).

### IsInstalled call sites and authoring guidance

`IsInstalled` is **not** invoked once per deployment. The agent core and the Steps Handler call it several times to decide whether the update — or any individual step — can be skipped. Authors must therefore treat it as a **cheap, side-effect-free, idempotent probe**. The known call sites are:

| Call site | Why |
|---|---|
| Agent core, before starting a deployment workflow | Avoids re-running an update that is already installed across an agent restart or a service-driven retry. |
| Agent core, after a successful Apply | Confirms the post-apply state matches `installedCriteria` before reporting success to the service. |
| Steps Handler, before each step's `Download` | If the step's content is already installed, downloading is skipped. |
| Steps Handler, before each step's `Install`/`Apply` | If the step is already installed, `Backup` / `Install` / `Apply` are skipped for that step and the workflow continues with the next step (the rest of the workflow is **not** short-circuited). |
| Steps Handler, after the per-(component × step) loop | Aggregate `IsInstalled` for the parent workflow: returns `Installed` only when **every** (component × step) pair returns `Installed`; any single `NotInstalled` makes the whole update `NotInstalled`. |

Authoring rules:

1. **Be cheap.** It runs many times. Avoid network calls, package-manager refreshes, or anything that mutates state. Cache results inside the handler if necessary.
2. **Be scoped.** A step's `IsInstalled` must reflect the installed state of *this step's content*, not system-wide state. A `microsoft/apt:1` step asks "is this package at this version installed?", not "is the device fully up to date?".
3. **Be deterministic.** Given the same `ADUC_WorkflowData`, return the same result regardless of how many times you are called or in what order.
4. **Use `installedCriteria` honestly.** Read it via `workflow_get_installed_criteria` and compare it against the handler-scoped state. Don't hard-code "always installed" or "always not installed" — both will break MSOE skip semantics.
5. **Don't return `0` to mean "yes".** `0` is `ADUC_Result_Failure`. Use `ADUC_Result_IsInstalled_Installed` (`900`) or `ADUC_Result_IsInstalled_NotInstalled` (`901`). The Steps Handler converts a failure return to `NotInstalled` so the workflow proceeds, but you should not rely on that.
6. **No reboots, no restarts.** `IsInstalled` is a query. It must never schedule a reboot, restart the agent, or modify the device.

When this handler is used as a step inside a multi-step manifest, the Steps Handler's aggregate `IsInstalled` is the **conjunction** of each step's per-component `IsInstalled` results. See [steps-handler.md → IsInstalled](steps-handler.md#isinstalled) for the exact algorithm and `selectedComponentsCount == 0` (no matching components) edge case.



In some case, a Device Builder may want to install an update content on one or more component(s) that connected to the Host Device instead.
Expand Down
Loading