You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1 line
5.8 KiB
1 line
5.8 KiB
{"version":3,"file":"urql-exchange-retry.mjs","sources":["../src/retryExchange.ts"],"sourcesContent":["import {\n makeSubject,\n share,\n pipe,\n merge,\n filter,\n fromValue,\n delay,\n mergeMap,\n takeUntil,\n} from 'wonka';\nimport {\n makeOperation,\n Exchange,\n Operation,\n CombinedError,\n OperationResult,\n} from '@urql/core';\nimport { sourceT } from 'wonka/dist/types/src/Wonka_types.gen';\n\nexport interface RetryExchangeOptions {\n initialDelayMs?: number;\n maxDelayMs?: number;\n randomDelay?: boolean;\n maxNumberAttempts?: number;\n /** Conditionally determine whether an error should be retried */\n retryIf?: (error: CombinedError, operation: Operation) => boolean;\n /** Conditionally update operations as they're retried (retryIf can be replaced with this) */\n retryWith?: (\n error: CombinedError,\n operation: Operation\n ) => Operation | null | undefined;\n}\n\nexport const retryExchange = ({\n initialDelayMs,\n maxDelayMs,\n randomDelay,\n maxNumberAttempts,\n retryIf,\n retryWith,\n}: RetryExchangeOptions): Exchange => {\n const MIN_DELAY = initialDelayMs || 1000;\n const MAX_DELAY = maxDelayMs || 15000;\n const MAX_ATTEMPTS = maxNumberAttempts || 2;\n const RANDOM_DELAY = randomDelay || true;\n\n return ({ forward, dispatchDebug }) => ops$ => {\n const sharedOps$ = pipe(ops$, share);\n const {\n source: retry$,\n next: nextRetryOperation,\n } = makeSubject<Operation>();\n\n const retryWithBackoff$ = pipe(\n retry$,\n mergeMap((op: Operation) => {\n const { key, context } = op;\n const retryCount = (context.retryCount || 0) + 1;\n let delayAmount = context.retryDelay || MIN_DELAY;\n\n const backoffFactor = Math.random() + 1.5;\n // if randomDelay is enabled and it won't exceed the max delay, apply a random\n // amount to the delay to avoid thundering herd problem\n if (RANDOM_DELAY && delayAmount * backoffFactor < MAX_DELAY) {\n delayAmount *= backoffFactor;\n }\n\n // We stop the retries if a teardown event for this operation comes in\n // But if this event comes through regularly we also stop the retries, since it's\n // basically the query retrying itself, no backoff should be added!\n const teardown$ = pipe(\n sharedOps$,\n filter(op => {\n return (\n (op.kind === 'query' || op.kind === 'teardown') && op.key === key\n );\n })\n );\n\n dispatchDebug({\n type: 'retryAttempt',\n message: `The operation has failed and a retry has been triggered (${retryCount} / ${MAX_ATTEMPTS})`,\n operation: op,\n data: {\n retryCount,\n },\n });\n\n // Add new retryDelay and retryCount to operation\n return pipe(\n fromValue(\n makeOperation(op.kind, op, {\n ...op.context,\n retryDelay: delayAmount,\n retryCount,\n })\n ),\n delay(delayAmount),\n // Stop retry if a teardown comes in\n takeUntil(teardown$)\n );\n })\n );\n\n const result$ = pipe(\n merge([sharedOps$, retryWithBackoff$]),\n forward,\n share,\n filter(res => {\n // Only retry if the error passes the conditional retryIf function (if passed)\n // or if the error contains a networkError\n if (\n !res.error ||\n (retryIf\n ? !retryIf(res.error, res.operation)\n : !retryWith && !res.error.networkError)\n ) {\n return true;\n }\n\n const maxNumberAttemptsExceeded =\n (res.operation.context.retryCount || 0) >= MAX_ATTEMPTS - 1;\n\n if (!maxNumberAttemptsExceeded) {\n const operation = retryWith\n ? retryWith(res.error, res.operation)\n : res.operation;\n if (!operation) return true;\n\n // Send failed responses to be retried by calling next on the retry$ subject\n // Exclude operations that have been retried more than the specified max\n nextRetryOperation(operation);\n return false;\n }\n\n dispatchDebug({\n type: 'retryExhausted',\n message:\n 'Maximum number of retries has been reached. No further retries will be performed.',\n operation: res.operation,\n });\n\n return true;\n })\n ) as sourceT<OperationResult>;\n\n return result$;\n };\n};\n"],"names":["retryExchange","MIN_DELAY","MAX_DELAY","MAX_ATTEMPTS","RANDOM_DELAY","ops$","sharedOps$","share","makeSubject","retryWithBackoff$","mergeMap","op","retryCount","context","delayAmount","retryDelay","backoffFactor","Math","random","teardown$","filter","kind","key","dispatchDebug","type","message","operation","data","takeUntil","delay","fromValue","makeOperation","_extends","retry$","res","error","retryIf","retryWith","networkError","nextRetryOperation","forward","merge"],"mappings":";;;;;;;;;;;;;;;;;;SAkCaA;;;MAQLC,wBAA8B;MAC9BC,oBAA0B;MAC1BC,2BAAoC;MACpCC,sBAA8B;;;;oBAEGC;UAC/BC,IAAwBC,EAANF;cAIpBG;;;UAEEC,IAEJC,YAAUC;;;YAEFC,KAAcC,EAAQD,cAAc,KAAK;YAC3CE,IAAcD,EAAQE,cAAcd;YAElCe,IAAgBC,KAAKC,WAAW;YAGlCd,KAAgBU,IAAcE,IAAgBd;UAChDY,KAAeE;;YAMXG,IAEJC,YAAOT;kBAEU,YAAZA,EAAGU,QAAgC,eAAZV,EAAGU,SAAwBV,EAAGW,QAAQA;WAFlEF,CADAd;iDAQFiB,EAAc;UACZC,MAAM;UACNC,uEAAqEb,YAAgBT;UACrFuB,WAAWf;UACXgB,MAAM;wBACJf;;;;eAeFgB,EAAUT,GAFVU,EAAMf,EAANe,CAPAC,EACEC,EAAcpB,EAAGU,MAAMV,GAAIqB,aACtBrB,EAAGE;UACNE,YAAYD;sBACZF;;SAvCRF,CADAuB;aAsDAb,YAAOc;cAIFA,EAAIC,UACJC,IACIA,EAAQF,EAAIC,OAAOD,EAAIR,aACvBW,KAAcH,EAAIC,MAAMG;kBAEtB;;eAINJ,EAAIR,UAAUb,QAAQD,cAAc,MAAMT,IAAe,IAE5B;cACxBuB,IAAYW,IACdA,EAAUH,EAAIC,OAAOD,EAAIR,aACzBQ,EAAIR;eACHA;oBAAkB;;UAIvBa,EAAmBb;kBACZ;;iDAGTH,EAAc;UACZC,MAAM;UACNC,SACE;UACFC,WAAWQ,EAAIR;;;gBAGV;SAlCTN,CADAb,EADAiC,EADAC,EAAM,EAACnC,GAAYG;;;;;"} |