logologo
Guide
Practice
Configuration
Plugins
Showcase
Blog
Ecosystem
Module Federation Examples
Practical Module Federation
Zephyr Cloud
Nx
简体中文
English
Guide
Practice
Configuration
Plugins
Showcase
Blog
Module Federation Examples
Practical Module Federation
Zephyr Cloud
Nx
简体中文
English
logologo

Development

Plugin System

Plugins

Node Plugin
Retry Plugin
Building a Custom Retry Plugin

Retry Plugin#

Edit this page on GitHub
Previous PageNode Plugin
Next PageBuilding a Custom Retry Plugin

#Retry Plugin

The Retry Plugin provides a robust retry mechanism for Module Federation. When remote modules or resources fail to load, it retries automatically to keep your app stable.

#Features

  • Automatic retries: Improve stability by retrying failed resource loads
  • Domain rotation: Switch across multiple backup domains automatically
  • Cache-busting: Add query parameters to avoid cache interference on retries
  • Flexible config: Customize retry times, delay, and callbacks

#Install

npm install @module-federation/retry-plugin

#Migration Guide

#From v0.18.x to v0.19.x

The plugin configuration has been simplified. The old fetch and script configuration objects are deprecated:

// ❌ Old way (deprecated)
RetryPlugin({
  fetch: {
    url: 'http://localhost:2008/not-exist-mf-manifest.json',
    fallback: () => 'http://localhost:2001/mf-manifest.json',
  },
  script: {
    url: 'http://localhost:2001/static/js/async/src_App_tsx.js',
    customCreateScript: (url, attrs) => { /* ... */ },
  }
})

// ✅ New way
RetryPlugin({
  retryTimes: 3,
  retryDelay: 1000,
  domains: ['http://localhost:2001'],
  manifestDomains: ['http://localhost:2001'],
  addQuery: ({ times, originalQuery }) => `${originalQuery}&retry=${times}`,
})

#Usage

#Method1: Used in the build plugin

rspack.config.ts
import { pluginModuleFederation } from '@module-federation/rsbuild-plugin';
import { defineConfig } from '@rsbuild/core';

export default defineConfig({
  plugins: [
    pluginReact(),
    pluginModuleFederation({
      runtimePlugins: [
        path.join(__dirname, './src/runtime-plugin/retry.ts'),
      ],
    }),
  ],
});
// ./src/runtime-plugin/retry.ts
import { RetryPlugin } from '@module-federation/retry-plugin';
const retryPlugin = () => RetryPlugin({
  retryTimes: 3,
  retryDelay: 1000,
  manifestDomains: ['https://domain1.example.com', 'https://domain2.example.com'],
  domains: ['https://cdn1.example.com', 'https://cdn2.example.com'],
  addQuery: ({ times, originalQuery }) => `${originalQuery}&retry=${times}`,
  onRetry: ({ times, url }) => console.log('retry', times, url),
  onSuccess: ({ url }) => console.log('success', url),
  onError: ({ url }) => console.log('error', url),
})
export default retryPlugin;

#Method2: Used in the pure runtime

import { createInstance, loadRemote } from '@module-federation/enhanced/runtime';
import { RetryPlugin } from '@module-federation/retry-plugin';

const mf = createInstance({
  name: 'federation_consumer',
  remotes: [],
  plugins: [
    RetryPlugin({
      retryTimes: 3,
      retryDelay: 1000,
      manifestDomains: ['https://domain1.example.com', 'https://domain2.example.com'],
      domains: ['https://cdn1.example.com', 'https://cdn2.example.com'],
      addQuery: ({ times, originalQuery }) => `${originalQuery}&retry=${times}`,
      onRetry: ({ times, url }) => console.log('retry', times, url),
      onSuccess: ({ url }) => console.log('success', url),
      onError: ({ url }) => console.log('error', url),
    }),
  ],
});

#Configuration

#Basic

retryTimes

  • Type: number
  • Optional
  • Number of retries, default is 3

retryDelay

  • Type: number
  • Optional
  • Delay between retries in milliseconds, default is 1000

#Advanced

domains

  • Type: string[]
  • Optional
  • Backup domains for rotation. Default is an empty array

addQuery

  • Type: boolean | ((context: { times: number; originalQuery: string }) => string)
  • Optional
  • Whether to append a query parameter when retrying, default is false
  • If a function is provided, it receives retry count and the original query string, and should return the new query string

fetchOptions

  • Type: RequestInit
  • Optional
  • Custom fetch options, default is an empty object

manifestDomains

  • Type: string[]
  • Optional
  • Domain rotation list used when fetching the manifest (e.g. mf-manifest.json). Takes precedence over domains for manifest fetch retries. Other resources still use domains.

#Callbacks

onRetry

  • Type: ({ times, domains, url, tagName }: { times?: number; domains?: string[]; url?: string; tagName?: string }) => void
  • Optional
  • Triggered on each retry
  • Params: times current retry number, domains domain list, url request URL, tagName resource type

onSuccess

  • Type: ({ domains, url, tagName }: { domains?: string[]; url?: string; tagName?: string; }) => void
  • Optional
  • Triggered when a retry finally succeeds
  • Params: domains domain list, url request URL, tagName resource type

onError

  • Type: ({ domains, url, tagName }: { domains?: string[]; url?: string; tagName?: string; }) => void
  • Optional
  • Triggered when all retries fail
  • Params: domains domain list, url request URL, tagName resource type

#Details

#Retry logic

The plugin retries automatically when a resource fails to load. The number of retries is controlled by retryTimes. For example:

  • retryTimes: 3 means up to 3 retries (after the first attempt)
  • A delay of retryDelay ms is applied before each retry

#Domain rotation

When domains is configured, the plugin rotates the host on each retry:

const retryPlugin = RetryPlugin({
  domains: [
    'https://cdn1.example.com',
    'https://cdn2.example.com',
    'https://cdn3.example.com'
  ],
});

Order of attempts:

  1. Initial attempt: original URL
  2. 1st retry: switch to cdn2.example.com
  3. 2nd retry: switch to cdn3.example.com
  4. 3rd retry: switch to cdn1.example.com

#Cache-busting

Use addQuery to add query parameters during retries to avoid cache interference:

const retryPlugin = RetryPlugin({
  addQuery: true, // adds ?retryCount=1, ?retryCount=2, etc.
});

You can also provide a function:

const retryPlugin = RetryPlugin({
  addQuery: ({ times, originalQuery }) => {
    return `${originalQuery}&retry=${times}&timestamp=${Date.now()}`;
  },
});

#Callbacks

You can monitor the retry lifecycle with callbacks:

const retryPlugin = RetryPlugin({
  onRetry: ({ times, domains, url, tagName }) => {
    console.log(`Retry #${times}, domains: ${domains}, url: ${url}`);
  },
  onSuccess: ({ domains, url, tagName }) => {
    console.log(`Retry success, domains: ${domains}, url: ${url}`);
  },
  onError: ({ domains, url, tagName }) => {
    console.log(`Retry failed, domains: ${domains}, url: ${url}`);
  },
});

Callback params:

  • times: current retry count (starts from 1)
  • domains: the current domain list
  • url: current request URL
  • tagName: resource type ('fetch' or 'script')

#Use cases

#1. CDN failover

const retryPlugin = RetryPlugin({
  retryTimes: 2,
  domains: [
    'https://cdn1.example.com',
    'https://cdn2.example.com',
    'https://cdn3.example.com'
  ],
  addQuery: true,
});

#2. Unstable networks

const retryPlugin = RetryPlugin({
  retryTimes: 5,
  retryDelay: 2000,
  onRetry: ({ times }) => {
    console.log(`Unstable network, retry #${times}`);
  },
});

#3. Monitoring and logging

const retryPlugin = RetryPlugin({
  onRetry: ({ times, url }) => {
    analytics.track('resource_retry', { times, url });
  },
  onError: ({ url }) => {
    logger.error('Resource load failed after all retries', { url });
  },
});

#Notes

  1. Performance: High retry counts increase loading time; tune for your environment
  2. Domains: Ensure all domains in domains serve the same resource
  3. Caching: If addQuery is enabled, consider CDN caching strategy
  4. Error handling: After all retries fail, the original error is thrown; handle it upstream

#Error codes

  • RUNTIME_008: Resource load failure that triggers the retry mechanism