(
replayData: SendReplayData,
retryConfig = {
count: 0,
interval: RETRY_BASE_INTERVAL,
},
)
| 8 | * Finalize and send the current replay event to Sentry |
| 9 | */ |
| 10 | export async function sendReplay( |
| 11 | replayData: SendReplayData, |
| 12 | retryConfig = { |
| 13 | count: 0, |
| 14 | interval: RETRY_BASE_INTERVAL, |
| 15 | }, |
| 16 | ): Promise<unknown> { |
| 17 | const { recordingData, onError } = replayData; |
| 18 | |
| 19 | // short circuit if there's no events to upload (this shouldn't happen as _runFlush makes this check) |
| 20 | if (!recordingData.length) { |
| 21 | return; |
| 22 | } |
| 23 | |
| 24 | try { |
| 25 | await sendReplayRequest(replayData); |
| 26 | return true; |
| 27 | } catch (err) { |
| 28 | if (err instanceof TransportStatusCodeError || err instanceof RateLimitError) { |
| 29 | throw err; |
| 30 | } |
| 31 | |
| 32 | // Capture error for every failed replay |
| 33 | setContext('Replays', { |
| 34 | _retryCount: retryConfig.count, |
| 35 | }); |
| 36 | |
| 37 | if (onError) { |
| 38 | onError(err); |
| 39 | } |
| 40 | |
| 41 | // If an error happened here, it's likely that uploading the attachment |
| 42 | // failed, we'll can retry with the same events payload |
| 43 | if (retryConfig.count >= RETRY_MAX_COUNT) { |
| 44 | const error = new Error(`${UNABLE_TO_SEND_REPLAY} - max retries exceeded`); |
| 45 | |
| 46 | try { |
| 47 | // In case browsers don't allow this property to be writable |
| 48 | // @ts-expect-error This needs lib es2022 and newer |
| 49 | error.cause = err; |
| 50 | } catch { |
| 51 | // nothing to do |
| 52 | } |
| 53 | |
| 54 | throw error; |
| 55 | } |
| 56 | |
| 57 | // will retry in intervals of 5, 10, 30 |
| 58 | retryConfig.interval *= ++retryConfig.count; |
| 59 | |
| 60 | return new Promise((resolve, reject) => { |
| 61 | setTimeout(async () => { |
| 62 | try { |
| 63 | await sendReplay(replayData, retryConfig); |
| 64 | resolve(true); |
| 65 | } catch (err) { |
| 66 | reject(err); |
| 67 | } |
no test coverage detected