Skip to content

Commit fc283ba

Browse files
authored
Completable result code throwable (#6348)
1 parent d16ba00 commit fc283ba

File tree

3 files changed

+101
-7
lines changed

3 files changed

+101
-7
lines changed
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,7 @@
11
Comparing source compatibility of opentelemetry-sdk-common-1.41.0-SNAPSHOT.jar against opentelemetry-sdk-common-1.40.0.jar
2-
No changes.
2+
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.common.CompletableResultCode (not serializable)
3+
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
4+
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.CompletableResultCode failExceptionally(java.lang.Throwable)
5+
+++ NEW METHOD: PUBLIC(+) java.lang.Throwable getFailureThrowable()
6+
+++ NEW ANNOTATION: javax.annotation.Nullable
7+
+++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.CompletableResultCode ofExceptionalFailure(java.lang.Throwable)

sdk/common/src/main/java/io/opentelemetry/sdk/common/CompletableResultCode.java

+55-4
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import java.util.concurrent.TimeUnit;
1414
import java.util.concurrent.atomic.AtomicBoolean;
1515
import java.util.concurrent.atomic.AtomicInteger;
16+
import java.util.concurrent.atomic.AtomicReference;
1617
import javax.annotation.Nullable;
1718

1819
/**
@@ -33,9 +34,19 @@ public static CompletableResultCode ofFailure() {
3334
return FAILURE;
3435
}
3536

37+
/**
38+
* Returns a {@link CompletableResultCode} that has been {@link #failExceptionally(Throwable)
39+
* failed exceptionally}.
40+
*/
41+
public static CompletableResultCode ofExceptionalFailure(Throwable throwable) {
42+
return new CompletableResultCode().failExceptionally(throwable);
43+
}
44+
3645
/**
3746
* Returns a {@link CompletableResultCode} that completes after all the provided {@link
38-
* CompletableResultCode}s complete. If any of the results fail, the result will be failed.
47+
* CompletableResultCode}s complete. If any of the results fail, the result will be failed. If any
48+
* {@link #failExceptionally(Throwable) failed exceptionally}, the result will be failed
49+
* exceptionally with the first {@link Throwable} from {@code codes}.
3950
*/
4051
public static CompletableResultCode ofAll(Collection<CompletableResultCode> codes) {
4152
if (codes.isEmpty()) {
@@ -44,15 +55,20 @@ public static CompletableResultCode ofAll(Collection<CompletableResultCode> code
4455
CompletableResultCode result = new CompletableResultCode();
4556
AtomicInteger pending = new AtomicInteger(codes.size());
4657
AtomicBoolean failed = new AtomicBoolean();
58+
AtomicReference<Throwable> throwableRef = new AtomicReference<>();
4759
for (CompletableResultCode code : codes) {
4860
code.whenComplete(
4961
() -> {
5062
if (!code.isSuccess()) {
5163
failed.set(true);
64+
Throwable codeThrowable = code.getFailureThrowable();
65+
if (codeThrowable != null) {
66+
throwableRef.compareAndSet(null, codeThrowable);
67+
}
5268
}
5369
if (pending.decrementAndGet() == 0) {
5470
if (failed.get()) {
55-
result.fail();
71+
result.failInternal(throwableRef.get());
5672
} else {
5773
result.succeed();
5874
}
@@ -71,6 +87,10 @@ public CompletableResultCode() {}
7187
@GuardedBy("lock")
7288
private Boolean succeeded = null;
7389

90+
@Nullable
91+
@GuardedBy("lock")
92+
private Throwable throwable = null;
93+
7494
@GuardedBy("lock")
7595
private final List<Runnable> completionActions = new ArrayList<>();
7696

@@ -89,11 +109,27 @@ public CompletableResultCode succeed() {
89109
return this;
90110
}
91111

92-
/** Complete this {@link CompletableResultCode} unsuccessfully if it is not already completed. */
112+
/**
113+
* Complete this {@link CompletableResultCode} unsuccessfully if it is not already completed,
114+
* setting the {@link #getFailureThrowable() failure throwable} to {@code null}.
115+
*/
93116
public CompletableResultCode fail() {
117+
return failInternal(null);
118+
}
119+
120+
/**
121+
* Completes this {@link CompletableResultCode} unsuccessfully if it is not already completed,
122+
* setting the {@link #getFailureThrowable() failure throwable} to {@code throwable}.
123+
*/
124+
public CompletableResultCode failExceptionally(Throwable throwable) {
125+
return failInternal(throwable);
126+
}
127+
128+
private CompletableResultCode failInternal(@Nullable Throwable throwable) {
94129
synchronized (lock) {
95130
if (succeeded == null) {
96131
succeeded = false;
132+
this.throwable = throwable;
97133
for (Runnable action : completionActions) {
98134
action.run();
99135
}
@@ -104,7 +140,7 @@ public CompletableResultCode fail() {
104140

105141
/**
106142
* Obtain the current state of completion. Generally call once completion is achieved via the
107-
* thenRun method.
143+
* {@link #whenComplete(Runnable)} method.
108144
*
109145
* @return the current state of completion
110146
*/
@@ -114,6 +150,21 @@ public boolean isSuccess() {
114150
}
115151
}
116152

153+
/**
154+
* Returns {@link Throwable} if this {@link CompletableResultCode} was {@link
155+
* #failExceptionally(Throwable) failed exceptionally}. Generally call once completion is achieved
156+
* via the {@link #whenComplete(Runnable)} method.
157+
*
158+
* @return the throwable if failed exceptionally, or null if: {@link #fail() failed without
159+
* exception}, {@link #succeed() succeeded}, or not complete.
160+
*/
161+
@Nullable
162+
public Throwable getFailureThrowable() {
163+
synchronized (lock) {
164+
return throwable;
165+
}
166+
}
167+
117168
/**
118169
* Perform an action on completion. Actions are guaranteed to be called only once.
119170
*

sdk/common/src/test/java/io/opentelemetry/sdk/common/CompletableResultCodeTest.java

+40-2
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,32 @@ class CompletableResultCodeTest {
2121

2222
@Test
2323
void ofSuccess() {
24-
assertThat(CompletableResultCode.ofSuccess().isSuccess()).isTrue();
24+
assertThat(CompletableResultCode.ofSuccess())
25+
.satisfies(
26+
code -> {
27+
assertThat(code.isSuccess()).isTrue();
28+
assertThat(code.getFailureThrowable()).isNull();
29+
});
2530
}
2631

2732
@Test
2833
void ofFailure() {
29-
assertThat(CompletableResultCode.ofFailure().isSuccess()).isFalse();
34+
assertThat(CompletableResultCode.ofFailure())
35+
.satisfies(
36+
code -> {
37+
assertThat(code.isSuccess()).isFalse();
38+
assertThat(code.getFailureThrowable()).isNull();
39+
});
40+
}
41+
42+
@Test
43+
void ofExceptionalFailure() {
44+
assertThat(CompletableResultCode.ofExceptionalFailure(new Exception("error")))
45+
.satisfies(
46+
code -> {
47+
assertThat(code.isSuccess()).isFalse();
48+
assertThat(code.getFailureThrowable()).hasMessage("error");
49+
});
3050
}
3151

3252
@Test
@@ -149,6 +169,24 @@ void ofAllWithFailure() {
149169
.isFalse();
150170
}
151171

172+
@Test
173+
void ofAllWithExceptionalFailure() {
174+
assertThat(
175+
CompletableResultCode.ofAll(
176+
Arrays.asList(
177+
CompletableResultCode.ofSuccess(),
178+
CompletableResultCode.ofFailure(),
179+
CompletableResultCode.ofExceptionalFailure(new Exception("error1")),
180+
CompletableResultCode.ofExceptionalFailure(new Exception("error2")),
181+
CompletableResultCode.ofSuccess())))
182+
.satisfies(
183+
code -> {
184+
assertThat(code.isSuccess()).isFalse();
185+
// failure throwable is set to first throwable seen in the collection
186+
assertThat(code.getFailureThrowable()).hasMessage("error1");
187+
});
188+
}
189+
152190
@Test
153191
void join() {
154192
CompletableResultCode result = new CompletableResultCode();

0 commit comments

Comments
 (0)