Skip to content

Commit 1a4adb4

Browse files
authored
fix: add missing span.end calls for AsyncTransactionManager (#4012)
The AsyncTransactionManager did not end the span when the transaction was committed or rolled back. This caused the spans not to be collected and exported.
1 parent 8156ef3 commit 1a4adb4

File tree

2 files changed

+66
-0
lines changed

2 files changed

+66
-0
lines changed

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

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,12 +165,19 @@ public void onFailure(Throwable t) {
165165
txnState = TransactionState.ABORTED;
166166
} else {
167167
txnState = TransactionState.COMMIT_FAILED;
168+
if (span != null) {
169+
span.setStatus(t);
170+
span.end();
171+
}
168172
commitResponse.setException(t);
169173
}
170174
}
171175

172176
@Override
173177
public void onSuccess(CommitResponse result) {
178+
if (span != null) {
179+
span.end();
180+
}
174181
commitResponse.set(result);
175182
}
176183
},
@@ -190,6 +197,10 @@ public ApiFuture<Void> rollbackAsync() {
190197
ignored -> ApiFutures.immediateFuture(null),
191198
MoreExecutors.directExecutor());
192199
} finally {
200+
if (span != null) {
201+
span.addAnnotation("Transaction rolled back");
202+
span.end();
203+
}
193204
txnState = TransactionState.ROLLED_BACK;
194205
}
195206
}

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

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,11 +27,14 @@
2727
import com.google.api.gax.longrunning.OperationTimedPollAlgorithm;
2828
import com.google.api.gax.retrying.RetrySettings;
2929
import com.google.cloud.NoCredentials;
30+
import com.google.cloud.spanner.AsyncTransactionManager.CommitTimestampFuture;
31+
import com.google.cloud.spanner.AsyncTransactionManager.TransactionContextFuture;
3032
import com.google.cloud.spanner.MockSpannerServiceImpl.SimulatedExecutionTime;
3133
import com.google.cloud.spanner.MockSpannerServiceImpl.StatementResult;
3234
import com.google.cloud.spanner.SpannerOptions.SpannerEnvironment;
3335
import com.google.cloud.spanner.connection.RandomResultSetGenerator;
3436
import com.google.common.collect.ImmutableList;
37+
import com.google.common.util.concurrent.MoreExecutors;
3538
import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
3639
import io.grpc.Status;
3740
import io.opentelemetry.api.GlobalOpenTelemetry;
@@ -451,6 +454,58 @@ public boolean isEnableApiTracing() {
451454
"CloudSpannerOperation.ExecuteStreamingQuery", "Spanner.ExecuteStreamingSql", spans);
452455
}
453456

457+
@Test
458+
public void testAsyncTransactionManagerCommit() throws Exception {
459+
try (AsyncTransactionManager manager = client.transactionManagerAsync()) {
460+
TransactionContextFuture transactionFuture = manager.beginAsync();
461+
CommitTimestampFuture commitTimestamp =
462+
transactionFuture
463+
.then(
464+
(transaction, __) -> transaction.executeUpdateAsync(UPDATE_RANDOM),
465+
MoreExecutors.directExecutor())
466+
.commitAsync();
467+
commitTimestamp.get();
468+
}
469+
470+
assertEquals(CompletableResultCode.ofSuccess(), spanExporter.flush());
471+
List<SpanData> spans = spanExporter.getFinishedSpanItems();
472+
assertContains("CloudSpanner.ReadWriteTransaction", spans);
473+
assertContains("CloudSpannerOperation.ExecuteUpdate", spans);
474+
assertContains("CloudSpannerOperation.Commit", spans);
475+
assertContains("Spanner.ExecuteSql", spans);
476+
assertContains("Spanner.Commit", spans);
477+
478+
assertParent("CloudSpanner.ReadWriteTransaction", "CloudSpannerOperation.ExecuteUpdate", spans);
479+
assertParent("CloudSpanner.ReadWriteTransaction", "CloudSpannerOperation.Commit", spans);
480+
assertParent("CloudSpannerOperation.ExecuteUpdate", "Spanner.ExecuteSql", spans);
481+
}
482+
483+
@Test
484+
public void testAsyncTransactionManagerRollback() throws Exception {
485+
try (AsyncTransactionManager manager = client.transactionManagerAsync()) {
486+
TransactionContextFuture transactionFuture = manager.beginAsync();
487+
transactionFuture
488+
.then(
489+
(transaction, __) -> transaction.executeUpdateAsync(UPDATE_RANDOM),
490+
MoreExecutors.directExecutor())
491+
.get();
492+
manager.rollbackAsync().get();
493+
}
494+
495+
assertEquals(CompletableResultCode.ofSuccess(), spanExporter.flush());
496+
List<SpanData> spans = spanExporter.getFinishedSpanItems();
497+
assertContains("CloudSpanner.ReadWriteTransaction", spans);
498+
assertContains("CloudSpannerOperation.ExecuteUpdate", spans);
499+
assertContains("Spanner.ExecuteSql", spans);
500+
assertContains("Spanner.Rollback", spans);
501+
502+
assertParent("CloudSpanner.ReadWriteTransaction", "CloudSpannerOperation.ExecuteUpdate", spans);
503+
assertParent("CloudSpannerOperation.ExecuteUpdate", "Spanner.ExecuteSql", spans);
504+
SpanData transactionSpan = getSpan("CloudSpanner.ReadWriteTransaction", spans);
505+
assertNotNull(transactionSpan);
506+
assertContainsEvent("Transaction rolled back", transactionSpan.getEvents());
507+
}
508+
454509
void assertContains(String expected, List<SpanData> spans) {
455510
assertTrue(
456511
"Expected " + spansToString(spans) + " to contain " + expected,

0 commit comments

Comments
 (0)