Why not one long command
A single SSH command that waits for the render would sit inside one session for hours, and long commands do get cut off: the article on exit code 124 is about a 17-minute render killed exactly that way. Starting the job and polling it turns one fragile long call into many short ones. Each poll in the run below took roughly 0.4 seconds.
Two things the render tool couldn't do at this length
Its built-in script generator tops out below three minutes of video (2 minutes 47 seconds in my test, even with the paragraph count raised), so a Groq step writes the full script and hands it to the tool. And the tool's text-to-speech call had a 30-second timeout that a script of about 2,000 words always exceeded, failing three retries in a row. Raising that timeout in the tool's config file to 240 seconds and restarting its container fixed it. The setting is shared by every channel using the same tool, but their short scripts never came near 30 seconds, so nothing else changed.
The loop
Start render (SSH) -> Wait 20 min -> Poll status (SSH) -> Parse status (Code)
-> IF ready? yes -> caption pass -> thumbnail -> append to queue
no -> IF attempts >= 20? yes -> alert + release the topic
no -> attempts + 1 -> back to Wait
Choosing the numbers
The ceiling is the poll interval times the maximum attempts: 20 minutes x 20 = 400 minutes, about 6.7 hours, chosen so a render started in the morning still finishes the same day. The first hand-run render of a 15-minute script took roughly two and a half hours of wall-clock time, so the ceiling is well over twice the longest render I had seen. A channel with short renders uses a threshold of 4 instead. A coarse interval keeps the load negligible, and a tighter one would only save minutes on a job measured in hours.
What a real run looked like
The scheduled run on September 17 started at 07:00 and finished at 08:22 UTC. The Groq script call took 4.3 seconds. The Wait node executed four times, 80 minutes of waiting in total, and the caption burn afterwards took under a minute. Render time depends on script length and how long stock-footage downloads take, so a render finishing well inside the ceiling is normal. The ceiling exists for the bad day.
Two details that keep the loop honest
- n8n stores longer waits in its database rather than holding them in memory, so a restart of the n8n process during the wait should not lose the run.
- The exit path matters as much as the happy path. When the attempt limit is hit, the run alerts and releases the topic back to the queue, following the rule in the claim-at-pickup article.
How to size the loop for your own job
Three numbers decide everything: the longest job you have actually seen, how much later than that you are still willing to wait, and how quickly you need to know that the job is done.
| Typical job length | Poll interval | Max attempts | Ceiling |
|---|---|---|---|
| 2 to 5 minutes (short videos) | 2 minutes | 4 to 6 | 8 to 12 minutes |
| 20 to 40 minutes | 5 minutes | 15 | 75 minutes |
| 1 to 3 hours (this explainer) | 20 minutes | 20 | about 6.7 hours |
These are the values I would start with, not rules. The ceiling should be at least twice the longest job you have measured, and the interval should be a small fraction of the typical job length.
The attempt counter
The counter travels with the item through the loop. A Code node after the status poll merges the poll result with the item from the start of the loop and adds one:
// Code node "Parse Status"
const prev = $('Wait for Render').item.json; // item from the start of this round
const status = JSON.parse($json.stdout || '{}');
return [{ json: {
...prev,
attempts: (prev.attempts || 0) + 1,
ready: status.state === 'done' && !!status.video_path,
video_path: status.video_path || null,
} }];
The important part is reading prev by node name. After an SSH node, $json only contains the command's output (code, stdout, stderr), so the task id and the counter would be lost if the loop relied on it.
Things that go wrong with long waits
- Executions pile up. If the schedule fires again before the previous run has finished waiting, two loops poll in parallel. Space the schedule wider than the ceiling, or check for a running job first.
- The job finished but the loop doesn't notice. Check both the state and that the output file exists. A "done" state with no file is a failure.
- Execution data grows. Each round adds node output to the execution. With 20 rounds that is still small, but don't put large payloads, such as base64 media, into the looping item.
- The exit path is never tested. Run the loop once with a very low attempt limit to make sure the alert and the topic reset actually work.
Frequently asked questions
How long can an n8n Wait node wait?
Long waits are supported. n8n stores waits longer than about a minute in its database rather than in memory, so a restart during the wait should not lose the execution.
Why not run the whole render in one SSH command?
A command that runs for hours is likely to be cut off by a timeout, and when it is, the error is easy to misread. Starting the job and polling it turns one long call into many short ones.
How do I choose the maximum number of attempts?
Multiply the poll interval by the attempts to get the ceiling, and make the ceiling at least twice the longest job you have measured.
What should happen when the attempt limit is reached?
Alert a human and release whatever the job had claimed, such as a topic in a queue, so it can be picked again.
n8n Automation Hub