Skip to content
This repository was archived by the owner on Apr 7, 2026. It is now read-only.

Commit 872e758

Browse files
committed
fix: getCommitResponse() should return error if tx rolled back
The ApiFuture that is returned by the AsyncTransactionManager#getCommitResponse() method should finish with an error if the transaction is rolled back.
1 parent 6886eb5 commit 872e758

3 files changed

Lines changed: 45 additions & 1 deletion

File tree

google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncTransactionManager.java

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,12 @@ interface AsyncTransactionFunction<I, O> {
203203
/** Returns the state of the transaction. */
204204
TransactionState getState();
205205

206-
/** Returns the {@link CommitResponse} of this transaction. */
206+
/**
207+
* Returns an {@link ApiFuture} with the eventual {@link CommitResponse} of this transaction. This
208+
* method can be called before the transaction has been committed. The {@link ApiFuture} will be
209+
* done when the transaction is committed or rolled back. If the commit fails or the transaction
210+
* is rolled back, the result of this {@link ApiFuture} will be an exception.
211+
*/
207212
ApiFuture<CommitResponse> getCommitResponse();
208213

209214
/**

google-cloud-spanner/src/main/java/com/google/cloud/spanner/AsyncTransactionManagerImpl.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,11 @@ public ApiFuture<Void> rollbackAsync() {
191191
Preconditions.checkState(
192192
txnState == TransactionState.STARTED,
193193
"rollback can only be called if the transaction is in progress");
194+
if (!commitResponse.isDone()) {
195+
commitResponse.setException(
196+
SpannerExceptionFactory.newSpannerException(
197+
ErrorCode.FAILED_PRECONDITION, "The transaction has been rolled back"));
198+
}
194199
try {
195200
return ApiFutures.transformAsync(
196201
txn.rollbackAsync(),

google-cloud-spanner/src/test/java/com/google/cloud/spanner/AsyncTransactionManagerTest.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import static com.google.cloud.spanner.SpannerApiFutures.get;
2626
import static com.google.common.truth.Truth.assertThat;
2727
import static org.junit.Assert.assertEquals;
28+
import static org.junit.Assert.assertFalse;
2829
import static org.junit.Assert.assertNotNull;
2930
import static org.junit.Assert.assertThrows;
3031
import static org.junit.Assert.assertTrue;
@@ -200,6 +201,39 @@ public void asyncTransactionManager_shouldRollbackOnCloseAsync() throws Exceptio
200201
0L);
201202
}
202203

204+
@Test
205+
public void testAsyncTransactionManager_commitResponseReturnsErrorAfterRollback()
206+
throws Exception {
207+
try (AsyncTransactionManager manager = client().transactionManagerAsync()) {
208+
TransactionContextFuture transactionContextFuture = manager.beginAsync();
209+
ApiFuture<CommitResponse> commitResponse = manager.getCommitResponse();
210+
while (true) {
211+
try {
212+
AsyncTransactionStep<Void, ?> next =
213+
transactionContextFuture.then(
214+
(transactionContext, ignored) ->
215+
transactionContext.bufferAsync(
216+
Collections.singleton(Mutation.delete("FOO", Key.of("foo")))),
217+
executor);
218+
assertFalse(commitResponse.isDone());
219+
manager.rollbackAsync().get();
220+
assertTrue(commitResponse.isDone());
221+
ExecutionException executionException =
222+
assertThrows(ExecutionException.class, commitResponse::get);
223+
assertEquals(SpannerException.class, executionException.getCause().getClass());
224+
SpannerException spannerException = (SpannerException) executionException.getCause();
225+
assertEquals(ErrorCode.FAILED_PRECONDITION, spannerException.getErrorCode());
226+
assertEquals(
227+
"FAILED_PRECONDITION: The transaction has been rolled back",
228+
spannerException.getMessage());
229+
break;
230+
} catch (AbortedException e) {
231+
transactionContextFuture = manager.resetForRetryAsync();
232+
}
233+
}
234+
}
235+
}
236+
203237
@Test
204238
public void testAsyncTransactionManager_returnsCommitStats() throws Exception {
205239
try (AsyncTransactionManager manager =

0 commit comments

Comments
 (0)