fetch-retry.ts 1.2 KB

123456789101112131415161718192021222324252627282930313233
  1. /**
  2. * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info.
  3. *
  4. * @author David Sehnal <david.sehnal@gmail.com>
  5. */
  6. import fetch, { Response } from 'node-fetch';
  7. import { retryIf } from '../../../mol-util/retry-if';
  8. const RETRIABLE_NETWORK_ERRORS = [
  9. 'ECONNRESET', 'ENOTFOUND', 'ESOCKETTIMEDOUT', 'ETIMEDOUT',
  10. 'ECONNREFUSED', 'EHOSTUNREACH', 'EPIPE', 'EAI_AGAIN'
  11. ];
  12. function isRetriableNetworkError(error: any) {
  13. return error && RETRIABLE_NETWORK_ERRORS.includes(error.code);
  14. }
  15. export async function fetchRetry(url: string, timeout: number, retryCount: number, onRetry?: () => void): Promise<Response> {
  16. const controller = new AbortController();
  17. const id = setTimeout(() => controller.abort(), timeout);
  18. const signal = controller.signal as any; // TODO: fix type
  19. const result = await retryIf(() => fetch(url, { signal }), {
  20. retryThenIf: r => r.status === 408 /** timeout */ || r.status === 429 /** too many requests */ || (r.status >= 500 && r.status < 600),
  21. // TODO test retryCatchIf
  22. retryCatchIf: e => isRetriableNetworkError(e),
  23. onRetry,
  24. retryCount
  25. });
  26. clearTimeout(id);
  27. return result;
  28. }