API reference@evolu/commonTask › retry

function retry<T, E, D, Output>(
  task: Task<T, E, D>,
  schedule: Schedule<Output, Exclude<E, AbortError>>,
  __namedParameters?: RetryOptions<Exclude<E, AbortError>, Output>,
): Task<T, RetryTaskError<E>, D>;

Defined in: packages/common/src/Task.ts:3979

Retries a Task according to a Schedule.

Use retry for failure recovery: it repeats after Err and wraps the final domain error. Use repeat for success-driven loops: it repeats after Ok and returns the Task's natural Result.

AbortError passes through unchanged when returned as a Result error, such as from daemon. Abort from run(task) remains Fiber control flow. Other errors are domain errors: retrying continues while the schedule yields another delay and RetryOptions.shouldRetry returns true. When retrying stops, retry returns RetryError with the final domain error as lastError.

AbortError recognition is structural. Domain errors, especially values parsed from untrusted input, must not use the reserved AbortError shape.

Retrying failures

import {
  assertErr,
  assertType,
  createRun,
  err,
  recurs,
  retry,
  type Result,
  type RetryTaskError,
  type Task,
  type Typed,
} from "@evolu/common";

const fetchData: Task<string, ServiceUnavailableError> = () =>
  err({ type: "ServiceUnavailable" });

interface ServiceUnavailableError extends Typed<"ServiceUnavailable"> {}

const fetchWithRetry = retry(fetchData, recurs(2));

await using run = createRun();
const result = await run(fetchWithRetry);
assertType<
  Result<string, RetryTaskError<ServiceUnavailableError>>,
  typeof result
>();
assertErr(result, {
  type: "RetryError",
  attempts: 3,
  lastError: { type: "ServiceUnavailable" },
});

Filtering retries

import {
  assertErr,
  createRun,
  err,
  recurs,
  retry,
  type Task,
  type Typed,
} from "@evolu/common";

const fetchData: Task<
  string,
  TemporaryFailureError | PermanentFailureError
> = () => err({ type: "PermanentFailure" });

interface TemporaryFailureError extends Typed<"TemporaryFailure"> {}

interface PermanentFailureError extends Typed<"PermanentFailure"> {}

const fetchWithRetry = retry(fetchData, recurs(5), {
  shouldRetry: (error) => error.type !== "PermanentFailure",
});

await using run = createRun();
const result = await run(fetchWithRetry);
assertErr(result, {
  type: "RetryError",
  attempts: 1,
  lastError: { type: "PermanentFailure" },
});