Tide · Reliability

Failed effects and retries (policy.retry)

An effect handler that returns completes its task as done, whatever it returns: a declined card is a valid result. A handler that throws is retried: policy.retry sets the number of retries (max) and the delay between them (baseMs), and backoff: 'exponential' doubles the delay each time. When the retries are exhausted the task is failed with the last error, and its run settles and counts it as failed.

Reflex
{
  id: 'billing.charge',
  intent: 'Charge every season pass on the first of the month.',
  on: {
    clock: {
      every: 'month',
      on: 1,
      at: '03:00',
      tz: 'Europe/Vienna',
    },
  },
  select: {
    query: { table: 'passes' },
    mode: 'each',
    unitKey: 'member',
  },
  effect: {
    name: 'payments.charge',
    input: {
      member: { $ref: '$.row.member' },
      amount: { $ref: '$.row.amount_cents' },
    },
  },
  policy: {
    retry: { max: 2, backoff: 'exponential', baseMs: 600000 },
  },
}
Gateway response per member
{
  ada: 'declines her card, and the handler returns that',
  linus: 'returns 503 every time, and the handler throws',
}
Attempts
Tasks
{
  ada: {
    state: 'done',
    attempt: 1,
    output: { status: 'declined' },
  },
  linus: {
    state: 'retrying',
    attempt: 1,
    error: '503 from the gateway',
  },
}
Run and next due
{
  run: { state: 'fanned', done: 1, failed: 0 },
  nextDue: '2026-10-01 03:10',
}
Output matches the expected value

Runs in this page on the installed package. The input and the expected output are defined by the example.