Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(server): Expose rate limits for metrics #3347

Merged
merged 14 commits into from
Mar 28, 2024
Prev Previous commit
ref: Adress review feedback
  • Loading branch information
jan-auer committed Mar 28, 2024
commit 697e236df2a53edc11090025e541c296309268ba
90 changes: 45 additions & 45 deletions relay-quotas/src/rate_limit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ pub struct RateLimit {
///
/// Ignored on all data categories except for `MetricBucket`. If empty, this rate limit applies
/// to metrics of all namespaces.
pub namespace: SmallVec<[MetricNamespace; 1]>,
pub namespaces: SmallVec<[MetricNamespace; 1]>,
}

impl RateLimit {
Expand All @@ -172,15 +172,15 @@ impl RateLimit {
scope: RateLimitScope::for_quota(scoping, quota.scope),
reason_code: quota.reason_code.clone(),
retry_after,
namespace: quota.namespace.into_iter().collect(),
namespaces: quota.namespace.into_iter().collect(),
}
}

/// Checks whether the rate limit applies to the given item.
pub fn matches(&self, scoping: ItemScoping<'_>) -> bool {
self.matches_scope(scoping)
&& scoping.matches_categories(&self.categories)
&& scoping.matches_namespaces(&self.namespace)
&& scoping.matches_namespaces(&self.namespaces)
}

/// Returns `true` if the rate limiting scope matches the given item.
Expand Down Expand Up @@ -225,10 +225,10 @@ impl RateLimits {
scope,
reason_code: _,
retry_after: _,
namespace,
namespaces: namespace,
} = &limit;

*categories == l.categories && *scope == l.scope && *namespace == l.namespace
*categories == l.categories && *scope == l.scope && *namespace == l.namespaces
});

match limit_opt {
Expand Down Expand Up @@ -423,7 +423,7 @@ mod tests {
scope: RateLimitScope::Organization(42),
reason_code: None,
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![],
namespaces: smallvec![],
};

assert!(rate_limit.matches(ItemScoping {
Expand Down Expand Up @@ -456,7 +456,7 @@ mod tests {
scope: RateLimitScope::Organization(42),
reason_code: None,
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![],
namespaces: smallvec![],
};

assert!(rate_limit.matches(ItemScoping {
Expand Down Expand Up @@ -489,7 +489,7 @@ mod tests {
scope: RateLimitScope::Project(ProjectId::new(21)),
reason_code: None,
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![],
namespaces: smallvec![],
};

assert!(rate_limit.matches(ItemScoping {
Expand Down Expand Up @@ -522,7 +522,7 @@ mod tests {
scope: RateLimitScope::Organization(42),
reason_code: None,
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![MetricNamespace::Custom],
namespaces: smallvec![MetricNamespace::Custom],
};

let scoping = Scoping {
Expand All @@ -549,7 +549,7 @@ mod tests {
scope: RateLimitScope::Organization(42),
reason_code: None,
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![], // all namespaces
namespaces: smallvec![], // all namespaces
};

assert!(general_rate_limit.matches(ItemScoping {
Expand All @@ -574,7 +574,7 @@ mod tests {
),
reason_code: None,
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![],
namespaces: smallvec![],
};

assert!(rate_limit.matches(ItemScoping {
Expand Down Expand Up @@ -609,7 +609,7 @@ mod tests {
scope: RateLimitScope::Organization(42),
reason_code: Some(ReasonCode::new("first")),
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![],
namespaces: smallvec![],
});

// longer rate limit shadows shorter one
Expand All @@ -618,7 +618,7 @@ mod tests {
scope: RateLimitScope::Organization(42),
reason_code: Some(ReasonCode::new("second")),
retry_after: RetryAfter::from_secs(10),
namespace: smallvec![],
namespaces: smallvec![],
});

insta::assert_ron_snapshot!(rate_limits, @r###"
Expand All @@ -632,7 +632,7 @@ mod tests {
scope: Organization(42),
reason_code: Some(ReasonCode("second")),
retry_after: RetryAfter(10),
namespace: [],
namespaces: [],
),
],
)
Expand All @@ -648,7 +648,7 @@ mod tests {
scope: RateLimitScope::Organization(42),
reason_code: Some(ReasonCode::new("first")),
retry_after: RetryAfter::from_secs(10),
namespace: smallvec![],
namespaces: smallvec![],
});

// shorter rate limit is shadowed by existing one
Expand All @@ -657,7 +657,7 @@ mod tests {
scope: RateLimitScope::Organization(42),
reason_code: Some(ReasonCode::new("second")),
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![],
namespaces: smallvec![],
});

insta::assert_ron_snapshot!(rate_limits, @r###"
Expand All @@ -671,7 +671,7 @@ mod tests {
scope: Organization(42),
reason_code: Some(ReasonCode("first")),
retry_after: RetryAfter(10),
namespace: [],
namespaces: [],
),
],
)
Expand All @@ -687,7 +687,7 @@ mod tests {
scope: RateLimitScope::Organization(42),
reason_code: None,
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![],
namespaces: smallvec![],
});

// Same scope but different categories
Expand All @@ -696,7 +696,7 @@ mod tests {
scope: RateLimitScope::Organization(42),
reason_code: None,
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![],
namespaces: smallvec![],
});

// Same categories but different scope
Expand All @@ -705,7 +705,7 @@ mod tests {
scope: RateLimitScope::Project(ProjectId::new(21)),
reason_code: None,
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![],
namespaces: smallvec![],
});

insta::assert_ron_snapshot!(rate_limits, @r###"
Expand All @@ -718,7 +718,7 @@ mod tests {
scope: Organization(42),
reason_code: None,
retry_after: RetryAfter(1),
namespace: [],
namespaces: [],
),
RateLimit(
categories: [
Expand All @@ -727,7 +727,7 @@ mod tests {
scope: Organization(42),
reason_code: None,
retry_after: RetryAfter(1),
namespace: [],
namespaces: [],
),
RateLimit(
categories: [
Expand All @@ -736,7 +736,7 @@ mod tests {
scope: Project(ProjectId(21)),
reason_code: None,
retry_after: RetryAfter(1),
namespace: [],
namespaces: [],
),
],
)
Expand All @@ -753,16 +753,16 @@ mod tests {
scope: RateLimitScope::Organization(42),
reason_code: None,
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![MetricNamespace::Custom],
namespaces: smallvec![MetricNamespace::Custom],
});

// Same scope but different categories
// Same category but different namespaces
rate_limits.add(RateLimit {
categories: smallvec![DataCategory::MetricBucket],
scope: RateLimitScope::Organization(42),
reason_code: None,
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![MetricNamespace::Spans],
namespaces: smallvec![MetricNamespace::Spans],
});

insta::assert_ron_snapshot!(rate_limits, @r###"
Expand All @@ -775,7 +775,7 @@ mod tests {
scope: Organization(42),
reason_code: None,
retry_after: RetryAfter(1),
namespace: [
namespaces: [
"custom",
],
),
Expand All @@ -786,7 +786,7 @@ mod tests {
scope: Organization(42),
reason_code: None,
retry_after: RetryAfter(1),
namespace: [
namespaces: [
"spans",
],
),
Expand All @@ -804,7 +804,7 @@ mod tests {
scope: RateLimitScope::Organization(42),
reason_code: Some(ReasonCode::new("first")),
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![],
namespaces: smallvec![],
});

// Distinct scope to prevent deduplication
Expand All @@ -813,7 +813,7 @@ mod tests {
scope: RateLimitScope::Organization(42),
reason_code: Some(ReasonCode::new("second")),
retry_after: RetryAfter::from_secs(10),
namespace: smallvec![],
namespaces: smallvec![],
});

let rate_limit = rate_limits.longest().unwrap();
Expand All @@ -825,7 +825,7 @@ mod tests {
scope: Organization(42),
reason_code: Some(ReasonCode("second")),
retry_after: RetryAfter(10),
namespace: [],
namespaces: [],
)
"###);
}
Expand All @@ -840,7 +840,7 @@ mod tests {
scope: RateLimitScope::Organization(42),
reason_code: None,
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![],
namespaces: smallvec![],
});

// Inactive error limit with distinct scope
Expand All @@ -849,7 +849,7 @@ mod tests {
scope: RateLimitScope::Project(ProjectId::new(21)),
reason_code: None,
retry_after: RetryAfter::from_secs(0),
namespace: smallvec![],
namespaces: smallvec![],
});

// Sanity check before running `clean_expired`
Expand All @@ -868,7 +868,7 @@ mod tests {
scope: Organization(42),
reason_code: None,
retry_after: RetryAfter(1),
namespace: [],
namespaces: [],
),
],
)
Expand All @@ -885,7 +885,7 @@ mod tests {
scope: RateLimitScope::Organization(42),
reason_code: None,
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![],
namespaces: smallvec![],
});

// Active transaction limit
Expand All @@ -894,7 +894,7 @@ mod tests {
scope: RateLimitScope::Organization(42),
reason_code: None,
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![],
namespaces: smallvec![],
});

let applied_limits = rate_limits.check(ItemScoping {
Expand All @@ -919,7 +919,7 @@ mod tests {
scope: Organization(42),
reason_code: None,
retry_after: RetryAfter(1),
namespace: [],
namespaces: [],
),
],
)
Expand All @@ -936,7 +936,7 @@ mod tests {
scope: RateLimitScope::Organization(42),
reason_code: None,
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![],
namespaces: smallvec![],
});

// Active transaction limit
Expand All @@ -945,7 +945,7 @@ mod tests {
scope: RateLimitScope::Organization(42),
reason_code: None,
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![],
namespaces: smallvec![],
});

let item_scoping = ItemScoping {
Expand Down Expand Up @@ -982,7 +982,7 @@ mod tests {
scope: Organization(42),
reason_code: Some(ReasonCode("zero")),
retry_after: RetryAfter(60),
namespace: [],
namespaces: [],
),
],
)
Expand All @@ -999,23 +999,23 @@ mod tests {
scope: RateLimitScope::Organization(42),
reason_code: Some(ReasonCode::new("first")),
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![],
namespaces: smallvec![],
});

rate_limits1.add(RateLimit {
categories: smallvec![DataCategory::Transaction],
scope: RateLimitScope::Organization(42),
reason_code: None,
retry_after: RetryAfter::from_secs(1),
namespace: smallvec![],
namespaces: smallvec![],
});

rate_limits2.add(RateLimit {
categories: smallvec![DataCategory::Error],
scope: RateLimitScope::Organization(42),
reason_code: Some(ReasonCode::new("second")),
retry_after: RetryAfter::from_secs(10),
namespace: smallvec![],
namespaces: smallvec![],
});

rate_limits1.merge(rate_limits2);
Expand All @@ -1030,7 +1030,7 @@ mod tests {
scope: Organization(42),
reason_code: Some(ReasonCode("second")),
retry_after: RetryAfter(10),
namespace: [],
namespaces: [],
),
RateLimit(
categories: [
Expand All @@ -1039,7 +1039,7 @@ mod tests {
scope: Organization(42),
reason_code: None,
retry_after: RetryAfter(1),
namespace: [],
namespaces: [],
),
],
)
Expand Down
Loading
Loading