Error Propagation and Retry Logic in createAsyncThunk

Illustrate the implementation of error catching within a recursive createAsyncThunk call, along with a retry mechanism for failed requests.
import { createAsyncThunk } from '@reduxjs/toolkit';

// A helper function to wait for a given amount of time using a Promise
const delay = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

// Our createAsyncThunk with retry logic
const fetchWithRetry = createAsyncThunk(
  async (arg, { rejectWithValue }) => {
    let retryCount = 0;
    const maxRetries = arg.maxRetries;
    const retryDelay = arg.retryDelay;

    try {
      // assuming some API fetching logic like `fetchData()`
      const response = await fetchData();
    } catch (error) {
      while (retryCount < maxRetries) {
        try {
          // Wait before retrying
          await delay(retryDelay);
          const response = await fetchData();
          return;  // Successful fetch
        } catch (err) {
          // We catch the error and continue the loop if the retry count
          // has not exceeded the max number of retries
          if (retryCount >= maxRetries) {
            // Reject with a custom payload if we run out of retries
            return rejectWithValue({ message: 'Max retries reached', error: err });
This code defines an asynchronous thunk action creator using `createAsyncThunk`. It includes a retry mechanism that attempts to fetch data up to a certain number of times (`maxRetries`) with a delay (`retryDelay`) between each attempt. If all attempts fail, the action is rejected with a custom payload. The `rejectWithValue` function allows us to return a custom error payload on rejection.