Skip to content

timer://

Consumer-only periodic-firing source. Drops a synthetic exchange into the route every period, optionally rate-limited or wall-clock anchored. Supports fixed-rate vs fixed-delay scheduling, repeatCount cap, wall-clock first fire via time + pattern, optional metadata headers, rapid-fire delay<0 mode, and multiple consumers per endpoint.

timer:// is for in-process schedules tied to the process lifetime. For cron expressions, use cron://; for cluster-wide scheduled work, use a real scheduler.

URI shape

timer://<name>[?period=1s&delay=0s&repeatCount=0&fixedRate=false&...]

<name> is an identifier (no functional meaning beyond logging and metadata headers). Multiple consumers on the same name share a single scheduler — every consumer receives every tick.

Parameters

Param Type Default Description
name path — Timer endpoint identifier.
timerName path-alias — URI path token alias for name.
period duration 1s Interval between fires. 0 triggers one-shot.
delay duration 0s Initial delay before the first fire. Negative ⇒ rapid-fire mode (tight loop, no timer).
repeatCount integer 0 Max number of fires; 0 = unlimited.
fixedRate boolean false true ⇒ fixed-rate (gap = period, even if processing overruns). false ⇒ fixed-delay (gap = period after processing completes).
includeMetadata boolean false Set the HelixTimer* properties and HelixTimerFiredTime/HelixTimerMessageTimestamp In headers (see below).
time string — Wall-clock time for the first fire. Parsed as RFC3339, then via pattern if set, then default formats.
pattern string — Custom Go time-format pattern (NOT Java) for parsing time. Example: 2006-01-02T15:04:05.
daemon boolean true Accepted for cross-framework compat; no-op in Helix.
synchronous boolean false Accepted for cross-framework compat; Helix is synchronous by default.
runLoggingLevel enum trace Log level for per-tick start/complete lines. trace/debug/info/warn/error/off.

Durations accept Go format (1s, 500ms) or integer milliseconds.

Body shape

The In body of each tick is the endpoint name (a string). Set your own body in the next route step if needed (e.g. setBody).

Headers

Set unconditionally on every tick (back-compat):

Header Type Description
firedTime time.Time The instant the tick was generated.
firedCount int 0-based fire counter.

Set when includeMetadata=true:

Exchange property Description
HelixTimerCounter 1-based fire counter.
HelixTimerName Endpoint name.
HelixTimerPeriod Period in milliseconds.
HelixTimerFiredTime Fire instant.
HelixTimerTime Wall-clock first-fire time (if time set).
In header Description
HelixTimerFiredTime Fire instant.
HelixTimerMessageTimestamp Fire instant as unix-millis.

Examples

Heartbeat every 10 seconds:

- id: heartbeat
  from: timer://heartbeat?period=10s
  steps:
    - setBody:
        starlang: |
          {"ts": now(), "service": "ingest"}
    - to: log://hb

Fire once at startup, then exit:

- id: bootstrap
  from: timer://once?repeatCount=1&period=0s
  steps:
    - to: postgres://schema/migrate

Wall-clock first fire, then every hour:

- id: hourly
  from: timer://daily?time=2026-06-04T08:00:00&period=1h

Fixed-rate (don't drift even if processing is slow):

- id: poll
  from: timer://poll?period=1s&fixedRate=true
  steps:
    - to: http://upstream/health

Burst-test a downstream queue:

- id: burst
  from: timer://burst?delay=-1ms&repeatCount=10000   # rapid-fire mode
  steps:
    - to: seda://to-process

Behavior notes

  • timer:// is consumer-only. CreateProducer returns ErrProducerNotSupported. Use setBody if you need to push to a scheduled route.
  • Multiple consumers share one scheduler. Two routes pointing from: timer://x?period=1s register on the same Endpoint; the scheduler fires once per tick and dispatches to each non-suspended consumer.
  • fixedRate vs default. Default is fixed-delay: gap between fires includes processing time, so a slow processor stretches the cadence. fixedRate=true keeps the clock strict (still synchronous though — if processing overruns the period, fires queue up serially).
  • Rapid-fire (delay<0). Bypasses the timer entirely and tight-loops through repeatCount. Use only when you want to flood a queue from a test, with runtime.Gosched() called every 100 fires.
  • One-shot (period=0). Fires once after the initial wait, then exits cleanly. Combine with repeatCount=1 for explicit clarity.
  • Pattern is Go, not Java. Use 2006-01-02T15:04:05, not yyyy-MM-dd….

Source

  • pkg/component/timer/timer.go — Component, Endpoint, Consumer, scheduler logic, time/pattern parsing.

See also

  • Cron expressions instead of intervals: cron://