Skip to content

[SFAM-2764] Fix node-migration deadlock in StorageNodeSet action flow#295

Merged
noctarius merged 1 commit into
mainfrom
SFAM-2764
Jul 13, 2026
Merged

[SFAM-2764] Fix node-migration deadlock in StorageNodeSet action flow#295
noctarius merged 1 commit into
mainfrom
SFAM-2764

Conversation

@noctarius

Copy link
Copy Markdown
Collaborator

During a restart/migration (spec.action=restart with a target workerNode) two operator bugs combined to leave the node stuck in in_restart.

Defect A — spdk-proxy DNS never published during actions: Reconcile early-returns into reconcileAction when spec.action is set, which skipped reconcileSpdkProxyEndpointSlices for the whole action. The target worker's spdk-proxy pod came up but its headless-service DNS entry was never written, so the control plane's iobuf_set_options RPC failed with NameResolutionError until it gave up. The pod-driven slice reconciliation now also runs on the action path, so the entry is published as soon as the new spdk-proxy pod becomes Ready.

Defect B — restart retry storm resets node state:
performNodeAction re-POSTed the restart on every reconcile, and handleNodeAction only short-circuited on a prior success. While a migration was in flight the node reads in_restart (longer than the ~4min completion budget), so each requeue re-fired /restart, reset online->in_restart, and spawned a duplicate task the runner aborted ("node is restarting, stopping task"). Add an idempotency guard that reads the backend node status first and skips the trigger when the action is already in progress (polls instead) or already complete, wiring up the previously-unused ActionStatus.Triggered/ObservedGeneration fields. Mirrors the existing pattern in nodedrain_controller.

Repeated reconciles during a long migration are now benign polling: no state resets, no duplicate tasks. The added status GET is one cheap read per action reconcile and replaces the repeated restart POSTs, so overall API traffic drops.

Adds regression tests for both fixes.

@noctarius noctarius self-assigned this Jul 1, 2026
Copilot AI review requested due to automatic review settings July 1, 2026 11:38

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Fixes a restart/migration deadlock in the StorageNodeSet action reconcile path by ensuring spdk-proxy EndpointSlice/DNS publication continues during actions and by making backend node actions idempotent across requeues.

Changes:

  • Reconcile spdk-proxy EndpointSlice objects even when spec.action is set (action early-return path).
  • Add an idempotency guard for long-running backend node actions using a pre-read of backend node status plus persisted ActionStatus fields (Triggered, ObservedGeneration).
  • Add regression unit tests covering both the EndpointSlice publication during actions and idempotent action triggering.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 3 comments.

File Description
internal/controller/simplyblockstoragenodeset_controller.go Runs spdk-proxy EndpointSlice reconciliation during actions; adds idempotency guard + helper funcs; wires ActionStatus.Triggered/ObservedGeneration.
internal/controller/simplyblockstoragenodeset_controller_unit_test.go Adds regression tests for EndpointSlice publication during action flow and for idempotent action triggering.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/controller/simplyblockstoragenodeset_controller.go
Comment thread internal/controller/simplyblockstoragenodeset_controller.go
@noctarius noctarius changed the title Fix node-migration deadlock in StorageNodeSet action flow [SFAM-2764] Fix node-migration deadlock in StorageNodeSet action flow Jul 2, 2026
During a restart/migration (spec.action=restart with a target workerNode)
two operator bugs combined to leave the node stuck in in_restart.

Defect A — spdk-proxy DNS never published during actions:
Reconcile early-returns into reconcileAction when spec.action is set, which
skipped reconcileSpdkProxyEndpointSlices for the whole action. The target
worker's spdk-proxy pod came up but its headless-service DNS entry was never
written, so the control plane's iobuf_set_options RPC failed with
NameResolutionError until it gave up. The pod-driven slice reconciliation now
also runs on the action path, so the entry is published as soon as the new
spdk-proxy pod becomes Ready.

Defect B — restart retry storm resets node state:
performNodeAction re-POSTed the restart on every reconcile, and handleNodeAction
only short-circuited on a prior success. While a migration was in flight the
node reads in_restart (longer than the ~4min completion budget), so each requeue
re-fired /restart, reset online->in_restart, and spawned a duplicate task the
runner aborted ("node is restarting, stopping task"). Add an idempotency guard
that reads the backend node status first and skips the trigger when the action
is already in progress (polls instead) or already complete, wiring up the
previously-unused ActionStatus.Triggered/ObservedGeneration fields. Mirrors the
existing pattern in nodedrain_controller.

Repeated reconciles during a long migration are now benign polling: no state
resets, no duplicate tasks. The added status GET is one cheap read per action
reconcile and replaces the repeated restart POSTs, so overall API traffic drops.

Adds regression tests for both fixes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@noctarius noctarius merged commit 2b4e8a9 into main Jul 13, 2026
5 checks passed
@noctarius noctarius deleted the SFAM-2764 branch July 13, 2026 09:53
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.

2 participants