Skip to content

fix: mark push CANCELED when client disconnects mid-push#217

Merged
coopernetes merged 1 commit into
mainfrom
feat/heartbeat-disconnect-cancel
May 5, 2026
Merged

fix: mark push CANCELED when client disconnects mid-push#217
coopernetes merged 1 commit into
mainfrom
feat/heartbeat-disconnect-cancel

Conversation

@coopernetes
Copy link
Copy Markdown
Member

Summary

  • Adds an onDisconnect callback to HeartbeatSender — fires once when a sideband write throws, indicating the client has gone away
  • StoreAndForwardReceivePackFactory wires the callback to PushStore.cancel() on the active push record, using validationRecordId (PENDING) if set, otherwise the initial pushId (RECEIVED)
  • No sweeper added — a TTL-based approach cannot distinguish abandoned RECEIVED records from PENDING records legitimately waiting in the approval queue

closes #214

Test plan

  • Push to /push/ path and Ctrl+C mid-way through the approval wait; confirm push record transitions to CANCELED
  • Normal push (no disconnect) still reaches FORWARDED correctly
  • Unit tests pass: ./gradlew :git-proxy-java-core:test

@coopernetes coopernetes force-pushed the feat/heartbeat-disconnect-cancel branch from ee7b1c1 to 065831e Compare May 5, 2026 13:47
…missing adminOverride

When a git client disconnects (e.g. Ctrl+C) during store-and-forward
processing, the push record was left stuck in RECEIVED or PENDING
indefinitely with no mechanism to clean it up.

Add an onDisconnect callback to HeartbeatSender. The heartbeat already
detects socket closure via IOException on the sideband write — now it
fires the callback when that happens. StoreAndForwardReceivePackFactory
wires the callback to call PushStore.cancel() on the active push record,
using validationRecordId (PENDING) if available, otherwise falling back
to the initial pushId (RECEIVED).

Also fix the approve endpoint returning HTTP 400 when the adminOverride
field is absent from the request body. The field was a primitive boolean,
causing Jackson to reject null with HttpMessageNotReadableException. Box
it to Boolean and treat null as false via Boolean.TRUE.equals(). Fix the
proxy-pass smoke test body to use the correct field names while here.

closes #214

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coopernetes coopernetes force-pushed the feat/heartbeat-disconnect-cancel branch from 065831e to 79915fd Compare May 5, 2026 13:49
@coopernetes coopernetes merged commit c0c9a4e into main May 5, 2026
16 checks passed
@coopernetes coopernetes deleted the feat/heartbeat-disconnect-cancel branch May 5, 2026 14:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

bug: client disconnect (ctrl+c) on /push leaves push record dangling in RECEIVED/PENDING

1 participant