Stop observations for async requests in Servlet filter
Prior to this commit, the `ServerHttpObservationFilter` would support async dispatches and would do the following: 1. start the observation 2. call the filter chain 3. if async has started, do nothing 4. if not in async mode, stop the observation This behavior would effectively rely on Async implementations to complete and dispatch the request back to the container for an async dispatch. This is what Spring web frameworks do and guarantee. Some implementations complete the async request but do not dispatch back; as a result, observations could leak as they are never stopped. This commit changes the support of async requests. The filter now opts-out of async dispatches - the filter will not be called for those anymore. Instead, if the application started async mode during the initial container dispatch, the filter will register an AsyncListener to be notified of the outcome of the async handling. Fixes gh-32730
This commit is contained in:
@@ -50,6 +50,11 @@ class ServerHttpObservationFilterTests {
|
||||
private final MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
|
||||
|
||||
@Test
|
||||
void filterShouldNotProcessAsyncDispatch() {
|
||||
assertThat(this.filter.shouldNotFilterAsyncDispatch()).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
void filterShouldFillObservationContext() throws Exception {
|
||||
this.filter.doFilter(this.request, this.response, this.mockFilterChain);
|
||||
@@ -60,7 +65,7 @@ class ServerHttpObservationFilterTests {
|
||||
assertThat(context.getCarrier()).isEqualTo(this.request);
|
||||
assertThat(context.getResponse()).isEqualTo(this.response);
|
||||
assertThat(context.getPathPattern()).isNull();
|
||||
assertThatHttpObservation().hasLowCardinalityKeyValue("outcome", "SUCCESS");
|
||||
assertThatHttpObservation().hasLowCardinalityKeyValue("outcome", "SUCCESS").hasBeenStopped();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -109,6 +114,16 @@ class ServerHttpObservationFilterTests {
|
||||
.hasLowCardinalityKeyValue("status", "500");
|
||||
}
|
||||
|
||||
@Test
|
||||
void shouldCloseObservationAfterAsyncCompletion() throws Exception {
|
||||
this.request.setAsyncSupported(true);
|
||||
this.request.startAsync();
|
||||
this.filter.doFilter(this.request, this.response, this.mockFilterChain);
|
||||
this.request.getAsyncContext().complete();
|
||||
|
||||
assertThatHttpObservation().hasLowCardinalityKeyValue("outcome", "SUCCESS").hasBeenStopped();
|
||||
}
|
||||
|
||||
private TestObservationRegistryAssert.TestObservationRegistryAssertReturningObservationContextAssert assertThatHttpObservation() {
|
||||
return TestObservationRegistryAssert.assertThat(this.observationRegistry)
|
||||
.hasObservationWithNameEqualTo("http.server.requests").that();
|
||||
|
||||
Reference in New Issue
Block a user