Skip to content

Implement retry in case of error #667

Closed

Description

@ValentinH

🚀 Feature Proposal

Implement a new "retry" option in @loadable/component.

Motivation

We monitor our errors with Sentry and we see quite a lot of errors coming with lazy-loaded components. Indeed, on flaky network, it's easy to have a request aborted and the component is never loaded. In our applications, we have started to wrap all dynamic imports passed to loadable with a retry function such as:

const Example = loadable(() =>
  retry(
    () => import('./Example'),
    { retries: 3 }
  )
)

where retry is a simple function:

type Options = {
  retries?: number
  interval?: number
  exponentialBackoff?: boolean
}

// taken from https://dev.to/goenning/how-to-retry-when-react-lazy-fails-mb5
export function retry<R>(
  fn: () => Promise<R>,
  { retries = 3, interval = 500, exponentialBackoff = true }: Options = {}
) {
  return new Promise<R>((resolve, reject) => {
    fn()
      .then(resolve)
      .catch((error) => {
        setTimeout(() => {
          if (retries === 1) {
            reject(error)
            return
          }

          // Passing on "reject" is the important part
          retry(fn, {
            retries: retries - 1,
            interval: exponentialBackoff ? interval * 2 : interval,
          }).then(resolve, reject)
        }, interval)
      })
  })
}

Example

const Example = loadable(() => import('./Example'),  {retries: 3})

Pitch

I'm wondering if this is something that could be directly implemented as part of loadable.

Activity

  1. changed the title [-]Implement retry in case of chunk error[/-] [+]Implement retry in case of error[/+] on Dec 7, 2020
  2. theKashey commented on Dec 7, 2020

    @theKashey
    Collaborator

    Good point. As a matter of fact - our own Sentry is filled with the same reports.

  3. ValentinH commented on Dec 7, 2020

    @ValentinH
    Author

    If you agree, I'd be happy to work a PR.

  4. theKashey commented on Dec 7, 2020

    @theKashey
    Collaborator

    That could be a little complicated as right now errors are just thrown, expected to be handled on the nearest ErrorBoundary.
    The question - should network problems be still reported (so the error has to be thrown), or in case they are retry-able loadable can swallow them?

  5. ValentinH commented on Dec 8, 2020

    @ValentinH
    Author

    I don't know if you are able to differentiate network errors from other kinds of errors when using dynamic imports. Do you know?

    Regarding errors just being thrown at the moment, if the retry is optional, we could still retry all errors as it would not be a breaking change. What do you think?

  6. theKashey commented on Dec 9, 2020

    @theKashey
    Collaborator

    I don't know if you are able to differentiate network errors

    You can, but that is abstraction leaking, so you should not try to differentiate.

    Regarding errors just being thrown at the moment...

    This moment can alter the implementation a lot. Providing ErrorBoundary with built-in retry mechanism and built-in reporting can be a better solution, and actually can be done right now. Well, almost - such error boundary cannot distinguish LoadableError from any error coming from within loaded content. So we are circling back to the problem of "how to differentiate"

  7. ValentinH commented on Dec 9, 2020

    @ValentinH
    Author

    I might be missing something but I think the retry function I shared in my issue is only retrying errors related to the dynamic import, not errors within the loaded component.

    By the way, I deployed it on our main app in production and almost all the ChunkLoadError are gone.

  8. theKashey commented on Dec 9, 2020

    @theKashey
    Collaborator

    If only error boundary could detect chunk loading error (thrown by loadable) - then it can do retry.

    Wrapping import with any extra code is breaking SSR. There is an update to a babel plugin to make that impossible as well.

  9. ValentinH commented on Dec 9, 2020

    @ValentinH
    Author

    Wrapping import with any extra code is breaking SSR. There is an update to a babel plugin to make that impossible as well.

    What do you mean by "breaking SSR"? We use this technique on an SSR application and I didn't notice any issues. 🤔

  10. sosnomIntent commented on Dec 10, 2020

    @sosnomIntent

    Hello!
    Facing the same issue from some time. I would like to try @ValentinH solution, will let you know when it will be tested it on production in my project

  11. stale commented on Feb 9, 2021

    @stale

    This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

  12. ValentinH commented on Feb 9, 2021

    @ValentinH
    Author

    I think this issue is still relevant. My last question was not answered actually.

  13. 19 remaining items

  14. ValentinH commented on Sep 28, 2021

    @ValentinH
    Author

    @YPCrumble you need to use a generic signature. I have updated my original message with what you are looking for 😉

  15. YPCrumble commented on Sep 28, 2021

    @YPCrumble

    @ValentinH worked perfectly, thank you @ValentinH !!!

  16. divyanshu013 commented on Nov 17, 2021

    @divyanshu013

    This issue is still problematic, if it's not prioritized / fixable at the moment can we link this in the docs? Discoverability of this solution can help future users from wasting few hours hopefully.

  17. stale commented on Apr 16, 2022

    @stale

    This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

  18. stale commented on Jun 19, 2022

    @stale

    This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

  19. YPCrumble commented on Jun 19, 2022

    @YPCrumble

    Not stale

  20. mattleonowicz commented on Jul 19, 2022

    @mattleonowicz

    Funny how I also did the exact same thing with retry and it works.
    I'm not sure if it should really be incorporated in this library though, its easier to maintain one simple library than a do-all giant.
    An entry in the docs would suffice, if you ask me.
    Another entry I'd expect (which is what I was looking for, and stumbled upon this issue instead) is to generally describe some good practices on what to do in case of fail, so how to "wrap" things with try catch and what are our options to safely recover from this (because even retrying network requests will return with error eventually, unless you want to repeat it indefinitely)

  21. stale commented on Oct 1, 2022

    @stale

    This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.

  22. roidayan1 commented on Jul 9, 2026

    @roidayan1

    Opened #1037 which addresses this from a different angle. Rather than a built-in retry policy ({ retries }), it adds a general onError(error, props) hook (plus a symmetric onLoad), available per-instance and globally via loadable.setConfig. That gives you a first-class place to implement retry / reload / error reporting in userland, without baking a specific policy into the library. Docs include a reload-once-after-deploy example.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions