@seqera/node-red-seqera
Version:
Node-RED nodes for interacting with the Seqera Platform API
231 lines (230 loc) • 7.82 kB
JSON
[
{
"id": "resume_example_tab",
"type": "tab",
"label": "Auto-resume on workflow failure",
"disabled": false,
"info": "# Auto-resume on workflow failure\n\nThis example demonstrates how to automatically resume a failed workflow using a **simple loop pattern**. When a workflow fails, it loops directly back to the launch node which automatically retries with resume enabled.\n\n## How it works (Loop Pattern)\n\n1. **Trigger** - Click inject to start (or use any trigger)\n2. **Launch** - Launches workflow (reads workflow ID from msg.workflowId for resume)\n3. **Monitor** - Monitors workflow status with three outputs\n4. **On Success** - Flow completes (output 2)\n5. **On Failure** - Loops directly back to Launch node (output 3)\n\n## Key Features\n\n- **Single Launch Node**: The same node handles both initial launch and resume\n- **Direct Loop**: Failed workflows loop directly back - no intermediate nodes needed!\n- **Automatic resume**: The launch node reads msg.workflowId and automatically:\n - Fetches the session ID from the failed workflow\n - Enables Nextflow resume\n - Uses the correct commit/revision\n\n## Setup Instructions\n\n1. Double click the **\"Launch workflow\"** node:\n - Configure Seqera Platform credentials\n - Set launchpad name\n - **Important**: \"Resume from\" field is set to read from \"msg.workflowId\" (type: msg)\n\n2. Configure the **\"Monitor workflow\"** node with same Seqera config\n\n3. Click **\"Deploy\"** in Node-RED (top right)\n\n4. Click the **Inject** node to start\n\n## Important Notes\n\n- The resumed workflow must use the same work directory as the original\n- Your compute environment must have access to the cached results\n- **This creates an infinite loop** that retries until success - add retry limit logic if needed\n- Each retry uses Nextflow's `-resume` to skip completed tasks",
"env": []
},
{
"id": "inject_trigger",
"type": "inject",
"z": "resume_example_tab",
"name": "Trigger workflow",
"props": [],
"repeat": "",
"crontab": "",
"once": false,
"onceDelay": 0.1,
"topic": "",
"x": 140,
"y": 180,
"wires": [["launch_node"]]
},
{
"id": "launch_node",
"type": "seqera-workflow-launch",
"z": "resume_example_tab",
"name": "Launch workflow",
"seqera": "",
"launchpadName": "nf-core-rnaseq",
"launchpadNameType": "str",
"paramsKey": "{}",
"paramsKeyType": "json",
"params": [
{
"name": "outdir",
"value": "./results",
"valueType": "str"
}
],
"runName": "",
"runNameType": "str",
"resumeWorkflowId": "workflowId",
"resumeWorkflowIdType": "msg",
"workspaceId": "",
"workspaceIdType": "str",
"sourceWorkspaceId": "",
"sourceWorkspaceIdType": "str",
"x": 350,
"y": 180,
"wires": [["monitor_node"]]
},
{
"id": "monitor_node",
"type": "seqera-workflow-monitor",
"z": "resume_example_tab",
"name": "Monitor workflow",
"seqera": "",
"workflowId": "workflowId",
"workflowIdType": "msg",
"workspaceId": "",
"workspaceIdType": "str",
"keepPolling": true,
"poll": "15",
"pollUnits": "seconds",
"x": 570,
"y": 180,
"wires": [[], ["debug_success"], ["73841c107d946dcc"]]
},
{
"id": "debug_success",
"type": "debug",
"z": "resume_example_tab",
"name": "✓ Success!",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 770,
"y": 180,
"wires": []
},
{
"id": "comment_trigger",
"type": "comment",
"z": "resume_example_tab",
"name": "Trigger",
"info": "Click this inject node to start the workflow.\n\nIn a real automation, you might trigger this\nfrom a file upload, scheduled time, or other event.\n\nThe initial message has no workflow ID,\nso the launch node will start fresh.",
"x": 130,
"y": 120,
"wires": []
},
{
"id": "comment_launch",
"type": "comment",
"z": "resume_example_tab",
"name": "Launch (with loop)",
"info": "This node handles BOTH initial launch AND resume.\n\n**Configuration:**\n- Resume from: `msg.workflowId` (type: msg)\n\n**First run:** `msg.workflowId` is `undefined` → launches fresh\n**Loop back:** `msg.workflowId` is populated → fetches session ID and resumes\n\nThe same node works for both cases! When a workflow ID is provided,\nthe node automatically fetches the session ID from the API and enables resume.",
"x": 350,
"y": 120,
"wires": []
},
{
"id": "comment_monitor",
"type": "comment",
"z": "resume_example_tab",
"name": "Monitor",
"info": "Monitors the workflow status.\n\n**Three outputs:**\n1. Running status (not connected - no action needed)\n2. Success (workflow completed) → Flow ends here with debug output\n3. Failed (workflow errored) → Loops directly back to Launch node\n\nOutput 3 connects back to the launch node, creating the resume loop.",
"x": 550,
"y": 120,
"wires": []
},
{
"id": "comment_outputs",
"type": "comment",
"z": "resume_example_tab",
"name": "Outputs",
"info": "**Success** - Final successful completion (debug output)",
"x": 770,
"y": 120,
"wires": []
},
{
"id": "73841c107d946dcc",
"type": "change",
"z": "resume_example_tab",
"name": "Increment retry counter",
"rules": [
{
"t": "set",
"p": "_retries",
"pt": "msg",
"to": "_retries ? _retries + 1 : 1",
"tot": "jsonata"
}
],
"action": "",
"property": "",
"from": "",
"to": "",
"reg": false,
"x": 190,
"y": 280,
"wires": [["d462ab97a42a95e0"]]
},
{
"id": "d462ab97a42a95e0",
"type": "switch",
"z": "resume_example_tab",
"name": "<= 3 retries?",
"property": "_retries",
"propertyType": "msg",
"rules": [
{
"t": "lte",
"v": "3",
"vt": "str"
},
{
"t": "else"
}
],
"checkall": "true",
"repair": false,
"outputs": 2,
"x": 410,
"y": 280,
"wires": [["launch_node"], ["59af93d472724fe5"]]
},
{
"id": "59af93d472724fe5",
"type": "debug",
"z": "resume_example_tab",
"name": "✘ Give up",
"active": true,
"tosidebar": true,
"console": false,
"tostatus": false,
"complete": "true",
"targetType": "full",
"statusVal": "",
"statusType": "auto",
"x": 590,
"y": 280,
"wires": []
},
{
"id": "3f8061dd9c9fca4c",
"type": "comment",
"z": "resume_example_tab",
"name": "Counter",
"info": "This `change` node sets `msg._retries` if\nnot already set, and increments it by\none if it does.\n\nSeqera Node-RED nodes pass through\nunrecognised `msg` variables, so this\npersists through the loop for each launch.\n\nMultiple pipeline launches can be triggered\nin parallel and each will have its own\nretry counter in the `msg` object.",
"x": 150,
"y": 320,
"wires": []
},
{
"id": "5ee40e98b81ff1e7",
"type": "comment",
"z": "resume_example_tab",
"name": "Switch",
"info": "A Node-RED `switch` node checks if we have\nhad 3 retries already by inspecting our\n`msg._retries` counter.",
"x": 390,
"y": 320,
"wires": []
},
{
"id": "9d80d663bb701bf6",
"type": "comment",
"z": "resume_example_tab",
"name": "Failure",
"info": "**Failure** - Give up after 3 attempts (debug output)",
"x": 590,
"y": 320,
"wires": []
},
{
"id": "ec31addc40995619",
"type": "global-config",
"env": [],
"modules": {
"@seqera/node-red-seqera": "1.2.0"
}
}
]