Repository navigation
branch-4.1: [fix](catalog) re-auth Iceberg REST catalog on 401 instead of wedging until FE restart - #70029
Merged
Conversation
… until FE restart (apache#64966) Problem Summary: An Iceberg REST catalog using oauth2 client credentials obtains its token when the catalog client is built and keeps it refreshed in the background. If a refresh permanently fails (for example the auth server is briefly unreachable or overloaded right when the refresh fires), the client is left holding a stale token, and every subsequent request fails with `NotAuthorizedException: Not authorized` (HTTP 401) — forever. The client has no re-authentication path of its own, and neither `REFRESH CATALOG` nor metadata-cache invalidation rebuilds it, so the catalog stays unusable until the FE process is restarted. We hit this in production against an Apache Polaris REST catalog. The failure mode is nasty to diagnose because the 401 is swallowed: `getDbNullable`/`buildDbForInit` report `Database [<db>] does not exist`, `SHOW DATABASES` returns a partial list, and since DDL statements (`CREATE VIEW`/`CREATE MTMV`/CTAS/`INSERT`) are `ForwardToMaster`, one wedged master FE breaks all DDL cluster-wide while plain SELECTs on follower FEs keep working. Only an FE restart recovered. Recovery now lives entirely at the REST layer (per review feedback — thanks @CalvinKirs): a new `ReauthenticatingRestSessionCatalog` (a `BaseViewSessionCatalog`) that `IcebergRestProperties` wraps around the `RESTSessionCatalog` it already builds and owns. On a 401 raised by a request made under the catalog's own identity, the wrapper rebuilds the delegate through the same build seam (fresh HTTP client, fresh OAuth2 token fetch), closes the wedged client, and retries the operation once. If the retry also fails, the error propagates unchanged. Design notes: - **REST-only.** Only `IcebergRestProperties` constructs the wrapper; no other catalog type sees this logic. `IcebergMetadataOps` is untouched apart from widening two declared types from `RESTSessionCatalog` to `BaseViewSessionCatalog`. - **All paths covered, no call-site changes, no stale references.** The default catalog (`asCatalog(empty)`), the view catalog (`asViewCatalog(empty)`), and per-user delegated sessions are all thin views that call back into the session catalog, so they inherit the recovery automatically — and because the swap happens below them, no holder of any of those references ever points at a dead client after recovery. - **Reads and mutations both retried.** A 401 is rejected by the server before the request is processed, so retrying after re-authentication cannot double-apply an operation. - **Per-user delegated sessions are excluded.** A 401 on a request carrying a delegated (per-user) credential means that user's token is invalid; rebuilding the shared client cannot fix it and must not be triggered by it. Likewise, when catalog initialization itself runs under a delegated credential (`iceberg.rest.session=user`), no wrapper is installed, so the rebuild path can never capture a user token into the shared client. - **Typed detection only.** `NotAuthorizedException` anywhere in the cause chain; no message-string matching. - **Bounded.** One rebuild + one retry per failed request; concurrent 401s coalesce into a single rebuild (a request that raced with a completed rebuild just retries on the fresh client). Boundary: recovery triggers on catalog-level operations. Objects already handed out (a loaded `Table`/`View`, a `buildTable`/`buildView` builder) keep the client they were created with; if the token expires between obtaining and using one, that single use can still 401, and the next catalog-level operation heals the client. - Iceberg REST catalogs recover automatically from an expired/rejected OAuth2 token (401) by re-authenticating and retrying once, instead of failing every request until the FE restarts. Other catalog types and non-401 failures are unaffected. Signed-off-by: Raghvendra Singh <[email protected]> Co-authored-by: Claude <[email protected]> (cherry picked from commit 3a75387) Backport to branch-4.1: retain the existing RESTCatalog facade for table, view, transaction and close operations. Wrap its session through the protected construction hook because delegated-session support is absent on this branch. No delegated-session feature is introduced. Validation: changed-file Checkstyle passes; nine focused recovery and RESTCatalog adapter tests pass against Iceberg 1.11.0.
Contributor
|
Thank you for your contribution to Apache Doris. Please clearly describe your PR:
|
Member
Author
|
run buildall |
yiguolei
approved these changes
Nov 4, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#64966