Skip to content

🚧 RPC: Add action field to GetObject for error recovery 🚧#6837

Draft
knutwannheden wants to merge 3 commits intomainfrom
rpc-revert-action
Draft

🚧 RPC: Add action field to GetObject for error recovery 🚧#6837
knutwannheden wants to merge 3 commits intomainfrom
rpc-revert-action

Conversation

@knutwannheden
Copy link
Contributor

@knutwannheden knutwannheden commented Feb 27, 2026

Summary

  • Adds a nullable action field to GetObject requests for receiver-initiated corrective actions
  • When action="revert", the handler restores both remoteObjects and localObjects to the pre-transfer state using a stored baseline
  • The requester also reverts its own remoteObjects tracking to the pre-transfer value to stay in sync
  • Back out ref registrations on failed transfers: tracks newly registered refs (localRefs/remoteRefs) during each transfer and removes them on failure, preventing "reference to object not previously sent" errors on retry
  • Fixes sender-side failure cleanup: removes from actionBaseline so a subsequent "revert" from the receiver doesn't restore the remoteObjects entry the sender already cleaned up
  • Optimistic update on the success path — no extra round-trip needed
  • One extra round-trip on the failure path (receiver sends revert after failed deserialization)
  • Extensible: the action field can carry future actions without protocol changes

See doc/adr/0009-getobject-action-field.md for the full design rationale.

Test plan

  • gw :rewrite-core:test --tests "*RpcTest*" — all tests pass including sendFailureCleansUpRemoteObjects
  • gw :rewrite-python:integTest — exercise composite recipe RPC lifecycle
  • gw :rewrite-javascript:test --tests "*Rpc*" — JS RPC tests
  • TypeScript type-check passes (npx tsc --noEmit — no errors in src/)

Add a nullable `action` field to GetObject requests. When null, the
request is a normal data transfer. When set to "revert", the handler
restores both remoteObjects and localObjects to the pre-transfer state,
and the requester reverts its own remoteObjects tracking to match.

This fixes state desynchronization after failed deserialization: the
handler stores the pre-transfer baseline in an actionBaseline map at
transfer start, optimistically updates remoteObjects when streaming
completes, and rolls both maps back on revert.

The action field is extensible for future corrective actions (clear,
reset, abort) without protocol changes.
@github-project-automation github-project-automation bot moved this to In Progress in OpenRewrite Feb 27, 2026
@knutwannheden knutwannheden marked this pull request as draft February 27, 2026 06:52
@knutwannheden knutwannheden changed the title RPC: Add action field to GetObject for error recovery RPC: Add action field to GetObject for error recovery Feb 27, 2026
@knutwannheden knutwannheden changed the title RPC: Add action field to GetObject for error recovery 🚧 RPC: Add action field to GetObject for error recovery 🚧 Feb 27, 2026
Resolve conflicts in getObject error handling across Java, TypeScript,
and Python RPC implementations. Combined main's baseline fix (using
remoteObjects as receive baseline) and Python's END_OF_OBJECT drain
logic with the branch's revert-based error recovery.
When an RPC object transfer fails, refs registered in localRefs (sender)
and remoteRefs (receiver) during the failed transfer were not cleaned up.
On retry, the sender would send ref-ID-only (no payload) but the receiver
would throw "reference to object not previously sent".

Track newly registered refs during each transfer and remove them from the
shared maps on failure. Also fix sender-side failure cleanup: remove from
actionBaseline so a subsequent "revert" from the receiver doesn't restore
the remoteObjects entry the sender already cleaned up.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: In Progress

Development

Successfully merging this pull request may close these issues.

1 participant