Skip to content

uffd-handler: the first peer dial waits for the source's capture - #1786

Merged
nikhilunni merged 2 commits into
mainfrom
fix/peer-first-dial-waits-for-capture
Nov 10, 2026
Merged

nikhilunni merged 2 commits into
mainfrom
fix/peer-first-dial-waits-for-capture

Conversation

@nikhilunni

Copy link
Copy Markdown
Contributor

Problem

The Firecracker root lane fails intermittently in the two-host live teleport tests:

postcopy-never-loaded: uffd handler exited before the load (exit status: 1);
handler log: … engram-uffd-handler: peer connect: peer io: Resource temporarily unavailable (os error 11)

The handler log in that error is new, and it names the cause.

The destination's memory handler dials the source before the source pauses the guest. The source holds that Hello until the capture registers the export (its budget is 120 s). Before the source pauses, it also waits for the destination to finish its disk precopy and ask for the VM state. The handler read HelloAck with the 5 s page-channel timeout. A capture that registers its export more than 5 s after the dial ends the handler with EAGAIN, and the restore fails.

This is a product defect, not only a test defect: a move whose destination needs more than 5 s between the handler's dial and the source's capture fails the same way, and the coordinator aborts it to the source.

Change

  • The first dial waits for HelloAck for the source's park budget plus one page timeout. When the export never registers, the source's own Error answer arrives first.
  • The 5 s page timeout applies again from Seal on. Redials and worker connections keep the 5 s limit, because their export exists.
  • The park budget is one constant, EXPORT_PARK_BUDGET in engram-migrate-proto, read by the server and the client.
  • handshake() is split from the dial, so the wait is an argument of one function.

A handler that waits on a source that died is still bounded: TCP keepalive is set on the socket before the handshake, and the host-agent's load gate ends the restore.

Tests

  • the_ack_wait_bounds_only_the_wait_for_hello_ack: a source that answers 300 ms late fails a 50 ms wait, passes a longer wait, and the socket then has the page timeout.
  • the_first_dial_outlasts_the_source_park_budget.
  • The Firecracker root lane of this PR runs the teleport tests that failed.

🤖 Generated with Claude Code

https://claude.ai/code/session_01HNhpmz4QPYaVCE7tFna54D

nikhilunni and others added 2 commits November 10, 2026 11:15
The destination's handler dials the source before the source pauses the
guest. The source holds that Hello until the capture registers the
export, and before it pauses it waits for the destination to finish its
disk precopy. The handler read HelloAck with the 5 s page-channel
timeout, so a capture later than 5 s after the dial ended the handler
with EAGAIN and the restore failed with postcopy-never-loaded. The
Firecracker root lane showed this as an intermittent failure of the
two-host live teleport tests.

The first dial now waits for HelloAck for the source's park budget plus
one page timeout, so the source's own answer arrives first when the
export never registers. The page timeout applies again from Seal on.
Redials and worker connections keep the 5 s limit: their export exists.

The park budget is one constant in engram-migrate-proto, read by the
server and the client.

Review pass: handshake() is split from the dial so the wait is an
argument of one function, not of each dial helper.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HNhpmz4QPYaVCE7tFna54D
The test set a 50 ms attempt deadline to end a hung first attempt. The
same deadline applied to the retry, which reads a local file. On a
loaded macOS runner that read took longer than 50 ms and the test
failed with 'attempt deadline 0.05s exceeded'.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01HNhpmz4QPYaVCE7tFna54D
@nikhilunni
nikhilunni merged commit 59d6249 into main Nov 10, 2026
28 checks passed
@nikhilunni
nikhilunni deleted the fix/peer-first-dial-waits-for-capture branch November 10, 2026 19:55
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.

1 participant