Blog>
Snippets

Optimizing Retry Attempts in Redux-Saga

Provide a code example illustrating how to limit the number of retry attempts in Redux-Saga to prevent infinite loops while attempting to recover from transient errors.
import { call, put } from 'redux-saga/effects';

function* fetchResource(resource) {
  try {
    const response = yield call(fetch, resource);
    const data = yield response.json();
    yield put({ type: 'FETCH_SUCCEEDED', data });
  } catch (error) {
    yield put({ type: 'FETCH_FAILED', error });
  }
}
This is a basic saga generator function that attempts to fetch a resource. If the fetch succeeds, it dispatches a 'FETCH_SUCCEEDED' action with the data. If the fetch fails, it dispatches a 'FETCH_FAILED' action with the error.
import { delay } from 'redux-saga/effects';

function* retrySaga(operation, maxAttempts = 3, delayTime = 2000) {
  for (let i = 0; i < maxAttempts; i++) {
    try {
      return yield* operation();
    } catch (error) {
      if (i < maxAttempts - 1) {
        yield delay(delayTime);
      } else {
        throw error;
      }
    }
  }
}
This is a utility generator function for adding retry logic to a saga. It attempts to perform an operation up to a maximum number of attempts (`maxAttempts`). Between each attempt, it waits for a specified delay (`delayTime` in milliseconds). If all attempts fail, it rethrows the last caught error.
import { put } from 'redux-saga/effects';

function* resourceFetcher() {
  try {
    const data = yield* retrySaga(() => fetchResource('/api/resource'));
    yield put({ type: 'RESOURCE_FETCH_SUCCESS', data });
  } catch (error) {
    yield put({ type: 'RESOURCE_FETCH_FAILURE', error });
  }
}
This generator function uses the `retrySaga` utility to attempt fetching a resource with retries. If the fetch ultimately succeeds, it dispatches a 'RESOURCE_FETCH_SUCCESS' action. If all attempts fail and it catches an error, it dispatches a 'RESOURCE_FETCH_FAILURE' action.