@@ -170,6 +170,26 @@ void annotatedAsyncCallShouldBeObservedAndErrorRecorded() {
170170 .isEqualTo (simulatedException );
171171 }
172172
173+ @ Test
174+ void observationShouldNotLeakToFutureCompletionThread () {
175+ registry .observationConfig ().observationHandler (new ObservationTextPublisher ());
176+
177+ AspectJProxyFactory pf = new AspectJProxyFactory (new ObservedService ());
178+ pf .addAspect (new ObservedAspect (registry ));
179+
180+ ObservedService service = pf .getProxy ();
181+ FakeAsyncTask fakeAsyncTask = new FakeAsyncTask ("test-result" );
182+
183+ ExecutorService executor = Executors .newSingleThreadExecutor ();
184+ CompletableFuture <String > asyncResult = service .supply (() -> service .async (fakeAsyncTask , executor ));
185+ // must run in the thread of the executor (async task)
186+ CompletableFuture <Void > asyncAssertion = asyncResult
187+ .thenRunAsync (() -> assertThat (registry ).doesNotHaveAnyRemainingCurrentObservation (), executor );
188+ fakeAsyncTask .proceed ();
189+
190+ assertThat (asyncAssertion ).succeedsWithin (Duration .ofMillis (200 ));
191+ }
192+
173193 @ Test
174194 void customObservationConventionShouldBeUsed () {
175195 registry .observationConfig ().observationHandler (new ObservationTextPublisher ());
@@ -392,14 +412,28 @@ void error() {
392412
393413 @ Observed (name = "test.async" )
394414 CompletableFuture <String > async (FakeAsyncTask fakeAsyncTask ) {
395- System .out .println ("async" );
396415 ContextSnapshot contextSnapshot = ContextSnapshotFactory .builder ()
397416 .captureKeyPredicate (key -> true )
398417 .contextRegistry (ContextRegistry .getInstance ())
399418 .build ()
400419 .captureAll ();
401- return CompletableFuture .supplyAsync (fakeAsyncTask ,
402- contextSnapshot .wrapExecutor (Executors .newSingleThreadExecutor ()));
420+ return supplyAsync (fakeAsyncTask , contextSnapshot .wrapExecutor (Executors .newSingleThreadExecutor ()));
421+ }
422+
423+ @ Observed (name = "test.async" )
424+ CompletableFuture <String > async (FakeAsyncTask fakeAsyncTask , Executor singleThreadExecutor ) {
425+ return supplyAsync (fakeAsyncTask , singleThreadExecutor );
426+ }
427+
428+ @ Observed (name = "test.supply" )
429+ <T > T supply (Supplier <T > supplier ) {
430+ System .out .println ("supply" );
431+ return supplier .get ();
432+ }
433+
434+ private CompletableFuture <String > supplyAsync (FakeAsyncTask fakeAsyncTask , Executor executor ) {
435+ System .out .println ("async" );
436+ return CompletableFuture .supplyAsync (fakeAsyncTask , executor );
403437 }
404438
405439 }
0 commit comments