Skip to content

PUT /api/exports: a create survives its client; an attached export with no device gets one - #135

Merged
jaredLunde merged 2 commits into
mainfrom
jared/export-attach-heal
Nov 11, 2026
Merged

jaredLunde merged 2 commits into
mainfrom
jared/export-attach-heal

Conversation

@jaredLunde

Copy link
Copy Markdown
Contributor

AWS run 39 on a beyond node: instd was SIGTERMed with two volume PUTs in flight. hyper dropped the handler between create_export and register_device (create_or_attach_volume), so each export stayed in the map with no block device and register_device never ran. Every re-PUT then hit the already-attached branch, which returned the export with device null (it registered a device only after a resize). instd read that as "ublk capacity exhausted" and retried the same call for ever.

  • The create body runs in tokio::spawn, so a dropped request cannot cancel it.
  • The already-attached branch registers a device when there is none (Linux only), so the retry heals a process killed mid-create. A failed registration is a 500 naming the missing device.
  • ARCHITECTURE.md PUT row updated.

Tests (tests/integration/attach_heal.rs), both fail on main and pass here:

  • a PUT dropped while export.json is being written (slow index store, handler polled then dropped) still completes: export.json reaches S3.
  • a PUT of an attached export with no device never answers 200 with device null.

cargo test -p glidefs --features test-utils --lib --test integration: 556 lib and 247 integration pass, 5 ignored as before.

Companion: beyondoss/beyond#1484 (instd re-sends once and names the error; claim V4.attach-heals-device, which fails on the current GlideFS). Needs a release (v0.9.19) before nodes get it; that is not part of this PR.

🤖 Generated with Claude Code

https://claude.ai/code/session_01WpMBiw38GkJFe49jfZowsH

jaredLunde and others added 2 commits November 11, 2026 03:07
…th no device gets one

AWS run 39: a client (instd) was killed with volume PUTs in flight. hyper dropped
the handler between create_export and register_device, leaving each export in the
map with no device. Every re-PUT hit the already-attached branch, which returned
the export with device null (it registered a device only after a resize), so the
volume could never be attached again.

- The create body runs in a spawned task, so a dropped request cannot cancel it.
- The already-attached branch registers a device when there is none (Linux),
  and answers 500 naming the missing device if that fails.
- Tests (fail on the old code): a PUT dropped while export.json is being written
  still completes; a PUT of an attached export with no device never answers 200
  with device null.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WpMBiw38GkJFe49jfZowsH
…r create-cut-off and resize

An NBD export is also served over TCP, so a missing /dev/nbdN is not a failure (create
already tolerates it). The heal in the already-attached branch now follows the same rule and
answers like the create path (device_error_response). Tests behind the ublk feature: a PUT of
a device-less ublk export, and a resize of one, never answer 200 with device null.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01WpMBiw38GkJFe49jfZowsH
@jaredLunde
jaredLunde merged commit c2a653b into main Nov 11, 2026
25 checks passed
@jaredLunde
jaredLunde deleted the jared/export-attach-heal branch November 11, 2026 12:05
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