Skip to main content

Cost & Time Limits and Self-Termination

Every workflow carries two guardrails you set when you register it: a maximum cost per run and a maximum execution time. They're there so a misbehaving run — a runaway loop, an unexpectedly expensive call — can't quietly burn your budget or hang forever.

How a breach is caught

As a run executes, it reports each step back to Circus, and on every report the platform tells it the current tally: time consumed, cost consumed, the configured limits, and an abort flag. The moment either limit is reached, that flag flips. Note the boundary is inclusive — reaching a limit exactly counts as a breach (the check is "at or over," not "strictly over").

This feeds a two-layer enforcement model, so a limit is honoured even if one layer fails:

  • Layer 1 — the run stops itself. The Circus nodes inside the workflow watch the abort flag and terminate the run when it trips. This is the normal, prompt path.
  • Layer 2 — the reconciler backstop. A background service periodically inspects running executions and remotely stops any that have breached their limits but failed to self-terminate. Enforcement doesn't depend on the workflow cooperating.

Manual termination

You can also stop a run yourself at any time — the Terminate action on the execution detail page works for queued and running executions (see Reading Execution Logs & Terminating Runs). It's the same mechanism you reach for when a run is clearly going nowhere.

A terminated run — whether it self-terminated on a breach, was caught by the reconciler, or you stopped it — ends as failed_transient: an external, retryable outcome rather than a platform fault. And whatever it consumed up to that point is still logged and costed, so a stopped run's spend is never invisible.