-
-
Notifications
You must be signed in to change notification settings - Fork 559
Update Live Workflow
Important
This feature requires xyOps v1.0.89 or newer.
The update_active_job API can modify a workflow while it is running. This makes it possible for one workflow job to change how future nodes will run, based on anything the current job has learned.
Code running inside a workflow job can update its parent workflow directly. This example "retargets" every unlaunched Event and Job node in the current parent workflow, to a specified list of new targets.
It assumes you are using the Shell Plugin, and it relies on the xyOps SDK for Node.js which is pre-installed with both xyOps and xySat (so you can use it without having to install anything).
#!/usr/bin/env node
const { api, job } = require('@pixlcore/xyops-sdk');
const targets = ['YOUR_TARGET_ID'];
(async function() {
try {
await job.read();
const parentJobID = job.workflow.job;
let result = await api.getJob({ id: parentJobID });
if (result.err) throw result.err;
const workflow = result.data.job.workflow;
const nodes = workflow.nodes.filter(function(node) {
return ((node.type == 'event') || (node.type == 'job')) && !workflow.state[node.id];
});
nodes.forEach(function(node) {
node.data.targets = targets;
});
result = await api.updateActiveJob({
id: parentJobID,
workflow: { nodes: workflow.nodes }
});
if (result.err) throw result.err;
job.finalSuccess('Retargeted ' + nodes.length + ' future workflow node(s).');
}
catch (err) {
job.finalError(1, err.message || String(err));
}
})();Replace YOUR_TARGET_ID with your server or group target ID. The current job must be running inside a workflow so job.workflow.job contains the parent Job ID.
The job also needs a Secret Vault variable named XYOPS_API_KEY, created from an API Key with the Update Jobs privilege. The SDK automatically uses the job's conductor URL and API Key for both calls.
The script fetches the live parent workflow and checks every node. An Event or Job node without an entry in workflow.state has not launched yet, so the script replaces its targets. It then submits the complete nodes array. Other workflow properties, including connections and runtime state, are preserved by the API's shallow workflow merge.
For a reusable version, we will build a Retarget Workflow Nodes Action Plugin. You can attach it to an Event or Job node in a workflow, enter a comma-separated list of future Workflow Node IDs, select one or more targets, and update all of those nodes before they launch.
For example, one Retarget Workflow Nodes action running on the current job can update all of these future nodes at once:
- Node
#nk3m7x2q - Node
#n8v4p2az - Node
#nt6c9w5r
The listed nodes do not need to be directly connected to the current node. They can be anywhere later in the workflow, as long as they have not started yet and their type is event or job.
An Action Plugin receives a JSON document on STDIN. For job actions, xyOps includes the complete JobHookData object. The current sub-job is available in the top-level job property.
For a job running inside a workflow, job.workflow.job contains the parent workflow's live Job ID. This is the only workflow location value the plugin needs because the destination nodes are supplied explicitly in its parameters.
The plugin also receives two custom parameters:
| Parameter | Description |
|---|---|
node_ids |
A comma-separated list of Workflow Node IDs to update. |
targets |
The new target array for all listed nodes. |
The plugin uses these values to perform the following steps:
- Parse the Node IDs in
params.node_ids. - Fetch the parent workflow job with the xyOps SDK and
get_job. - Locate every requested Node ID in
workflow.nodes. - Replace each node's
data.targetsarray with the selected targets. - Submit the complete
workflow.nodesarray through the SDK andupdate_active_job.
The workflow property has special shallow-merge behavior in update_active_job. Sending workflow.nodes does not replace workflow.connections, workflow.state, workflow.jobs, or any other omitted workflow properties. However, nodes is itself an array, so the plugin must fetch and submit the complete array.
The Action Plugin needs an API Key to call get_job and update_active_job on the local conductor.
- Open API Keys in the xyOps sidebar.
- Click New API Key.
- Give it a clear title, such as
Retarget Live Workflow. - Grant it the Update Jobs privilege.
- Save the API Key.
- Copy the generated key value immediately.
The API Key secret is only shown once, so keep it handy for the next step.
Tip
Use a dedicated API Key for this plugin, and only grant it the Update Jobs privilege.
Store the API Key in a Secret Vault so it never needs to appear in the plugin source code or parameters.
- Open Secrets in the xyOps sidebar.
- Click New Vault.
- Give it a title, such as
Live Workflow Credentials. - Add the following secret variable:
| Field | Value |
|---|---|
| Variable Name | XYOPS_API_KEY |
| Variable Value | The API Key copied in Step 1 |
- Save the vault.
You can leave Plugin Access empty for now. We will assign the plugin after creating it.
Now create the reusable Action Plugin.
- Open Plugins in the xyOps sidebar.
- Click New Plugin.
- Set Plugin Title to
Retarget Workflow Nodes. - Check Plugin Enabled.
- Set Type to Action Plugin.
- Set Executable to:
node. - Click Edit Script and paste in the following code:
// Retarget Workflow Nodes
const { api } = require('@pixlcore/xyops-sdk');
let inputJSON = '';
process.stdin.setEncoding('utf8');
process.stdin.on('data', function(chunk) {
inputJSON += chunk;
});
process.stdin.on('end', async function() {
try {
const input = JSON.parse(inputJSON);
const nodeIDs = input.params.node_ids.split(/\s*,\s*/);
const parentJobID = input.job.workflow.job;
let result = await api.getJob({ id: parentJobID });
if (result.err) throw result.err;
const workflow = result.data.job.workflow;
const nodes = workflow.nodes.filter(function(node) {
return nodeIDs.includes(node.id);
});
nodes.forEach(function(node) {
node.data.targets = input.params.targets;
});
result = await api.updateActiveJob({
id: parentJobID,
workflow: { nodes: workflow.nodes }
});
if (result.err) throw result.err;
console.log(JSON.stringify({
xy: 1,
code: 0,
description: 'Retargeted workflow nodes: #' + nodes.map(function(node) { return node.id; }).join(', #')
}));
}
catch (err) {
console.log(JSON.stringify({
xy: 1,
code: 1,
description: err.message || String(err)
}));
}
});The xyOps SDK is pre-installed on the conductor, so this script does not require an NPM install or a separate plugin dependency.
Still on the plugin edit page, add the following two parameters.
| Field | Value |
|---|---|
| Param ID | node_ids |
| Label | Workflow Node IDs |
| Control Type | Text Box |
| Required | Checked |
| Caption | Enter one or more future Event or Job Node IDs, separated by commas. |
Enter values using a comma-separated format such as:
nk3m7x2q, n8v4p2az, nt6c9w5r
Whitespace surrounding each ID is ignored.
| Field | Value |
|---|---|
| Param ID | targets |
| Label | Targets |
| Control Type | System Menu |
| System Menu | Targets |
| Multi-Select Menu | Checked |
| Required | Checked |
| Caption | Select the new targets for all listed workflow nodes. |
The Targets system menu combines all valid server groups and individual servers. With Multi-Select Menu checked, the selected values are passed to the plugin as an array in input.params.targets.
Save the plugin after adding both parameters.
For reference, the resulting parameter definitions are equivalent to:
[
{
"id": "node_ids",
"title": "Workflow Node IDs",
"type": "textarea",
"value": "",
"caption": "Enter one or more future Event or Job Node IDs, separated by commas.",
"required": true
},
{
"id": "targets",
"title": "Targets",
"type": "system",
"list_id": "targets",
"caption": "Select the new targets for all listed workflow nodes.",
"multiple": true,
"required": true
}
]Now give the plugin access to the API Key secret.
- Open Secrets.
- Edit the
Live Workflow Credentialsvault created earlier. - Find Plugin Access.
- Select the
Retarget Workflow Nodesplugin. - Save the vault.
xyOps exports the vault variable as XYOPS_API_KEY when the plugin runs. It also automatically exports XYOPS_BASE_URL for Action Plugins. The SDK reads both variables during startup and handles authentication and URL construction for us.
Create or edit a workflow containing the future Event or Job nodes you want to retarget.
- Edit each future node and copy the Node ID displayed in the dialog title.
- Add an Action node and select the
Retarget Workflow NodesAction Plugin. - Connect the Action node to the Event or Job whose result should trigger the update.
- Select the desired action condition, such as Success, Error, or Complete.
- Enter the future Node IDs in Workflow Node IDs, separated by commas.
- Select the new server groups or servers in Targets.
- Save the workflow.
The action condition only controls when the plugin runs. It does not affect which nodes are selected. The explicit node_ids parameter makes the destination list clear, even when the workflow contains multiple branches or several wire conditions.
Note
The plugin is designed for workflow Event and Job nodes. A standalone plugin test does not contain job.workflow.job, so the full behavior must be tested in a small workflow.
Before using this in production, make a small workflow with one current job and two future jobs:
- Configure the current node to finish successfully after a short delay.
- Configure both future nodes with recognizable original targets.
- Copy the two future Workflow Node IDs into the Action Plugin's Workflow Node IDs field.
- Select a different safe target in the action's Targets menu.
- Run the workflow.
- Open the Action result and confirm that it reports both updated Node IDs.
- Open each future sub-job after it runs and confirm that its target list contains the newly selected target.
The workflow definition itself is not changed. Only the live workflow Job record is updated for that one run, so the next run starts with the targets saved in the original workflow definition.
The reusable parameters are configured independently on each Action node. This makes it easy to select different node lists and targets based on the current job's result:
- Add one
Retarget Workflow NodesAction on the Success condition, listing the nodes and targets for the successful path. - Add another on the Error condition, listing diagnostic nodes or fallback targets.
- Use Complete when the same retargeting should happen regardless of the current job's result.
For more advanced rules, you can extend the script to inspect any data included in input.job, including result codes, descriptions, tags, and workflow data, before choosing the final Node IDs or targets.
Standard remote jobs are owned by xySat while they execute. xySat sends full Job updates back to the conductor, so update_active_job rejects those jobs while their job.remote property is set.
This plugin does not update the remote sub-job. It reads the parent ID from job.workflow.job and updates the top-level workflow Job instead. The parent workflow remains owned by the conductor for its entire run, so its future node definitions can be safely changed while a sub-job is completing.
The Secret Vault is not assigned to the Action Plugin, or the variable name does not exactly match XYOPS_API_KEY. Edit the vault, check Plugin Access, and verify the variable name.
The action did not receive job.workflow.job. Make sure it is attached to an Event or Job node inside a workflow. This error is expected if you use the standalone Action Plugin test dialog.
Workflow Node IDs are eight-character lowercase alphanumeric strings beginning with n. Enter a comma-separated list such as nk3m7x2q, n8v4p2az, without labels, quotes, or hash symbols.
One of the IDs does not exist in the live workflow. Check for a typo and make sure you copied the Node ID from the same workflow definition.
The listed ID belongs to an Action, Limit, Controller, Trigger, or Note node. This example only changes target arrays on event and job nodes.
The action ran too late to safely change one of the listed nodes. Move the action earlier in the workflow or remove that Node ID from the list.
Verify that the API Key has the Update Jobs privilege.
The parent workflow completed before the API call arrived, or the wrong Job ID was supplied. The plugin must call update_active_job with job.workflow.job, not the current sub-job's job.id.
The same API can make other changes to future workflow nodes. For example, an Action Plugin can change future parameters, algorithms, tags, labels, or replay settings.
It can even add new nodes while a workflow is running. To do this, fetch the live workflow, append new entries to the complete workflow.nodes array, append the required wires to the complete workflow.connections array, and submit both arrays:
const response = await api.updateActiveJob({
id: parentJobID,
workflow: {
nodes: completeUpdatedNodes,
connections: completeUpdatedConnections
}
});Each new node needs a unique lowercase alphanumeric ID, valid x and y coordinates, and data appropriate for its node type. Each new connection needs its own unique ID plus valid source and dest Node IDs. Most importantly, the new connections must make the node reachable from workflow execution that has not happened yet.