Skip to main content
import { Timer } from "smithers-orchestrator";

type TimerProps = {
  id: string;
  duration?: string; // "500ms" | "30s" | "2h" | "7d"; exactly one of duration/until required
  until?: string | Date; // ISO 8601 string or Date
  every?: string; // reserved: recurring timers ship in phase 2; throws if set
  skipIf?: boolean;
  dependsOn?: string[];
  needs?: Record<string, string>;
  label?: string;
  meta?: Record<string, unknown>;
  key?: string;
};
<Workflow name="delayed-report">
  <Sequence>
    <Timer id="cooldown" duration="30s" />
    <Task id="report" output={outputs.report} agent={reportAgent}>
      Generate the daily summary report.
    </Task>
  </Sequence>
</Workflow>

Notes

  • Exactly one of duration or until is required; both or neither throws at render time.
  • Produces no output. Past until timestamps fire immediately.
  • Worker restarts during the wait don’t reset the timer.

Durable Suspend and Wake

A waiting timer holds no worker and no CPU. The run’s status becomes waiting-timer, only the absolute fire time is persisted, and the host releases the worker. Tear the worker down or redeploy mid-wait and nothing is lost. The host wakes the run on its own when the fire time arrives. A Gateway sweeps due timers on its scheduler tick (every 1 to 15s), and bunx smithers-orchestrator supervise also scans waiting-timer runs and resumes due ones when you are operating without Gateway. Wake resolution is bounded by the Gateway tick or supervisor interval rather than by a live process. Timers that came due while the host was down fire on the first sweep after it restarts.