Makes this effect cancellable by an AbortSignal, such as the one React Query or a
request handler provides.
Once the signal aborts, no further step starts. The effect stops at the next step
boundary (between flatMaps, retries, repeat iterations and IO.gen yields), and no
map, recover or other callback inside it runs after that. The result is a failure
with InterruptedError, which catchTag("InterruptedError", …) can handle outside this
call. Inside it, retry, recover and catchAll cannot swallow the cancellation.
bracket / acquireRelease cleanup still runs, to completion: acquire and release
are not interruptible.IO.never() under
interruptOn never resolves for the same reason. IO.async and IO.tryPromise
thunks receive the region's signal as their argument, so IO.async((signal) => fetch(url, { signal })) aborts the request itself; its rejection is reported as the
cancellation. IO(() => …) thunks get no signal. IO.sleep is not woken early.runSync only sees a signal that was already aborted when this effect starts.E is unknown (effects from IO.async or IO(...)), the union collapses to
unknown; use InterruptedError.is(e) to recognise the cancellation.Re-runs the effect until its output satisfies done, or the max bound is hit.
Value-channel dual of retryWhile: this repeats on success values that
haven't yet met the predicate, whereas the retry* family repeats on failure.
The first failure short-circuits and propagates unchanged. Compose the two
axes when both matter:
Pure sync predicate. Loop stops (successfully) when this returns true.
Optional ReadonlydelayMs?: numberOptional fixed delay between iterations.
Readonlymax: numberMaximum iterations before exhaustion is signaled.
The satisfying value, or RepeatExhausted<A> in the error channel
(carrying the last observed value) if the bound is reached first.
Re-runs the effect while cont holds, or until the max bound is hit.
Symmetric sibling of repeatUntil — mirrors the naming of retryWhile.
repeatWhile(cont) is equivalent to repeatUntil((a) => !cont(a)); the
loop stops successfully as soon as cont returns false.
Pure sync predicate. Loop continues while this returns true.
Optional ReadonlydelayMs?: numberOptional fixed delay between iterations.
Readonlymax: numberMaximum iterations before exhaustion is signaled.
Retries the effect only while a predicate over the error holds.
Useful for selective retry policies — e.g. retry HTTP 5xx but not 4xx,
retry network errors but not validation errors. The predicate is evaluated
BEFORE each retry; returning false short-circuits and re-fails with the
original error.
Optional ReadonlydelayMs?: numberOptional fixed delay between attempts.
Readonlyn: numberMaximum number of retry attempts.
Readonlywhile: (error: E, attempt: number) => booleanPredicate (error, attempt) => boolean (attempt is 1-indexed
for the first retry; if the predicate returns false, the retry is skipped).
Retries the effect with exponential backoff and optional full jitter.
Delay schedule: min(maxMs, baseMs * factor^(attempt-1)). With jitter
enabled, the actual delay is computed * (0.5 + Math.random() * 0.5)
(full jitter, 50–100% of the computed value) — prevents thundering herd.
ReadonlybaseMs: numberInitial delay before the first retry.
Optional Readonlyfactor?: numberBackoff multiplier per attempt. Defaults to 2.
Optional Readonlyjitter?: booleanApply full jitter (50–100% of computed delay). Defaults to true.
Optional ReadonlymaxMs?: numberCap on per-attempt delay. Defaults to 30_000.
Readonlyn: numberMaximum number of retry attempts.
Optional Readonlywhile?: (error: E, attempt: number) => booleanOptional predicate (error, attempt) => boolean gating each retry.
Starts the effect and returns a handle that cancels it, with IO.interruptOn
semantics: after cancel(), no further step runs and result resolves to
Left(InterruptedError). Calling cancel() after the effect finished does nothing.
Requires R = never.
Runs the effect and returns an Exit.
With options.signal, the run stops at the next step once the signal aborts and
returns an Interrupted Exit, with the same rules as IO.interruptOn: no further
step or callback runs, recovery can't swallow it, and cleanup completes. Unlike
interruptOn, E is not widened: the cancellation is reported as Interrupted, not as
a typed InterruptedError. This suits runners (React hooks, query adapters) that
discard a cancelled result rather than handle it.
Fails with TimeoutError if the effect doesn't complete within the specified duration.
Maximum time in milliseconds
Converts to JSON representation.
Converts to string representation.
Makes IO iterable for generator do-notation (yield* syntax). Yields the IO itself, allowing IO.gen to extract the value.