--- alias: tutorials-automation-scheduled-action-scenario-04-workflow-ready-signal description: "Show how to use workflow-owned readiness signals, time windows, and post-action validation to upgrade controllers at safe runtime checkpoints." --- # Scenario 4 - Controller Version Update - Workflow Ready Signal ## Overview This scenario shows how to use the `Defined in Workflow` **Detector** to let the **Controller** workflow own the readiness decision. Instead of time windows or entity states, the IoT developer embeds ready logic directly in the workflow so that the update is triggered exactly when the equipment signals it is safe, without requiring operators to manage states or time windows. In this example, the cookie factory's packing controller is upgraded from `A/3` to `A/4` across two packing lines, each upgrading independently as its workflow signals a safe state during a shift-change window. ### When to Use - **Readiness owned by the workflow** - when the IoT developer has embedded custom readiness logic in the **Controller** workflow and wants it to drive the maintenance trigger directly, rather than relying on MES states or time windows configured by operators. - **Equipment conditions not visible to MES** - when readiness depends on internal equipment state (sensor values, recipe progress, multi-step handshakes) that only the controller workflow can evaluate. - **Complement to other detectors** - use `EntityStateInList` when operators own readiness via **Resource** states; `NoMaterialsOnResource` when readiness is derived from **Material** tracking; `DefinedInWorkflow` when the IoT developer owns the readiness signal in code. ### Example The cookie factory is upgrading its packing lines from `PackingController A/3` to `A/4`. The update is not tied to a fixed maintenance window. Each packing cell upgrades independently when its production workflow signals that the line is at a safe stopping point between jobs. Shift-change **Pre-Conditions** ensure upgrades only happen during handover windows, and a 15-minute ready delay guards against transient pauses. - **Resources**: `ASA Packer-01`, `ASA Packer-02`. - **Controller**: `PackingController`. - Current version: revision `A`, version `3`. - Target version: revision `A`, version `4`. ```mermaid graph LR subgraph current["PackingController A/3 (current)"] P1[Packer-01] P2[Packer-02] end W["Workflow\nready signal"] -->|DefinedInWorkflow| P1 & P2 P1 -->|UpdateControllerVersion| P1T[Packer-01] P2 -->|UpdateControllerVersion| P2T[Packer-02] subgraph target["PackingController A/4 (target)"] P1T P2T end ``` ## Prerequisites Before creating the Definition, confirm the following: - Load the Scenario 4 automation master data into MES, it creates the `PackingController [A.3]` and `PackingController [A.4]` **Controller** definitions, `packing-manager` record, and both packer instances (master data package: [01-automation-masterdata.json](./masterdata/scenario04/01-automation-masterdata.json)). - All target instances are currently running `PackingController` revision `A`, version `3`. - The shipped `PackingController [A.3]` sample installs the File Raw driver, but you must still implement or adapt workflow logic that sets and clears the `DefinedInWorkflow` ready signal for each instance before enabling the Definition. - MES Configuration Entries under `/Cmf/Tutorials/AutomationScheduleAction/Scenario4/IoHealthy/{resourceName}` are set to `true` for the **Resources** you expect to finish with `ProcessedSuccess`. The sample **DEE** defaults missing entries to `false`, which results in `ValidationFailed`. - Notification templates `ASA PreAction Template`, `ASA Success Template`, `ASA Failure Template`, and `ASA Ignored Template` exist in MES if you intend to use notifications. - **DEE action** [`ASA_Scenario4_ValidatePackerIo`](./dees/ASA_Scenario4_ValidatePackerIo.cs) is created and deployed in MES before enabling the Definition (see [[howto-iot-import-dee-action]]). ## Configuration ### Why This Pattern This Definition uses the following combination of components: | Component | Type | Purpose | |---|---|---| | **Context** | `AutomationController` | Discovers all instances currently running the source controller version (`A/3`). | | **Pre-Conditions** | `AllowedWeekdays` + `AllowedTimeWindow` | Restricts upgrades to shift-change windows when lines are between production runs. | | **Detector** | `DefinedInWorkflow` | Delegates the readiness decision to the controller workflow. | | **Acceptance Gate** | `ReadyDelay` | Enforces a stability period after the workflow signals ready, preventing execution on transient transitions. | | **Action** | `UpdateControllerVersion` | Stops the current runtime, removes it, and starts a new runtime with revision `A`, version `4`. | | **Post Action Validation** | `MaxStartupTime` + `CustomDeeAction` | Confirms the new runtime starts within the timeout and passes an I/O check. | Table 1: Scenario 4 Component Design ### Create the Definition Open **Automation Scheduled Action** and select **Create** (see [[user-guide-automation-scheduled-action-create|Create Definition]]). The wizard has four tabs. #### Tab 1 - General Data Start by filling in the general definition fields. - Give it a name like `CF_Update_Packaging_Controller_A4` and a description that captures its purpose (for example, "Upgrade packing controller from A/3 to A/4 when workflow signals safe state."). - Set **Is Enabled** to **Disabled** for now. - Set **Validity** to `5` days. This covers a full work week of shift windows. Adjust if your rollout window is shorter or longer. For **Context**, select **Automation Controller**, enter `PackingController` as the controller: - Set **Revision** to `A` and **Version** to `3`. This targets all instances currently running `PackingController A/3` - one task per instance. For the **Detector**, select **Defined in Workflow**. The workflow must signal readiness for this detector to return `true`. If the workflow does not implement this signal path, tasks will remain at `SkippedNotReady` until they expire. For the **Action**, select **Update Controller Version**: - Set **Revision** to `A` and **Version** to `4`. Optionally, configure notification templates to be alerted at key moments: | Event | Template | |---|---| | Pre-Action | `ASA PreAction Template` | | Success | `ASA Success Template` | | Failure | `ASA Failure Template` | | Ignored | `ASA Ignored Template` | Table 2: Scenario 4 Notification Templates #### Tab 2 - Pre-Conditions Select :material-plus: twice to add the following pre-conditions in this order: **1. Allowed Weekdays** - Set the weekdays to `Monday` through `Friday`. **2. Allowed Time Window** - Add three windows: `05:00–06:30`, `13:00–14:00`, and `21:00–22:00`. These correspond to the shift-change windows in UTC. All times are evaluated in UTC, so convert your shift-change windows before entering them here. #### Tab 3 - Acceptance Gates Select :material-plus: and select **Ready Delay**. Set the delay to `900` seconds. The workflow must signal ready for 15 consecutive minutes before the upgrade runs. This prevents triggering on a transient workflow state during a brief pause between jobs. #### Tab 4 - Post-Action Validations Select :material-plus: twice to add the following validations in this order: **1. Max Startup Time** - Set the timeout to `420` seconds. This waits up to 7 minutes for the new runtime to reach a running state. **2. DEE Action** - Enter `ASA_Scenario4_ValidatePackerIo` as the action. This checks I/O connectivity after the instance starts. !!! tip "Verify tasks before enabling" Click **Save** with **Is Enabled** set to **Disabled**. The system immediately resolves the context and creates one task per target instance. Before enabling, open **Automation Scheduled Action Tasks** and confirm: - All expected targets appear in the task list. - No unexpected targets are included. Once the task list is correct, enable the Definition from the top ribbon (see [[user-guide-automation-scheduled-action-enable-disable|Enable / Disable Definition]]). ## How It Works at Runtime After you enable the Definition, the system processes each task on every polling pass as follows: 1. **Context** discovers all instances currently running `PackingController A/3` and creates one task per instance. 2. Weekday and time-window **Pre-Conditions** are checked against current UTC time. Tasks are skipped outside the allowed shift-change windows. 3. The **Detector** queries the controller workflow whether this instance has signaled ready. 4. The `ReadyDelay` **Acceptance Gate** confirms the workflow has maintained the ready signal for at least 15 minutes. 5. The **Action** stops the current `A/3` runtime and starts a new runtime with `A/4`. 6. `MaxStartupTime` waits up to 7 minutes for the new runtime to reach a running state. 7. `ASA_Scenario4_ValidatePackerIo` confirms I/O connectivity after startup. 8. The task is finalized with outcome and notifications are sent. ```mermaid flowchart TD A([Task per Packer instance]) --> B{"Shift window?
Mon-Fri
05:00-06:30
13:00-14:00
21:00-22:00"} B -- No --> S1([SkippedPreConditionFailed]) B -- Yes --> C{"Workflow signals
ready?"} C -- No --> S2([SkippedNotReady]) C -- Yes --> D{"Stable 15+ min?"} D -- No --> S3([SkippedGateFailed]) D -- Yes --> E["UpdateControllerVersion
A/3 → A/4"] E --> NOP{"Already on
A/4?"} NOP -- Yes --> IGN([IgnoredNoOp]) NOP -- No --> F{"Running within
420 s?"} F -- No --> FAIL1([ValidationFailed]) F -- Yes --> G{"ASA_Scenario4_ValidatePackerIo
passes?"} G -- No --> FAIL2([ValidationFailed]) G -- Yes --> OK([ProcessedSuccess]) ``` ## Expected Task Outcomes | `LastOutcome` | `State` | Meaning | |---|---|---| | `ProcessedSuccess` | `Processed` | **Controller** upgraded and both validations passed. | | `IgnoredNoOp` | `Ignored` | Instance was already running `A/4` - no change needed. | | `ActionFailed` | `Failed` | Runtime replacement failed. Check **Manager** capacity and **Controller** definition availability. | | `ValidationFailed` | `Failed` | Runtime started but did not reach running state within 420 seconds, or the I/O check failed. | | `SkippedPreConditionFailed` | (task stays active) | Current UTC time or weekday is outside the allowed shift-change windows. | | `SkippedNotReady` | (task stays active) | Workflow has not signaled ready for this instance. | | `SkippedGateFailed` | (task stays active) | Workflow signaled ready but has not sustained that state for 15 minutes yet. | Table 3: Scenario 4 Task Outcomes ## Simulating This Scenario Confirm the Scenario 4 master data is loaded and both packer instances are running on `packing-manager`. This scenario uses `DefinedInWorkflow` as the **Detector**, so the **Controller** workflow must raise the ready signal explicitly. The shipped sample master data does not include the final workflow logic that toggles `DefinedInWorkflow` for you. A simple demo pattern is to add a File Raw Driver step that watches a per-resource directory and sets the flag when a file named `ready.signal` appears. If you implement that pattern, you can drive readiness from the filesystem without redeploying code between test runs. One simple directory convention for that demo workflow is: ```log C:\simulation\cookie-factory\{resource-name}\ ``` ### To Trigger Processing for One Resource 1. On the machine running `packing-manager`, navigate to `C:\simulation\cookie-factory\ASA Packer-01\`. 2. Create an empty file named `ready.signal` in that directory. 3. Ensure `/Cmf/Tutorials/AutomationScheduleAction/Scenario4/IoHealthy/ASA Packer-01` is set to `true`, otherwise the sample **Post Action Validation** ends in `ValidationFailed`. 4. The File Raw Driver detects the new file, fires the workflow event, and the workflow sets the `DefinedInWorkflow` ready flag to `true`. 5. Open **Automation Scheduled Action** Tasks and confirm `IsReady` becomes `true` for the `ASA Packer-01` task. 6. Wait 15 minutes. The `ReadyDelay` gate passes and the task executes `UpdateControllerVersion` from `A/3` to `A/4`. 7. Confirm the instance is now running `PackingController A/4` in the **Automation Controller Instance** record. 8. The task transitions to `ProcessedSuccess`. Repeat steps 1–8 for `ASA Packer-02`. Each resource is processed independently. ### To Observe the Gate Countdown Open the task and watch `ReadyStateChangedAt`. The **Acceptance Gate** requires this timestamp to be at least 15 minutes in the past before the action runs. Delete `ready.signal` before the **Acceptance Gate** passes. `ReadyStateChangedAt` resets and the countdown restarts from zero when the file is recreated. ### To Demonstrate the Gate Reset 1. Create `ready.signal` for `ASA Packer-01`. 2. After 10 minutes, delete the file. 3. Confirm `IsReady` drops to `false` and `ReadyStateChangedAt` resets. 4. Recreate the file and the 15-minute countdown starts over. ### To Observe the Ignored Outcome Before enabling the Definition, manually update one instance to `PackingController A/4` directly from the **Automation Controller Instance** record. Enable the Definition and the task for that instance transitions immediately to `IgnoredNoOp` because the target is already in the desired state. ### To Reset and Repeat 1. Delete `ready.signal` from the **Resource** directory if present. 2. Revert the instance back to `PackingController A/3` from the **Automation Controller Instance** record. 3. Create a new Definition (the original tasks are in a terminal state and will not re-evaluate). ## Troubleshooting ### IsReady Does Not Become True After Creating `ready.signal` If `IsReady` stays `false` after creating the file, check: 1. The File Raw Driver is running and watching the correct directory path for the target resource. 2. The workflow step that handles the file event and sets the `DefinedInWorkflow` flag is reachable from the current instance state. 3. The manager console shows no workflow errors for that instance. ### UpdateControllerVersion Requires the Same Controller Lineage `UpdateControllerVersion` only applies when the source and target versions belong to the same **Controller** definition. You cannot use this action to switch a cell to a completely different controller type.