Skip to content

fix: confirm Envoy Service via uncached read before clearing Gateway address#9568

Open
sealab2066 wants to merge 3 commits into
envoyproxy:mainfrom
sealab2066:fix/gateway-address-transient-empty-list
Open

fix: confirm Envoy Service via uncached read before clearing Gateway address#9568
sealab2066 wants to merge 3 commits into
envoyproxy:mainfrom
sealab2066:fix/gateway-address-transient-empty-list

Conversation

@sealab2066

Copy link
Copy Markdown

What this PR does / why we need it:

Fixes #9567.

A Gateway backed by a LoadBalancer Service can get permanently stuck at Programmed=False / AddressNotAssigned, with its status.addresses cleared, after a transient empty result from the cached client — even though the backing Service has a valid IP and the data plane keeps routing.

updateStatusForGatewayenvoyServiceForGateway does a cached List. When that list transiently returns 0 items (an informer cache that has not yet observed the Service, or a relist window), the caller receives svc == nil, and UpdateGatewayStatusProgrammedCondition takes the else { gw.Status.Addresses = nil } branch, producing AddressNotAssigned. There is no distinction between "the Service is genuinely absent" and "the cache momentarily returned nothing", and no periodic status resync — so once latched, the Gateway does not self-recover (only a controller restart or a forced Service MODIFIED event fixes it).

This confirms with an uncached read (mgr.GetAPIReader()) before concluding the Service is gone, so a transient cache miss no longer wipes the Gateway address.

See #9567 for the full analysis: the trigger is a periodic (every ~10 min) cloud LB re-ensure that touches every Service, the recovery paths (rollout restart / kubectl annotate svc), and why the already-merged fixes #8962 (#8953) and #9100 (#9094) do not cover this path.

Release Notes: Yes (release-notes/current/bug_fixes/9567-gateway-address-transient-empty-service-list.md).

…address

A transient empty result from the cached client in envoyServiceForGateway (an
informer cache that has not yet observed the Service, or a relist window) was
treated as "the Service no longer exists". UpdateGatewayStatusProgrammedCondition
then wiped gw.Status.Addresses and set Programmed=False/AddressNotAssigned, and
the Gateway did not self-recover. Confirm with an uncached read (GetAPIReader)
before concluding the Service is gone.

Refs envoyproxy#9567

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Sergei Cherevko <scherevko@scorewarrior.com>
@sealab2066
sealab2066 requested a review from a team as a code owner July 23, 2026 09:57
@netlify

netlify Bot commented Jul 23, 2026

Copy link
Copy Markdown

Deploy Preview for cerulean-figolla-1f9435 ready!

Name Link
🔨 Latest commit e06a62d
🔍 Latest deploy log https://app.netlify.com/projects/cerulean-figolla-1f9435/deploys/6a62050507c9ba0008775db6
😎 Deploy Preview https://deploy-preview-9568--cerulean-figolla-1f9435.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e1475f0e77

ℹ️ About Codex in GitHub

Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".

if kerrors.IsNotFound(err) {
return nil, nil
}
return nil, err

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Preserve addresses when live confirmation errors

When the cached list is empty but the uncached API read fails, such as an apiserver timeout or 429 while the informer is stale, this returns (nil, err). updateStatusForGateway only logs that error and still calls UpdateGatewayStatusProgrammedCondition with svc == nil (status.go lines 749-762), which clears Gateway.status.addresses and marks AddressNotAssigned; that is exactly the unconfirmed-cache-miss case this fallback is meant to avoid. Treat the failed confirmation as “do not update addresses yet” or make the caller skip the programmed update on service lookup errors.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

Good catch — fixed in 6c6380b. updateStatusForGateway now skips UpdateGatewayStatusProgrammedCondition when the Service lookup returns an error, so a failed uncached confirmation (apiserver timeout/429 with a stale informer) no longer clears the addresses. Added a test covering the propagated-error case.

Address review feedback: when the cached list is empty and the uncached
confirmation read itself fails (apiserver timeout/429 while the informer is
stale), envoyServiceForGateway returns (nil, err). updateStatusForGateway now
skips UpdateGatewayStatusProgrammedCondition on that error instead of clearing
gw.Status.Addresses / setting AddressNotAssigned from an inconclusive read.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Signed-off-by: Sergei Cherevko <scherevko@scorewarrior.com>
@sealab2066

Copy link
Copy Markdown
Author

Related to #9509 (fixes #9432) — same family (stale informer cache in the Gateway status path, both fixed with an uncached read), but a different code path, so the two are complementary rather than duplicates:

Neither supersedes the other; merging both closes the two distinct Programmed=False failure modes (AddressNotAssigned vs NoResources).

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.

Gateway stuck at Programmed=False / AddressNotAssigned on v1.8.1 after transient LoadBalancer IP loss; does not self-recover

1 participant