Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
fix: handle thrown exceptions in runAsyncTransaction callback (#671)
  • Loading branch information
Brian Chen committed Jun 25, 2021
1 parent 7f1fee6 commit 969f7fd
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 7 deletions.
Expand Up @@ -145,28 +145,35 @@ public void run() {
* Invokes the user callback on the user callback executor and returns the user-provided result.
*/
private SettableApiFuture<T> invokeUserCallback() {
final SettableApiFuture<T> callbackResult = SettableApiFuture.create();
final SettableApiFuture<T> returnedResult = SettableApiFuture.create();

userCallbackExecutor.execute(
new Runnable() {
@Override
public void run() {
ApiFuture<T> userCallbackResult;
try {
userCallbackResult = userCallback.updateCallback(transaction);
} catch (Exception e) {
userCallbackResult = ApiFutures.immediateFailedFuture(e);
}
ApiFutures.addCallback(
userCallback.updateCallback(transaction),
userCallbackResult,
new ApiFutureCallback<T>() {
@Override
public void onFailure(Throwable t) {
callbackResult.setException(t);
returnedResult.setException(t);
}

@Override
public void onSuccess(T result) {
callbackResult.set(result);
returnedResult.set(result);
}
},
MoreExecutors.directExecutor());
firestoreExecutor);
}
});
return callbackResult;
return returnedResult;
}

/** A callback that invokes the BeginTransaction callback. */
Expand Down
Expand Up @@ -253,7 +253,7 @@ public String updateCallback(Transaction transaction) throws Exception {
}

@Test
public void rollbackOnCallbackErrorAsync() {
public void rollbackOnCallbackApiFutureErrorAsync() {
doReturn(beginResponse())
.doReturn(rollbackResponse())
.when(firestoreMock)
Expand Down Expand Up @@ -339,6 +339,31 @@ public ApiFuture<String> updateCallback(Transaction transaction) {
assertEquals(1, requests.size());
}

@Test
public void noRollbackOnThrownExceptionAsync() {
doReturn(beginResponse())
.doReturn(rollbackResponse())
.when(firestoreMock)
.sendRequest(requestCapture.capture(), Matchers.<UnaryCallable<Message, Message>>any());

ApiFuture<String> transaction =
firestoreMock.runAsyncTransaction(
new Transaction.AsyncFunction<String>() {
@Override
public ApiFuture<String> updateCallback(Transaction transaction) {
throw new RuntimeException("User exception");
}
},
options);

try {
transaction.get();
fail();
} catch (Exception e) {
assertTrue(e.getMessage().endsWith("User exception"));
}
}

@Test
public void limitsRetriesWithFailure() {
ResponseStubber responseStubber =
Expand Down
Expand Up @@ -688,6 +688,24 @@ public String updateCallback(Transaction transaction) {
}
}

@Test
public void asyncTxFailsWithUserError() throws Exception {
try {
firestore
.runAsyncTransaction(
new Transaction.AsyncFunction<String>() {
@Override
public ApiFuture<String> updateCallback(Transaction transaction) {
throw new RuntimeException("User exception");
}
})
.get();
fail();
} catch (Exception e) {
assertTrue(e.getMessage().endsWith("User exception"));
}
}

@Test
public void doesNotRetryTransactionsWithFailedPreconditions() {
final DocumentReference documentReference = randomColl.document();
Expand Down

0 comments on commit 969f7fd

Please sign in to comment.