Skip to content

Retry LB sync while nodes are still cloud-provider initializing - #939

Open
pyadagiri-do wants to merge 4 commits into
masterfrom
CON-14209-retry-unready-nodes
Open

Retry LB sync while nodes are still cloud-provider initializing#939
pyadagiri-do wants to merge 4 commits into
masterfrom
CON-14209-retry-unready-nodes

Conversation

@pyadagiri-do

@pyadagiri-do pyadagiri-do commented Aug 4, 2026

Copy link
Copy Markdown

Summary

  • Fix CON-14209 / ESC-23605 race
  • When some EXTERNAL REGIONAL_NETWORK backends are still cloud-provider-initializing, update the LB with currently lb-ready nodes, then return api.RetryError so upstream retries for the rest.
  • Bound retries with init grace periods and a backoff cadence so stuck/private-only nodes do not keep the loop alive forever.
  • Preserve api.RetryError through service annotation patching so upstream does not fall back to exponential backoff.

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

This PR addresses a race where nodes still marked as cloud-provider-uninitialized (and therefore missing required public addressing) could cause partial backend updates for REGIONAL_NETWORK EXTERNAL load balancers, potentially preventing later convergence when node addresses appear. It does so by returning api.RetryError in that scenario and ensuring the retry error is preserved through error wrapping, with unit tests covering transient vs permanent “private-only” cases.

Changes:

  • Return api.RetryError (with a short retry delay) when filtered publicNetUnready nodes are still cloud-provider-uninitialized, avoiding partial backend updates.
  • Wrap buildLoadBalancerRequest errors using %w so upstream can detect RetryError via errors.As.
  • Extend unit tests to assert retry behavior and distinguish transient initialization races from permanently ineligible nodes.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.

File Description
cloud-controller-manager/do/loadbalancers.go Adds initialization-aware retry behavior for node filtering and preserves retry semantics via %w error wrapping.
cloud-controller-manager/do/loadbalancers_test.go Adds helpers and test coverage to verify RetryError behavior and retry delay for initialization vs permanent filtering cases.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines 624 to +628
if classification == nodeClassPublicNetUnready {
klog.V(4).Infof("Node %s filtered: no external IP addresses (required for REGIONAL_NETWORK EXTERNAL load balancer)", node.Name)
state.filteredCount++
state.publicNetUnreadyCount++
state.publicNetUnreadyNodes = append(state.publicNetUnreadyNodes, node)

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

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

Suppressed comments (1)

cloud-controller-manager/do/loadbalancers_test.go:7416

  • These assertions only exercise buildLoadBalancerRequest directly, so they do not verify the behavior this PR depends on: RetryError surviving the new wrappers in EnsureLoadBalancer and UpdateLoadBalancer. A regression back to %s in either public path would leave these tests green while upstream resumes exponential backoff. Add public-method cases with an initializing private-only node and assert errors.As(err, &retryErr) (and the retry delay) for both paths.
			var retryErr *api.RetryError
			gotRetry := errors.As(err, &retryErr)

@skumarc-do

Copy link
Copy Markdown

The guard treats 'taint present + no ExternalIP' as "still initializing, address is coming." That makes sense for the race in ESC-23605. But what happens if a node ends up stuck with the taint indefinitely?

@skumarc-do
skumarc-do self-requested a review August 11, 2026 15:19

@skumarc-do skumarc-do 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.

What happens if we are scaling the nodes and one of the node is stuck / in the retry phase, will the other nodes get processed successfully?

@pyadagiri-do

Copy link
Copy Markdown
Author

The guard treats 'taint present + no ExternalIP' as "still initializing, address is coming." That makes sense for the race in ESC-23605. But what happens if a node ends up stuck with the taint indefinitely?

Yup, if a node is stuck with the taint, we will keep retrying. So anyway as the node is in broken, so should be fine I guess ?

@pyadagiri-do

Copy link
Copy Markdown
Author

What happens if we are scaling the nodes and one of the node is stuck / in the retry phase, will the other nodes get processed successfully?

Good catch. brought it up on the related thread for discussion
https://digitalocean.slack.com/archives/C02GCCTT8JV/p1786462365654339?thread_ts=1781772662.068499&cid=C02GCCTT8JV

@pyadagiri-do

Copy link
Copy Markdown
Author

What happens if we are scaling the nodes and one of the node is stuck / in the retry phase, will the other nodes get processed successfully?

Good catch. brought it up on the related thread for discussion https://digitalocean.slack.com/archives/C02GCCTT8JV/p1786462365654339?thread_ts=1781772662.068499&cid=C02GCCTT8JV

updated the approach now. to call updateLB with ready nodes. And later if there return retry error if there are nodes initializing or stuck. This should unblock the other nodes processing

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.

3 participants