Skip to main content

Cancellation & Timeouts

Cancellation

There may be cases where you want to cancel a call, for example because the user closed a dialog. All client methods take an optional AbortSignal as an argument for this purpose. If this signal is aborted, the browser stops the request, and the fetch API raises an AbortError to abort the code path of the application.

Connect converts those errors into a ConnectError with code Canceled, so that you can handle cancellation appropriately:

import { createPromiseClient, ConnectError, Code } from "@connectrpc/connect";

const client = createPromiseClient(ElizaService, ...);

// For the sake of this example, let's cancel the request right away
const abort = new AbortController();
abort.abort();

try {
await client.say({sentence: "I feel..."}, { signal: abort.signal });
} catch (err) {
if (err instanceof ConnectError && err.code != Code.Canceled) {
// handle the genuine error, ignoring cancelled requests
}
}

Timeouts

Similar to the signal option for cancellation, there is also the timeoutMs option, which allows you to specify a timeout, in milliseconds, for an individual call. The timeout value is specified in the same options object described above.

When a timeout is reached before the request has been completed, a ConnectError with code DeadlineExceeded will be thrown.

An example using a timeout of 3 seconds:

try {
await client.say({sentence: "Hello"}, { timeoutMs: 3000 });
} catch (err) {
if (err instanceof ConnectError && err.code === Code.DeadlineExceeded) {
// handle the timeout error
}
}

The timeout value is sent to the server, and honored on the server (and typically also on the client). This allows for propagation of the timeout to upstream services.

Timeouts in Connect are the equivalent of deadlines in gRPC. They both behave similarly in that they will throw a "deadline exceeded" error. Since Connect's defined error codes map to the same codes and semantics as gRPC, this allows for easy interop between the two protocols.

There is no silver bullet to error handling with async/await and cancellation or timeout errors as they both can force you to handle exceptional flow. In general, we recommend to let the exception travel up to a central error handler in your application, and only catch errors in the case they need to be explicitly handled in your business logic.

But your use case may vary, and we encourage you to roll your own client if you want to represent errors differently when handling cancellations and timeouts.