Closed
Description
When testing the new R2DBC driver with the Cloud Spanner emulator, I noticed that the active transaction was not being rolled back despite AsyncTransactionManager.close()
being called.
The contract for close()
is to roll back the active transaction when closed, but I wonder if close()
was not meant to be implemented as closeAsync()
and kind of got left out.
Environment details
Spanner client library version: 1.59.0
Steps to reproduce
- Start emulator and set the emulator environment variable (
SPANNER_EMULATOR_HOST=localhost:9010
). The issue has nothing to do with the emulator, but it's really easy to observe when using one. - Update "project", "instance", "database" to real values.
- Set up the following table definition:
gcloud spanner databases ddl update database --ddl="CREATE TABLE test ( value INT64 ) PRIMARY KEY (value)" --instance=instance
- Run
transactionManagerRollsBackTransactionWhenClosed
twice; observe that everything works as expected. - Run
asyncTransactionManagerDoesNotRollBackTransactionWhenClosed
twice; observe that the first run succeeds, but the second fails with errorio.grpc.StatusRuntimeException: ABORTED: Transaction NNN aborted due to active transaction MMM. The emulator only supports one transaction at a time.
DatabaseId databaseId = DatabaseId.of("project", "instance", "database");
SpannerOptions options = SpannerOptions.newBuilder().build();
Spanner spanner = options.getService();
DatabaseClient dbClient = null;
TransactionManager txnManager = null;
AsyncTransactionManager asyncTxnManager = null;
@Test
public void transactionManagerRollsBackTransactionWhenClosed() throws Exception {
try {
dbClient = spanner.getDatabaseClient(databaseId);
txnManager = dbClient.transactionManager();
TransactionContext ctx = txnManager.begin();
ctx.executeUpdate(Statement.newBuilder("INSERT INTO test (value) VALUES (1234567)").build());
// MISSING COMMIT; expecting rollback
// tm.commit();
} finally {
if (txnManager != null) {
System.out.println("************ CLOSING TRANSACTION MANAGER");
txnManager.close();
}
}
}
@Test
public void asyncTransactionManagerDoesNotRollBackTransactionWhenClosed() throws Exception {
try {
dbClient = spanner.getDatabaseClient(databaseId);
asyncTxnManager = dbClient.transactionManagerAsync();
TransactionContext ctx = asyncTxnManager.beginAsync().get();
ctx.executeUpdateAsync(Statement.newBuilder("INSERT INTO test (value) VALUES (1234567)").build())
.get();
// MISSING COMMIT; expecting rollback upon transaction manager closing
// tm.commit();
} finally {
if (asyncTxnManager != null) {
asyncTxnManager.close();
}
}
}