1---
2title: Retrying Operations
3order: 5
4---
5
6# Retrying Operations
7
8The `retryExchange` lets us retry specific operation, by default it will
9retry only network errors, but we can specify additional options to add
10functionality.
11
12> **Note:** [You can find a code example for `@urql/exchange-retry` in an example in the `urql` repository.](https://github.com/urql-graphql/urql/tree/main/examples/with-retry)
13
14## Installation and Setup
15
16First install `@urql/exchange-retry` alongside `urql`:
17
18```sh
19yarn add @urql/exchange-retry
20# or
21npm install --save @urql/exchange-retry
22```
23
24You'll then need to add the `retryExchange`, exposed by this package, to your `urql` Client:
25
26```js
27import { Client, cacheExchange, fetchExchange } from 'urql';
28import { retryExchange } from '@urql/exchange-retry';
29
30// None of these options have to be added, these are the default values.
31const options = {
32 initialDelayMs: 1000,
33 maxDelayMs: 15000,
34 randomDelay: true,
35 maxNumberAttempts: 2,
36 retryIf: err => err && err.networkError,
37};
38
39// Note the position of the retryExchange - it should be placed prior to the
40// fetchExchange and after the cacheExchange for it to function correctly
41const client = new Client({
42 url: 'http://localhost:1234/graphql',
43 exchanges: [
44 cacheExchange,
45 retryExchange(options), // Use the retryExchange factory to add a new exchange
46 fetchExchange,
47 ],
48});
49```
50
51We want to place the `retryExchange` before the `fetchExchange` so that retries are only performed _after_ the operation has passed through the cache and has attempted to fetch.
52
53## The Options
54
55There are a set of optional options that allow for fine-grained control over the `retry` mechanism.
56
57We have the `initialDelayMs` to specify at what interval the `retrying` should start, this means that if we specify `1000` that when our `operation` fails we'll wait 1 second and then retry it.
58
59Next up is the `maxDelayMs`, our `retryExchange` will keep increasing the time between retries, so we don't spam our server with requests it can't complete, this option ensures we don't exceed a certain threshold. This time between requests will increase with a random `back-off` factor multiplied by the `initialDelayMs`, read more about the [thundering herd problem](https://en.wikipedia.org/wiki/Thundering_herd_problem).
60
61Talking about increasing the `delay` randomly, `randomDelay` allows us to disable this. When this option is set to `false` we'll only increase the time between attempts with the `initialDelayMs`. This means if we fail the first time we'll have 1 second wait, next fail we'll have 2 seconds and so on.
62
63We can declare how many times it should attempt the `operation` with `maxNumberAttempts`, otherwise, it defaults to 2. If you want it to retry indefinitely, you can simply pass in `Number.POSITIVE_INFINITY`.
64
65[For more information on the available options check out the API Docs.](../api/retry-exchange.md)
66
67## Reacting to Different Errors
68
69We can introduce specific triggers for the `retryExchange` to start retrying operations,
70let's look at an example:
71
72```js
73import { Client, cacheExchange, fetchExchange } from 'urql';
74import { retryExchange } from '@urql/exchange-retry';
75
76const client = new Client({
77 url: 'http://localhost:1234/graphql',
78 exchanges: [
79 cacheExchange,
80 retryExchange({
81 retryIf: error => {
82 return !!(error.graphQLErrors.length > 0 || error.networkError);
83 },
84 }),
85 fetchExchange,
86 ],
87});
88```
89
90In the above example we'll retry when we have `graphQLErrors` or a `networkError`, we can go
91more granular and check for certain errors in `graphQLErrors`.
92
93## Failover / Fallback
94
95In case of a network error, e.g., when part the infrastructure is down, but a fallback GraphQL endpoint is available, e.g., from a different provider on a different domain, the `retryWith` option allows for client-side failover. This could also be used in case of a `graphQLError`, for example, when APIs are deployed via a windowing strategy, i.e., a newer version at URL X, while an older one remains at Y.
96
97Note that finer granularity depending on custom requirements may be applicable, and that this does not allow for balancing load.
98
99```js
100const fallbackUrl = 'http://localhost:1337/anotherGraphql';
101
102const options = {
103 initialDelayMs: 1000,
104 maxDelayMs: 15000,
105 randomDelay: true,
106 maxNumberAttempts: 2,
107 retryWith: (error, operation) => {
108 if (error.networkError) {
109 const context = { ...operation.context, url: fallbackUrl };
110 return { ...operation, context };
111 }
112 return null;
113 },
114};
115```