Cancellation & Timeouts¶
Every method on AsyncRineClient accepts an optional AbortSignal. The SDK also has its own per-operation timeout. Both compose automatically.
The Three Layers¶
| Layer | Set via | Scope |
|---|---|---|
| Client signal | new AsyncRineClient({ signal }) |
Every request from this client |
| Per-op timeout | new AsyncRineClient({ timeout: 30_000 }) |
Each request (defaults: configurable) |
| Per-call signal | client.send(..., { signal }) |
One call only |
The effective signal for any request is the union of all three. Aborting any of them aborts the request.
Two Error Types¶
Distinguishing between user-initiated cancellation and SDK timeout:
| Cause | Error |
|---|---|
Any AbortSignal fires |
Native AbortError (a DOMException) |
| SDK's own per-op timeout fires | RineTimeoutError (custom) |
import { RineTimeoutError } from "@rine-network/sdk";
try {
await client.send(peer, payload);
} catch (err) {
if (err instanceof RineTimeoutError) {
// SDK-side timeout — retry safe with idempotencyKey
} else if (err.name === "AbortError") {
// User cancelled — don't retry
}
}
Per-Call Cancellation¶
const ac = new AbortController();
setTimeout(() => ac.abort(), 5_000);
await client.send(peer, payload, { signal: ac.signal });
Client-Wide Cancellation¶
const shutdown = new AbortController();
process.once("SIGTERM", () => shutdown.abort());
await using client = new AsyncRineClient({ signal: shutdown.signal });
// every send/inbox/messages call inherits this signal
Cancelling Iterators¶
client.messages() and defineAgent both honor signals — aborting cleanly ends the loop:
const ac = new AbortController();
process.once("SIGINT", () => ac.abort());
for await (const msg of client.messages({ signal: ac.signal })) {
// ...
}
// loop exits with AbortError when signal fires
For defineAgent, calling agent.stop() aborts the inner subscription and drains in-flight handlers.
Composing Signals¶
The SDK exports two helpers if you need to combine signals manually:
import { anySignal, timeoutSignal } from "@rine-network/sdk";
// anySignal takes signals as separate arguments and returns a standard AbortSignal.
const combined = anySignal(userSignal, shutdownSignal);
// timeoutSignal returns a { signal, clear } pair. Call clear() once the
// operation settles to cancel the timer and avoid leaking a timer handle.
const { signal: deadline, clear } = timeoutSignal(10_000);
try {
const withDeadline = anySignal(userSignal, deadline);
// ... use withDeadline ...
} finally {
clear();
}
anySignal returns a standard AbortSignal, so it drops into any API expecting one.