n8n logon8n Automation Hub
Build breakdown

Sizing an n8n Wait-and-Poll Loop for a Video That Takes Hours to Render

Build breakdown · n8n workflow · September 19, 2026 · Updated October 13, 2026

One channel's weekly explainer is a 10 to 15 minute video generated end to end by a self-hosted render service. Doing that inside a single SSH node would hit a timeout long before the render finished. The workflow starts the job and checks on it instead. The interesting part is choosing the numbers.

Workflow at a glance
  1. Groq writes the full German script first (about 1,800 to 2,200 words), because the render tool's own script generator topped out under three minutes of video
  2. An SSH node starts the render through the tool's HTTP API and keeps the task id
  3. A Wait node pauses 20 minutes, an SSH poll asks for the task status, and a Code node decides whether the finished video path exists
  4. If not ready, an attempt counter goes up and the loop repeats until it reaches 20, about 6.7 hours of waiting at most
  5. On a real scheduled run the loop went round four times and the whole execution took 1 hour 21 minutes

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

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 lengthPoll intervalMax attemptsCeiling
2 to 5 minutes (short videos)2 minutes4 to 68 to 12 minutes
20 to 40 minutes5 minutes1575 minutes
1 to 3 hours (this explainer)20 minutes20about 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

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.

Long-running jobs that time out inside n8n?

I build start-and-poll loops with sensible ceilings, alerts and clean failure paths.