-
Notifications
You must be signed in to change notification settings - Fork 124
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
Make requests emit metrics when rate limited #423
Make requests emit metrics when rate limited #423
Conversation
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
/** Request filter that returns a 429 Too Many Requests if the rate limiter says so */ | ||
@Priority(Priorities.AUTHORIZATION + 1) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fun fact: this actually did nothing previously. It's a lucky coincidence that this ran after the ContextResolverFilter due to addFilter ordering.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removing this moves it back to USER right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. Previously I don't think it did anything because it was outside Jersey. Also we don't seem to have any Jersey filters so the priority doesn't really matter currently.
environment | ||
.servlets() | ||
.addFilter("ratelimiter", new RateLimiterFilter(configuration.getRateLimiter())) | ||
.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*"); | ||
environment.jersey().register(new RateLimiterFilter(configuration.getRateLimiter())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This seems like a semantic change unrelated to the metrics. If I'm reading this correctly, this changes the rate limiter to only apply to Jersey resources. Do we want that?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes because TimedApplicationEventListener, which is what emits metrics on requests, depends on Jersey events.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I get that, but my concern is whether this actually changes the behavior of the system by rate-limiting less things now
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(Please fact check me as I only started working with Java web services recently)
I think all of our endpoints are in Jersey, so it shouldn't change the scope, but at a minimum it does push rate limiting further into the request handling chain.
The fundamental problem seems to be that only Jersey knows how to map a request path to its handling method (and thus its metric name). If that mapping was available everywhere, most of TimedApplicationEventListener could be re-written as a top level filter.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Semantically, there is a difference, as ServletFilters are applied before Jersey Filters. Practically, however, it shouldn't have an impact. I think the only real dependency the RateLimiter might have is that the RealmContext is set in case there are different rate limits per realm. Since the ContextResolverFilter
still applies first, we shouldn't see a practical difference.
.servlets() | ||
.addFilter("ratelimiter", new RateLimiterFilter(configuration.getRateLimiter())) | ||
.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*"); | ||
environment.jersey().register(new RateLimiterFilter(configuration.getRateLimiter())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This change is unrelated to metrics, right ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See #423 (comment)
@@ -66,16 +66,16 @@ private class TimedRequestEventListener implements RequestEventListener { | |||
@Override | |||
public void onEvent(RequestEvent event) { | |||
String realmId = CallContext.getCurrentContext().getRealmContext().getRealmIdentifier(); | |||
if (event.getType() == RequestEvent.Type.RESOURCE_METHOD_START) { | |||
if (event.getType() == RequestEvent.Type.REQUEST_MATCHED) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FYI, this listener to @TimedApi
(populated in mustache template) is not required with Quarkus.
> 0); | ||
} | ||
|
||
private double getCounter(String metricName) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Will replace this with https://github.com/apache/polaris/blob/cfd908ad3bc7527d5fbd2127f8eb7bce54a0acbd/polaris-service/src/test/java/org/apache/polaris/service/test/TestMetricsUtil.java once my other PR is merged
environment | ||
.servlets() | ||
.addFilter("ratelimiter", new RateLimiterFilter(configuration.getRateLimiter())) | ||
.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*"); | ||
environment.jersey().register(new RateLimiterFilter(configuration.getRateLimiter())); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Semantically, there is a difference, as ServletFilters are applied before Jersey Filters. Practically, however, it shouldn't have an impact. I think the only real dependency the RateLimiter might have is that the RealmContext is set in case there are different rate limits per realm. Since the ContextResolverFilter
still applies first, we shouldn't see a practical difference.
Description
Makes requests emit metrics when they get rate limited.
There were 2 issues preventing this:
This PR makes the rate limiting filter a Jersey Servlet filter and makes the per-request metric emitter emit count metrics for requests that have a REQUEST_MATCHED But not RESOURCE_METHOD_START event.
Type of change
How Has This Been Tested?
Please describe the tests that you ran to verify your changes. Provide instructions so we can reproduce. Please also list any relevant details for your test configuration
Checklist:
Please delete options that are not relevant.