Skip to content

Commit 383fe47

Browse files
Merge branch '1.15.x'
2 parents 79f0517 + ce3a9e0 commit 383fe47

File tree

2 files changed

+42
-8
lines changed

2 files changed

+42
-8
lines changed

micrometer-observation/src/main/java/io/micrometer/observation/aop/ObservedAspect.java

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@
7171
* @author Jonatan Ivanov
7272
* @author Yanming Zhou
7373
* @author Jeonggi Kim
74+
* @author Maksim Petelin
7475
* @since 1.10.0
7576
*/
7677
@Aspect
@@ -147,16 +148,16 @@ public ObservedAspect(ObservationRegistry registry,
147148
try {
148149
Object result = pjp.proceed();
149150
if (result == null) {
150-
stopObservation(observation, scope, null);
151+
stopObservation(observation, null);
151152
return result;
152153
}
153154
else {
154155
CompletionStage<?> stage = (CompletionStage<?>) result;
155-
return stage.whenComplete((res, error) -> stopObservation(observation, scope, error));
156+
return stage.whenComplete((res, error) -> stopObservation(observation, error));
156157
}
157158
}
158159
catch (Throwable error) {
159-
stopObservation(observation, scope, error);
160+
stopObservation(observation, error);
160161
throw error;
161162
}
162163
finally {
@@ -187,11 +188,10 @@ private Method getMethod(ProceedingJoinPoint pjp) throws NoSuchMethodException {
187188
return method;
188189
}
189190

190-
private void stopObservation(Observation observation, Observation.Scope scope, @Nullable Throwable error) {
191+
private void stopObservation(Observation observation, @Nullable Throwable error) {
191192
if (error != null) {
192193
observation.error(error);
193194
}
194-
scope.close();
195195
observation.stop();
196196
}
197197

samples/micrometer-samples-spring-framework6/src/test/java/io/micrometer/samples/spring6/aop/ObservedAspectTests.java

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -169,6 +169,26 @@ void annotatedAsyncCallShouldBeObservedAndErrorRecorded() {
169169
.isEqualTo(simulatedException);
170170
}
171171

172+
@Test
173+
void observationShouldNotLeakToFutureCompletionThread() {
174+
registry.observationConfig().observationHandler(new ObservationTextPublisher());
175+
176+
AspectJProxyFactory pf = new AspectJProxyFactory(new ObservedService());
177+
pf.addAspect(new ObservedAspect(registry));
178+
179+
ObservedService service = pf.getProxy();
180+
FakeAsyncTask fakeAsyncTask = new FakeAsyncTask("test-result");
181+
182+
ExecutorService executor = Executors.newSingleThreadExecutor();
183+
CompletableFuture<String> asyncResult = service.supply(() -> service.async(fakeAsyncTask, executor));
184+
// must run in the thread of the executor (async task)
185+
CompletableFuture<Void> asyncAssertion = asyncResult
186+
.thenRunAsync(() -> assertThat(registry).doesNotHaveAnyRemainingCurrentObservation(), executor);
187+
fakeAsyncTask.proceed();
188+
189+
assertThat(asyncAssertion).succeedsWithin(Duration.ofMillis(200));
190+
}
191+
172192
@Test
173193
void customObservationConventionShouldBeUsed() {
174194
registry.observationConfig().observationHandler(new ObservationTextPublisher());
@@ -391,14 +411,28 @@ void error() {
391411

392412
@Observed(name = "test.async")
393413
CompletableFuture<String> async(FakeAsyncTask fakeAsyncTask) {
394-
System.out.println("async");
395414
ContextSnapshot contextSnapshot = ContextSnapshotFactory.builder()
396415
.captureKeyPredicate(key -> true)
397416
.contextRegistry(ContextRegistry.getInstance())
398417
.build()
399418
.captureAll();
400-
return CompletableFuture.supplyAsync(fakeAsyncTask,
401-
contextSnapshot.wrapExecutor(Executors.newSingleThreadExecutor()));
419+
return supplyAsync(fakeAsyncTask, contextSnapshot.wrapExecutor(Executors.newSingleThreadExecutor()));
420+
}
421+
422+
@Observed(name = "test.async")
423+
CompletableFuture<String> async(FakeAsyncTask fakeAsyncTask, Executor singleThreadExecutor) {
424+
return supplyAsync(fakeAsyncTask, singleThreadExecutor);
425+
}
426+
427+
@Observed(name = "test.supply")
428+
<T> T supply(Supplier<T> supplier) {
429+
System.out.println("supply");
430+
return supplier.get();
431+
}
432+
433+
private CompletableFuture<String> supplyAsync(FakeAsyncTask fakeAsyncTask, Executor executor) {
434+
System.out.println("async");
435+
return CompletableFuture.supplyAsync(fakeAsyncTask, executor);
402436
}
403437

404438
}

0 commit comments

Comments
 (0)