Skip to content

Commit cf93c9e

Browse files
committed
metrics rate limits
1 parent 9bfadb5 commit cf93c9e

File tree

4 files changed

+47
-5
lines changed

4 files changed

+47
-5
lines changed

packages/types/src/datacategory.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,8 +26,8 @@ export type DataCategory =
2626
| 'monitor'
2727
// Feedback type event (v2)
2828
| 'feedback'
29-
// Statsd type event for metrics
30-
| 'statsd'
29+
// Metrics sent via the statsd or metrics envelope items. `namespace` defines which namespace(s) will be affected
30+
| 'metric_bucket'
3131
// Span
3232
| 'span'
3333
// Unknown data category

packages/utils/src/envelope.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ const ITEM_TYPE_TO_DATA_CATEGORY_MAP: Record<EnvelopeItemType, DataCategory> = {
210210
check_in: 'monitor',
211211
feedback: 'feedback',
212212
span: 'span',
213-
statsd: 'statsd',
213+
statsd: 'metric_bucket',
214214
};
215215

216216
/**

packages/utils/src/ratelimit.ts

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,13 +67,14 @@ export function updateRateLimits(
6767
* rate limit headers are of the form
6868
* <header>,<header>,..
6969
* where each <header> is of the form
70-
* <retry_after>: <categories>: <scope>: <reason_code>
70+
* <retry_after>: <categories>: <scope>: <reason_code>: <namespaces>
7171
* where
7272
* <retry_after> is a delay in seconds
7373
* <categories> is the event type(s) (error, transaction, etc) being rate limited and is of the form
7474
* <category>;<category>;...
7575
* <scope> is what's being limited (org, project, or key) - ignored by SDK
7676
* <reason_code> is an arbitrary string like "org_quota" - ignored by SDK
77+
* <namespaces> Semicolon-separated list of metric namespace identifiers. Only present if rate limit applies to the metric_bucket data category
7778
*/
7879
for (const limit of rateLimitHeader.trim().split(',')) {
7980
const [retryAfter, categories] = limit.split(':', 2);
@@ -83,7 +84,16 @@ export function updateRateLimits(
8384
updatedRateLimits.all = now + delay;
8485
} else {
8586
for (const category of categories.split(';')) {
86-
updatedRateLimits[category] = now + delay;
87+
if (category === 'metric_bucket') {
88+
const namespaces = limit.split(':', 5)[4] ? limit.split(':', 5)[4].split(';') : [];
89+
90+
if (!namespaces || namespaces.includes('custom')) {
91+
// back off transmitting metrics from the SDK
92+
updatedRateLimits[category] = now + delay;
93+
}
94+
} else {
95+
updatedRateLimits[category] = now + delay;
96+
}
8797
}
8898
}
8999
}

packages/utils/test/ratelimit.test.ts

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -197,3 +197,35 @@ describe('updateRateLimits()', () => {
197197
expect(updatedRateLimits.all).toEqual(60_000);
198198
});
199199
});
200+
201+
describe('data category "metric_bucket"', () => {
202+
test('should add limit for `metric_bucket` category when namespaces contain "custom"', () => {
203+
const rateLimits: RateLimits = {};
204+
const headers = {
205+
'retry-after': null,
206+
'x-sentry-rate-limits': '42:metric_bucket:::custom',
207+
};
208+
const updatedRateLimits = updateRateLimits(rateLimits, { headers }, 0);
209+
expect(updatedRateLimits.metric_bucket).toEqual(42 * 1000);
210+
});
211+
212+
test('should not add limit for `metric_bucket` category when namespaces do not contain "custom"', () => {
213+
const rateLimits: RateLimits = {};
214+
const headers = {
215+
'retry-after': null,
216+
'x-sentry-rate-limits': '42:metric_bucket:::namespace1;namespace2',
217+
};
218+
const updatedRateLimits = updateRateLimits(rateLimits, { headers }, 0);
219+
expect(updatedRateLimits.metric_bucket).toBeUndefined();
220+
});
221+
222+
test('should add limit for `metric_bucket` category when namespaces are empty', () => {
223+
const rateLimits: RateLimits = {};
224+
const headers = {
225+
'retry-after': null,
226+
'x-sentry-rate-limits': '42:metric_bucket',
227+
};
228+
const updatedRateLimits = updateRateLimits(rateLimits, { headers }, 0);
229+
expect(updatedRateLimits.metric_bucket).toEqual(42 * 1000);
230+
});
231+
});

0 commit comments

Comments
 (0)