The Transport is responsible for sending events to Sentry. It handles buffering, rate limiting, and error handling.
Overview
Transports:
- Send envelopes containing events to Sentry
- Buffer requests to prevent overwhelming the system
- Handle rate limiting from the Sentry backend
- Support graceful shutdown with flushing
Interface Definition
export interface Transport {
send(request: Envelope): PromiseLike<TransportMakeRequestResponse>;
flush(timeout?: number): PromiseLike<boolean>;
}
Methods
send
Send an envelope to Sentry.
send(request: Envelope): PromiseLike<TransportMakeRequestResponse>
The envelope containing events to send.
Returns: Promise resolving to a response object.
HTTP status code of the response.
Response headers including rate limit information.Rate limit information from Sentry.
Time to wait before retrying.
flush
Wait for all pending requests to complete.
flush(timeout?: number): PromiseLike<boolean>
Maximum time in milliseconds to wait. If not provided, waits indefinitely.
Returns: Promise resolving to true if all requests completed, false if timeout was reached.
Creating a Transport
Use the createTransport helper to create a transport:
import { createTransport } from '@sentry/core';
const transport = createTransport(
options: InternalBaseTransportOptions,
makeRequest: TransportRequestExecutor,
buffer?: PromiseBuffer<TransportMakeRequestResponse>
): Transport
options
InternalBaseTransportOptions
required
Transport configuration options.The Sentry ingestion endpoint URL.
Custom HTTP headers to include in requests.
Maximum number of requests to buffer. Defaults to 64.
Tunnel URL for proxying requests.
Callback to record dropped events for client reports.
makeRequest
TransportRequestExecutor
required
Function that executes the actual HTTP request.type TransportRequestExecutor = (
request: TransportRequest
) => PromiseLike<TransportMakeRequestResponse>
Optional custom promise buffer for request queuing.
Transport Request
export type TransportRequest = {
body: string | Uint8Array;
};
body
string | Uint8Array
required
The serialized envelope to send.
Example: HTTP Transport
import { createTransport, BaseTransportOptions } from '@sentry/core';
function makeHttpRequest(
request: TransportRequest
): Promise<TransportMakeRequestResponse> {
return fetch(options.url, {
method: 'POST',
body: request.body,
headers: {
'Content-Type': 'application/x-sentry-envelope',
...options.headers
}
}).then(response => ({
statusCode: response.status,
headers: {
'x-sentry-rate-limits': response.headers.get('x-sentry-rate-limits'),
'retry-after': response.headers.get('retry-after')
}
}));
}
export function makeHttpTransport(
options: BaseTransportOptions
): Transport {
return createTransport(options, makeHttpRequest);
}
Example: Custom Transport
import { Transport, Envelope } from '@sentry/core';
class CustomTransport implements Transport {
constructor(private options: CustomTransportOptions) {}
send(envelope: Envelope): Promise<TransportMakeRequestResponse> {
// Custom implementation
return this.customSendLogic(envelope);
}
flush(timeout?: number): Promise<boolean> {
// Wait for pending requests
return this.waitForPendingRequests(timeout);
}
private customSendLogic(envelope: Envelope): Promise<TransportMakeRequestResponse> {
// Implement your custom send logic
return Promise.resolve({ statusCode: 200 });
}
private waitForPendingRequests(timeout?: number): Promise<boolean> {
// Implement flush logic
return Promise.resolve(true);
}
}
Rate Limiting
The transport automatically handles rate limiting:
// From packages/core/src/transports/base.ts
// Rate limited items are dropped before sending
forEachEnvelopeItem(envelope, (item, type) => {
const dataCategory = envelopeItemTypeToDataCategory(type);
if (isRateLimited(rateLimits, dataCategory)) {
options.recordDroppedEvent('ratelimit_backoff', dataCategory);
} else {
filteredEnvelopeItems.push(item);
}
});
Buffer Management
Transports use a promise buffer to limit concurrent requests:
import { makePromiseBuffer } from '@sentry/core';
const DEFAULT_TRANSPORT_BUFFER_SIZE = 64;
const buffer = makePromiseBuffer(
options.bufferSize || DEFAULT_TRANSPORT_BUFFER_SIZE
);
// Add request to buffer
buffer.add(requestTask).then(
result => result,
error => {
if (error === SENTRY_BUFFER_FULL_ERROR) {
recordEnvelopeLoss('queue_overflow');
return Promise.resolve({});
}
throw error;
}
);
Error Handling
Transports handle various error scenarios:
413 Content Too Large:
if (response.statusCode === 413) {
DEBUG_BUILD && debug.error(
'Envelope was discarded due to exceeding size limits.'
);
recordEnvelopeLoss('send_error');
return response;
}
Network Errors:
try {
return await makeRequest({ body: serializedEnvelope });
} catch (error) {
recordEnvelopeLoss('network_error');
throw error;
}