Skip to content
You are reading the v2 docs, currently in beta.V1 docs
oRPC
Esc
↑↓navigate↵open⌘Jpreview
On this page

Retry Plugin

Automatically retry failed oRPC requests with customizable strategies controlled through client context options.

Setup

import { RetryLinkPlugin, RetryLinkPluginContext } from '@orpc/client/plugins'

interface ClientContext extends RetryLinkPluginContext {}

const link = new RPCLink<ClientContext>({
  plugins: [
    new RetryLinkPlugin(),
  ],
})

Usage

By default, retries are disabled. To enable retries, set the retry count in the request context:

const 
const planets: {
    id: number;
    name: string;
    description?: string | undefined;
}[]
planets
= await
const client: {
    planet: {
        list: ProcedureClient<RetryLinkPluginContext, ZodObject<{
            limit: ZodOptional<ZodNumber>;
            cursor: ZodDefault<ZodNumber>;
        }, $strip>, ZodArray<ZodObject<{
            id: ZodNumber;
            name: ZodString;
            description: ZodOptional<ZodString>;
        }, $strip>>, object>;
        find: ProcedureClient<RetryLinkPluginContext, ZodObject<{
            id: ZodNumber;
        }, $strip>, ZodObject<...>, object>;
        create: ProcedureClient<...>;
    };
}
client
.
planet: {
    list: ProcedureClient<RetryLinkPluginContext, ZodObject<{
        limit: ZodOptional<ZodNumber>;
        cursor: ZodDefault<ZodNumber>;
    }, $strip>, ZodArray<ZodObject<{
        id: ZodNumber;
        name: ZodString;
        description: ZodOptional<ZodString>;
    }, $strip>>, object>;
    find: ProcedureClient<RetryLinkPluginContext, ZodObject<{
        id: ZodNumber;
    }, $strip>, ZodObject<...>, object>;
    create: ProcedureClient<...>;
}
planet
.
list: Client
(input: {
    limit?: number | undefined;
    cursor?: number | undefined;
}, options?: FriendlyClientOptions<RetryLinkPluginContext> | undefined) => PromiseWithError<{
    id: number;
    name: string;
    description?: string | undefined;
}[], Error>
list
({ limit?: number | undefinedlimit: 10 }, {
context?: RetryLinkPluginContext | undefinedcontext: { RetryLinkPluginContext.retry?: Value<Promisable<number>, [Omit<StandardLinkInterceptorOptions<RetryLinkPluginContext>, "next">]> | undefined
Maximum retry attempts before throwing. Use `Number.POSITIVE_INFINITY` for infinite retries (e.g. for AsyncIteratorObject).
@default0
retry
: 3, // Maximum retry attempts
RetryLinkPluginContext.retryDelay?: Value<Promisable<number>, [RetryLinkPluginAttemptOptions<RetryLinkPluginContext>]> | undefined
Delay (in ms) before retrying.
@remarks**Note**: Why 2000ms? The EventSource spec suggests a default retry delay of 2 seconds if it doesn't specify@default(o) => o.lastEventRetry ?? 2000
retryDelay
: 2000, // Delay between retries in ms
RetryLinkPluginContext.shouldRetry?: Value<Promisable<boolean>, [RetryLinkPluginAttemptOptions<RetryLinkPluginContext>]> | undefined
Determine whether to retry.
@default(o) => isRetryableError(o.error)
shouldRetry
: options: RetryLinkPluginAttemptOptions<RetryLinkPluginContext>options => true, // Determines whether to retry based on the error
RetryLinkPluginContext.onRetry?: ((options: RetryLinkPluginAttemptOptions<RetryLinkPluginContext>) => void | ((isSuccess: boolean) => void)) | undefined
Hook called before each retry. Can return a cleanup callback.
onRetry
: (options: RetryLinkPluginAttemptOptions<RetryLinkPluginContext>options) => {
// Hook executed on each retry return (isSuccess: booleanisSuccess) => { // Execute after the retry is complete } }, } })

Client Error Responses

By default, errors from a 4xx response other than 408 and 429 are not retried, since retrying would most likely fail the same way. To retry every error, set shouldRetry to true, or extend the default with isRetryableError:

import { ORPCError } from '@orpc/client'
import { isRetryableError } from '@orpc/client/plugins'

const planets = await client.planet.list({ limit: 10 }, {
  context: {
    retry: 3,
    shouldRetry: ({ error }) => isRetryableError(error) || (error instanceof ORPCError && error.code === 'CONFLICT'),
  }
})

Event Source Simulation

To replicate the behavior of EventSource for an AsyncIteratorObject, use the following configuration:

const streaming = await client.streaming('the input', {
  context: {
    retry: Number.POSITIVE_INFINITY,
  }
})

for await (const message of streaming) {
  console.log(message)
}

Learn More

For implementation details, see the source code.

Last updated on

Was this page helpful?