Completable result code throwable (#6348)
This commit is contained in:
parent
d16ba00e15
commit
fc283ba763
|
|
@ -1,2 +1,7 @@
|
|||
Comparing source compatibility of opentelemetry-sdk-common-1.41.0-SNAPSHOT.jar against opentelemetry-sdk-common-1.40.0.jar
|
||||
No changes.
|
||||
*** MODIFIED CLASS: PUBLIC FINAL io.opentelemetry.sdk.common.CompletableResultCode (not serializable)
|
||||
=== CLASS FILE FORMAT VERSION: 52.0 <- 52.0
|
||||
+++ NEW METHOD: PUBLIC(+) io.opentelemetry.sdk.common.CompletableResultCode failExceptionally(java.lang.Throwable)
|
||||
+++ NEW METHOD: PUBLIC(+) java.lang.Throwable getFailureThrowable()
|
||||
+++ NEW ANNOTATION: javax.annotation.Nullable
|
||||
+++ NEW METHOD: PUBLIC(+) STATIC(+) io.opentelemetry.sdk.common.CompletableResultCode ofExceptionalFailure(java.lang.Throwable)
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ import java.util.concurrent.CountDownLatch;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/**
|
||||
|
|
@ -33,9 +34,19 @@ public final class CompletableResultCode {
|
|||
return FAILURE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link CompletableResultCode} that has been {@link #failExceptionally(Throwable)
|
||||
* failed exceptionally}.
|
||||
*/
|
||||
public static CompletableResultCode ofExceptionalFailure(Throwable throwable) {
|
||||
return new CompletableResultCode().failExceptionally(throwable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link CompletableResultCode} that completes after all the provided {@link
|
||||
* CompletableResultCode}s complete. If any of the results fail, the result will be failed.
|
||||
* CompletableResultCode}s complete. If any of the results fail, the result will be failed. If any
|
||||
* {@link #failExceptionally(Throwable) failed exceptionally}, the result will be failed
|
||||
* exceptionally with the first {@link Throwable} from {@code codes}.
|
||||
*/
|
||||
public static CompletableResultCode ofAll(Collection<CompletableResultCode> codes) {
|
||||
if (codes.isEmpty()) {
|
||||
|
|
@ -44,15 +55,20 @@ public final class CompletableResultCode {
|
|||
CompletableResultCode result = new CompletableResultCode();
|
||||
AtomicInteger pending = new AtomicInteger(codes.size());
|
||||
AtomicBoolean failed = new AtomicBoolean();
|
||||
AtomicReference<Throwable> throwableRef = new AtomicReference<>();
|
||||
for (CompletableResultCode code : codes) {
|
||||
code.whenComplete(
|
||||
() -> {
|
||||
if (!code.isSuccess()) {
|
||||
failed.set(true);
|
||||
Throwable codeThrowable = code.getFailureThrowable();
|
||||
if (codeThrowable != null) {
|
||||
throwableRef.compareAndSet(null, codeThrowable);
|
||||
}
|
||||
}
|
||||
if (pending.decrementAndGet() == 0) {
|
||||
if (failed.get()) {
|
||||
result.fail();
|
||||
result.failInternal(throwableRef.get());
|
||||
} else {
|
||||
result.succeed();
|
||||
}
|
||||
|
|
@ -71,6 +87,10 @@ public final class CompletableResultCode {
|
|||
@GuardedBy("lock")
|
||||
private Boolean succeeded = null;
|
||||
|
||||
@Nullable
|
||||
@GuardedBy("lock")
|
||||
private Throwable throwable = null;
|
||||
|
||||
@GuardedBy("lock")
|
||||
private final List<Runnable> completionActions = new ArrayList<>();
|
||||
|
||||
|
|
@ -89,11 +109,27 @@ public final class CompletableResultCode {
|
|||
return this;
|
||||
}
|
||||
|
||||
/** Complete this {@link CompletableResultCode} unsuccessfully if it is not already completed. */
|
||||
/**
|
||||
* Complete this {@link CompletableResultCode} unsuccessfully if it is not already completed,
|
||||
* setting the {@link #getFailureThrowable() failure throwable} to {@code null}.
|
||||
*/
|
||||
public CompletableResultCode fail() {
|
||||
return failInternal(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Completes this {@link CompletableResultCode} unsuccessfully if it is not already completed,
|
||||
* setting the {@link #getFailureThrowable() failure throwable} to {@code throwable}.
|
||||
*/
|
||||
public CompletableResultCode failExceptionally(Throwable throwable) {
|
||||
return failInternal(throwable);
|
||||
}
|
||||
|
||||
private CompletableResultCode failInternal(@Nullable Throwable throwable) {
|
||||
synchronized (lock) {
|
||||
if (succeeded == null) {
|
||||
succeeded = false;
|
||||
this.throwable = throwable;
|
||||
for (Runnable action : completionActions) {
|
||||
action.run();
|
||||
}
|
||||
|
|
@ -104,7 +140,7 @@ public final class CompletableResultCode {
|
|||
|
||||
/**
|
||||
* Obtain the current state of completion. Generally call once completion is achieved via the
|
||||
* thenRun method.
|
||||
* {@link #whenComplete(Runnable)} method.
|
||||
*
|
||||
* @return the current state of completion
|
||||
*/
|
||||
|
|
@ -114,6 +150,21 @@ public final class CompletableResultCode {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns {@link Throwable} if this {@link CompletableResultCode} was {@link
|
||||
* #failExceptionally(Throwable) failed exceptionally}. Generally call once completion is achieved
|
||||
* via the {@link #whenComplete(Runnable)} method.
|
||||
*
|
||||
* @return the throwable if failed exceptionally, or null if: {@link #fail() failed without
|
||||
* exception}, {@link #succeed() succeeded}, or not complete.
|
||||
*/
|
||||
@Nullable
|
||||
public Throwable getFailureThrowable() {
|
||||
synchronized (lock) {
|
||||
return throwable;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Perform an action on completion. Actions are guaranteed to be called only once.
|
||||
*
|
||||
|
|
|
|||
|
|
@ -21,12 +21,32 @@ class CompletableResultCodeTest {
|
|||
|
||||
@Test
|
||||
void ofSuccess() {
|
||||
assertThat(CompletableResultCode.ofSuccess().isSuccess()).isTrue();
|
||||
assertThat(CompletableResultCode.ofSuccess())
|
||||
.satisfies(
|
||||
code -> {
|
||||
assertThat(code.isSuccess()).isTrue();
|
||||
assertThat(code.getFailureThrowable()).isNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofFailure() {
|
||||
assertThat(CompletableResultCode.ofFailure().isSuccess()).isFalse();
|
||||
assertThat(CompletableResultCode.ofFailure())
|
||||
.satisfies(
|
||||
code -> {
|
||||
assertThat(code.isSuccess()).isFalse();
|
||||
assertThat(code.getFailureThrowable()).isNull();
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofExceptionalFailure() {
|
||||
assertThat(CompletableResultCode.ofExceptionalFailure(new Exception("error")))
|
||||
.satisfies(
|
||||
code -> {
|
||||
assertThat(code.isSuccess()).isFalse();
|
||||
assertThat(code.getFailureThrowable()).hasMessage("error");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
|
|
@ -149,6 +169,24 @@ class CompletableResultCodeTest {
|
|||
.isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
void ofAllWithExceptionalFailure() {
|
||||
assertThat(
|
||||
CompletableResultCode.ofAll(
|
||||
Arrays.asList(
|
||||
CompletableResultCode.ofSuccess(),
|
||||
CompletableResultCode.ofFailure(),
|
||||
CompletableResultCode.ofExceptionalFailure(new Exception("error1")),
|
||||
CompletableResultCode.ofExceptionalFailure(new Exception("error2")),
|
||||
CompletableResultCode.ofSuccess())))
|
||||
.satisfies(
|
||||
code -> {
|
||||
assertThat(code.isSuccess()).isFalse();
|
||||
// failure throwable is set to first throwable seen in the collection
|
||||
assertThat(code.getFailureThrowable()).hasMessage("error1");
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
void join() {
|
||||
CompletableResultCode result = new CompletableResultCode();
|
||||
|
|
|
|||
Loading…
Reference in New Issue