| 27 | * @param makeRequest |
| 28 | */ |
| 29 | export function createTransport( |
| 30 | options: InternalBaseTransportOptions, |
| 31 | makeRequest: TransportRequestExecutor, |
| 32 | buffer: PromiseBuffer<TransportMakeRequestResponse> = makePromiseBuffer( |
| 33 | options.bufferSize || DEFAULT_TRANSPORT_BUFFER_SIZE, |
| 34 | ), |
| 35 | ): Transport { |
| 36 | let rateLimits: RateLimits = {}; |
| 37 | const flush = (timeout?: number): PromiseLike<boolean> => buffer.drain(timeout); |
| 38 | |
| 39 | function send(envelope: Envelope): PromiseLike<TransportMakeRequestResponse> { |
| 40 | const filteredEnvelopeItems: EnvelopeItem[] = []; |
| 41 | |
| 42 | // Drop rate limited items from envelope |
| 43 | forEachEnvelopeItem(envelope, (item, type) => { |
| 44 | const dataCategory = envelopeItemTypeToDataCategory(type); |
| 45 | if (isRateLimited(rateLimits, dataCategory)) { |
| 46 | options.recordDroppedEvent('ratelimit_backoff', dataCategory); |
| 47 | } else { |
| 48 | filteredEnvelopeItems.push(item); |
| 49 | } |
| 50 | }); |
| 51 | |
| 52 | // Skip sending if envelope is empty after filtering out rate limited events |
| 53 | if (filteredEnvelopeItems.length === 0) { |
| 54 | return Promise.resolve({}); |
| 55 | } |
| 56 | |
| 57 | const filteredEnvelope: Envelope = createEnvelope(envelope[0], filteredEnvelopeItems as (typeof envelope)[1]); |
| 58 | |
| 59 | // Creates client report for each item in an envelope |
| 60 | const recordEnvelopeLoss = (reason: EventDropReason): void => { |
| 61 | // Don't record outcomes for client reports - we don't want to create a feedback loop if client reports themselves fail to send |
| 62 | if (envelopeContainsItemType(filteredEnvelope, ['client_report'])) { |
| 63 | DEBUG_BUILD && debug.warn(`Dropping client report. Will not send outcomes (reason: ${reason}).`); |
| 64 | return; |
| 65 | } |
| 66 | forEachEnvelopeItem(filteredEnvelope, (item, type) => { |
| 67 | options.recordDroppedEvent(reason, envelopeItemTypeToDataCategory(type)); |
| 68 | }); |
| 69 | }; |
| 70 | |
| 71 | const requestTask = (): PromiseLike<TransportMakeRequestResponse> => |
| 72 | makeRequest({ body: serializeEnvelope(filteredEnvelope) }).then( |
| 73 | response => { |
| 74 | // Handle 413 Content Too Large |
| 75 | // Loss of envelope content is expected so we record a send_error client report |
| 76 | // https://develop.sentry.dev/sdk/expected-features/#dealing-with-network-failures |
| 77 | if (response.statusCode === 413) { |
| 78 | DEBUG_BUILD && |
| 79 | debug.error( |
| 80 | 'Sentry responded with status code 413. Envelope was discarded due to exceeding size limits.', |
| 81 | ); |
| 82 | recordEnvelopeLoss('send_error'); |
| 83 | return response; |
| 84 | } |
| 85 | |
| 86 | // We don't want to throw on NOK responses, but we want to at least log them |