diff --git a/pkg/kv/txn_interceptor_heartbeater.go b/pkg/kv/txn_interceptor_heartbeater.go index 8dc20341cfcc..a1cbefc56b1a 100644 --- a/pkg/kv/txn_interceptor_heartbeater.go +++ b/pkg/kv/txn_interceptor_heartbeater.go @@ -375,25 +375,28 @@ func (h *txnHeartbeater) heartbeat(ctx context.Context) bool { // Clone the txn in order to put it in the heartbeat request. txn := h.mu.txn.Clone() - if txn.Key == nil { log.Fatalf(ctx, "attempting to heartbeat txn without anchor key: %v", txn) } - ba := roachpb.BatchRequest{} ba.Txn = txn - - hb := &roachpb.HeartbeatTxnRequest{ + ba.Add(&roachpb.HeartbeatTxnRequest{ RequestHeader: roachpb.RequestHeader{ Key: txn.Key, }, Now: h.clock.Now(), - } - ba.Add(hb) + }) + // Send the heartbeat request directly through the gatekeeper interceptor. + // See comment on h.gatekeeper for a discussion of why. log.VEvent(ctx, 2, "heartbeat") br, pErr := h.gatekeeper.SendLocked(ctx, ba) + // If the txn is no longer pending, ignore the result of the heartbeat. + if h.mu.txn.Status != roachpb.PENDING { + return false + } + var respTxn *roachpb.Transaction if pErr != nil { log.VEventf(ctx, 2, "heartbeat failed: %s", pErr)