@@ -13,6 +13,7 @@ import { _getTraceInfoFromScope } from '../utils/trace-info';
1313import { createMetricEnvelope } from './envelope' ;
1414
1515const MAX_METRIC_BUFFER_SIZE = 1000 ;
16+ const DEFAULT_MAX_METRIC_DROP_LIMIT = 2000 ;
1617
1718/**
1819 * Converts a metric attribute to a serialized metric attribute.
@@ -89,10 +90,19 @@ function setMetricAttribute(
8990export function _INTERNAL_captureSerializedMetric ( client : Client , serializedMetric : SerializedMetric ) : void {
9091 const bufferMap = _getBufferMap ( ) ;
9192 const metricBuffer = _INTERNAL_getMetricBuffer ( client ) ;
93+ const maxDropLimit = client . getOptions ( ) . maxMetricDropLimit ?? DEFAULT_MAX_METRIC_DROP_LIMIT ;
94+ const inFlightCount = _getInFlightCount ( client ) ;
9295
9396 if ( metricBuffer === undefined ) {
9497 bufferMap . set ( client , [ serializedMetric ] ) ;
9598 } else {
99+ const totalMetrics = metricBuffer . length + inFlightCount ;
100+
101+ if ( totalMetrics >= maxDropLimit && maxDropLimit > 0 ) {
102+ client . recordDroppedEvent ( 'buffer_overflow' , 'metric' ) ;
103+ return ;
104+ }
105+
96106 if ( metricBuffer . length >= MAX_METRIC_BUFFER_SIZE ) {
97107 _INTERNAL_flushMetricsBuffer ( client , metricBuffer ) ;
98108 bufferMap . set ( client , [ serializedMetric ] ) ;
@@ -266,14 +276,18 @@ export function _INTERNAL_flushMetricsBuffer(client: Client, maybeMetricBuffer?:
266276 const clientOptions = client . getOptions ( ) ;
267277 const envelope = createMetricEnvelope ( metricBuffer , clientOptions . _metadata , clientOptions . tunnel , client . getDsn ( ) ) ;
268278
279+ // Track the number of metrics being flushed as in-flight
280+ const metricsCount = metricBuffer . length ;
281+ _setInFlightCount ( client , count => count + metricsCount ) ;
282+
269283 // Clear the metric buffer after envelopes have been constructed.
270284 _getBufferMap ( ) . set ( client , [ ] ) ;
271285
272286 client . emit ( 'flushMetrics' ) ;
273287
274288 // sendEnvelope should not throw
275289 // eslint-disable-next-line @typescript-eslint/no-floating-promises
276- client . sendEnvelope ( envelope ) ;
290+ client . sendEnvelope ( envelope ) . then ( ( ) => _setInFlightCount ( client , count => count - metricsCount ) ) ;
277291}
278292
279293/**
@@ -306,3 +320,31 @@ function _getBufferMap(): WeakMap<Client, Array<SerializedMetric>> {
306320 // The reference to the Client <> MetricBuffer map is stored on the carrier to ensure it's always the same
307321 return getGlobalSingleton ( 'clientToMetricBufferMap' , ( ) => new WeakMap < Client , Array < SerializedMetric > > ( ) ) ;
308322}
323+
324+ function _getInFlightMap ( ) : WeakMap < Client , number > {
325+ // Track the number of metrics currently in-flight (flushed but not yet sent/completed)
326+ return getGlobalSingleton ( 'clientToInFlightMetricsMap' , ( ) => new WeakMap < Client , number > ( ) ) ;
327+ }
328+
329+ /**
330+ * Gets the number of metrics currently in-flight (flushed but not yet sent/completed) for a given client.
331+ *
332+ * @param client - The client to get the in-flight count for.
333+ * @returns The number of metrics in-flight.
334+ */
335+ function _getInFlightCount ( client : Client ) : number {
336+ return _getInFlightMap ( ) . get ( client ) ?? 0 ;
337+ }
338+
339+ /**
340+ * Sets the in-flight metrics count for a given client.
341+ *
342+ * @param client - The client to set the count for.
343+ * @param countOrUpdater - The value to set the count to, or a function to update the count. If a function is provided, it will be called with the current count as an argument.
344+ */
345+ function _setInFlightCount ( client : Client , countOrUpdater : number | ( ( current : number ) => number ) ) : void {
346+ const inFlightMap = _getInFlightMap ( ) ;
347+ const currentCount = _getInFlightCount ( client ) ;
348+ const nextCount = typeof countOrUpdater === 'function' ? countOrUpdater ( currentCount ) : countOrUpdater ;
349+ inFlightMap . set ( client , Math . max ( 0 , nextCount ) ) ;
350+ }
0 commit comments