import { ITelemetryLogger } from "@fluidframework/common-definitions" ; import { assert , delay , performance } from "@fluidframework/common-utils" ; import { canRetryOnError } from "@fluidframework/driver-utils" ; import { OdspErrorType } from "@fluidframework/odsp-driver-definitions" ; import { Odsp409Error } from "./epochTracker" ; /**
 * This method retries only for retriable coherency and service read only errors.
 */ export async function runWithRetry < T > ( api , callName , logger , checkDisposed ? ) { let retryAfter = 1000 ; const start = performance . now ( ) ; let lastError ; for ( let attempts = 1 ; ; attempts ++ ) { if ( checkDisposed !== undefined ) { checkDisposed ( ) ; } try { const result = await api ( ) ; if ( attempts > 1 ) { logger . sendTelemetryEvent ( { eventName : "MultipleRetries" , callName , attempts , duration : performance . now ( ) - start } , lastError ) ; } return result ; } catch ( error ) { const canRetry = canRetryOnError ( error ) ; const coherencyError = error ?. [ Odsp409Error ] === true ; const serviceReadonlyError = error ?. errorType === OdspErrorType . serviceReadOnly ; if ( ! ( coherencyError || serviceReadonlyError ) ) { throw error ; } if ( attempts === 5 ) { logger . sendErrorEvent ( { eventName : coherencyError ? "CoherencyErrorTooManyRetries" : "ServiceReadonlyErrorTooManyRetries" , callName , attempts , duration : performance . now ( ) - start } , error ) ; error . canRetry = false ; throw error ; } assert ( canRetry , 0x24d ) ; await delay ( Math . floor ( retryAfter ) ) ; retryAfter += retryAfter / 4 * ( 1 + Math . random ( ) ) ; lastError = error ; } } }