1- import type { TransportMakeRequestResponse } from '@sentry/types' ;
1+ import type { DataCategory , TransportMakeRequestResponse } from '@sentry/types' ;
22
33// Intentionally keeping the key broad, as we don't know for sure what rate limit headers get returned from backend
44export type RateLimits = Record < string , number > ;
@@ -32,15 +32,15 @@ export function parseRetryAfterHeader(header: string, now: number = Date.now()):
3232 *
3333 * @return the time in ms that the category is disabled until or 0 if there's no active rate limit.
3434 */
35- export function disabledUntil ( limits : RateLimits , category : string ) : number {
36- return limits [ category ] || limits . all || 0 ;
35+ export function disabledUntil ( limits : RateLimits , dataCategory : DataCategory ) : number {
36+ return limits [ dataCategory ] || limits . all || 0 ;
3737}
3838
3939/**
4040 * Checks if a category is rate limited
4141 */
42- export function isRateLimited ( limits : RateLimits , category : string , now : number = Date . now ( ) ) : boolean {
43- return disabledUntil ( limits , category ) > now ;
42+ export function isRateLimited ( limits : RateLimits , dataCategory : DataCategory , now : number = Date . now ( ) ) : boolean {
43+ return disabledUntil ( limits , dataCategory ) > now ;
4444}
4545
4646/**
@@ -67,23 +67,32 @@ 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. Defines which namespace(s) will be affected.
78+ * Only present if rate limit applies to the metric_bucket data category.
7779 */
7880 for ( const limit of rateLimitHeader . trim ( ) . split ( ',' ) ) {
79- const [ retryAfter , categories ] = limit . split ( ':' , 2 ) ;
81+ const [ retryAfter , categories , , , namespaces ] = limit . split ( ':' , 5 ) ;
8082 const headerDelay = parseInt ( retryAfter , 10 ) ;
8183 const delay = ( ! isNaN ( headerDelay ) ? headerDelay : 60 ) * 1000 ; // 60sec default
8284 if ( ! categories ) {
8385 updatedRateLimits . all = now + delay ;
8486 } else {
8587 for ( const category of categories . split ( ';' ) ) {
86- updatedRateLimits [ category ] = now + delay ;
88+ if ( category === 'metric_bucket' ) {
89+ // namespaces will be present when category === 'metric_bucket'
90+ if ( ! namespaces || namespaces . split ( ';' ) . includes ( 'custom' ) ) {
91+ updatedRateLimits [ category ] = now + delay ;
92+ }
93+ } else {
94+ updatedRateLimits [ category ] = now + delay ;
95+ }
8796 }
8897 }
8998 }
0 commit comments