Skip to content

SK-3253:Add gated retry on 401 status code for flowvault SDK. - #449

Merged
yaswanth-pula-skyflow merged 4 commits into
flowvault-release/26.10.28from
SK-3253/fix-inflight-bearer-401-retry
Oct 28, 2026
Merged

yaswanth-pula-skyflow merged 4 commits into
flowvault-release/26.10.28from
SK-3253/fix-inflight-bearer-401-retry

Conversation

@yaswanth-pula-skyflow

Copy link
Copy Markdown
Collaborator

SK-3253: Retry once on 401 when the bearer token expired mid-call

Ticket: SK-3253 (customer case CUST-4591)

Problem

Every vault method checks the bearer token once, at its start, with now > exp. The token is then used for every HTTP request that method sends. If it expires while a request is in flight, or between the check and a later request of the same method, the gateway answers 401 and the SDK returns that as the result. Nothing regenerates the token until the next method call.

In flowvault a bulk method splits records into batches and sends each batch as its own request under that one check. A customer's bulk tokenize of 2,000 records started a few seconds before expiry, passed the check, and lost every batch after exp as per-record httpCode=401 errors.

Fix

When a request fails with 401 and the SDK can see from its own copy of the token that the token is at or past expiry, the SDK generates a new token once and resends that request once.

  • Trigger is 401 only. Any other status is returned as today.
  • Only for credentials the SDK can mint from: service-account file, credentials string, environment credentials. A static token (setToken) or an API key returns the 401 unchanged.
  • Only when the sent token's exp is within 60 seconds of now. A 401 on a token with more life than that is not expiry and is returned unchanged, with no token generated.
  • One regeneration and one resend per request. The response to the resend is returned whatever it is.
  • Single-flight. Regeneration is serialised with the existing token check. A request that finds the cache already holds a different token reuses it, so concurrent 401s on one token cost one generation.
  • If generation fails, or returns the token that was just rejected, the original 401 is returned.

Later requests in the same method read the refreshed token from the cache, so a bulk call that crosses expiry now completes in full. No new configuration. The start-of-method check is unchanged.

Changes

common

  • BaseVaultClient: the auth interceptor used by every OkHttp client now handles the 401 branch. New refreshBearerTokenAfterUnauthorized implements the rules above, synchronized with setBearerToken. Token reads go through a synchronized getToken() so a token refreshed on one thread is seen by the others.
  • Token.isExpiringWithin(token, windowSeconds): public, additive. isExpired is unchanged.
  • New InfoLogs / WarningLogs entries for the refresh path. No new logging on the happy path.

flowvault

  • VaultClient: uses the shared auth interceptor from common. The transport retry interceptor stays outside it, so configured 408/429/5xx retries and the call timeout still bound the whole exchange.

skyvault

  • VaultClient: token supplier switched to getToken(). Vault and detect calls get the retry through the shared interceptor.
  • Connections are intentionally unchanged. A connection 401 can come from the proxied third party, and a resend there is not guaranteed to be side-effect free.

Not covered, by design

setToken tokens, API keys, any 401 on a token that is not near expiry, a connection call that straddles expiry. All behave exactly as today.

Tests

  • common: BaseVaultClientTests (interceptor branches, gate, single-flight, same-token-back, failure), TokenTests (isExpiringWithin boundaries, malformed and missing exp).
  • flowvault: AuthInterceptorTests (retry ordering, resend once, static token and API key untouched).
  • All three module suites pass. flowvault japicmp against the baseline passes; the only public API change is the new Token.isExpiringWithin.

@yaswanth-pula-skyflow
yaswanth-pula-skyflow requested a balanced review from Copilot October 26, 2026 15:08
@github-actions

Copy link
Copy Markdown

✅ Gitleaks Findings: No secrets detected. Safe to proceed!

@github-actions

Copy link
Copy Markdown

Semgrep Findings: Issues with Error level severity are found (Error is Highest severity in Semgrep), Please resolve the issues before merging.

@codecov

codecov Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 91.25%. Comparing base (eecd06a) to head (d82f4f1).
⚠️ Report is 2 commits behind head on flowvault-release/26.10.28.

Additional details and impacted files
@@                       Coverage Diff                        @@
##             flowvault-release/26.10.28     #449      +/-   ##
================================================================
+ Coverage                         90.99%   91.25%   +0.26%     
- Complexity                            0      570     +570     
================================================================
  Files                               174      174              
  Lines                              7350     7399      +49     
  Branches                           1013     1022       +9     
================================================================
+ Hits                               6688     6752      +64     
+ Misses                              437      424      -13     
+ Partials                            225      223       -2     
Flag Coverage Δ
common 90.80% <100.00%> (+1.65%) ⬆️
flowvault 87.92% <100.00%> (-0.02%) ⬇️
skyvault 94.88% <100.00%> (-0.07%) ⬇️
unittests-flowvault 90.41% <100.00%> (?)

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
Module: common 90.80% <100.00%> (+1.65%) ⬆️
Module: skyvault 94.88% <100.00%> (-0.07%) ⬇️
Module: flowvault 87.92% <100.00%> (-0.02%) ⬇️
Service Account 87.76% <100.00%> (+0.39%) ⬆️
Vault Data 90.81% <ø> (ø)
Vault Tokens 99.03% <ø> (ø)
Vault Connection 100.00% <ø> (ø)
Vault Controller 82.75% <ø> (ø)
Detect 100.00% <ø> (ø)
Audit 100.00% <ø> (ø)
BIN Lookup 100.00% <ø> (ø)
Config 96.26% <ø> (ø)
Utils 90.41% <ø> (+0.04%) ⬆️
Errors 100.00% <ø> (ø)
Enums 100.00% <ø> (ø)
Logs 100.00% <100.00%> (+4.39%) ⬆️
Files with missing lines Coverage Δ
...mon/src/main/java/com/skyflow/BaseVaultClient.java 92.22% <100.00%> (+5.68%) ⬆️
...ommon/src/main/java/com/skyflow/logs/InfoLogs.java 100.00% <100.00%> (ø)
...on/src/main/java/com/skyflow/logs/WarningLogs.java 100.00% <100.00%> (+100.00%) ⬆️
...in/java/com/skyflow/serviceaccount/util/Token.java 96.96% <100.00%> (+1.13%) ⬆️
...owvault/src/main/java/com/skyflow/VaultClient.java 97.26% <100.00%> (-0.15%) ⬇️
...kyvault/src/main/java/com/skyflow/VaultClient.java 97.80% <100.00%> (+0.19%) ⬆️

... and 2 files with indirect coverage changes


Continue to review full report in Codecov by Harness.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update eecd06a...d82f4f1. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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.

🟡 Changes recommended

Refresh operations can exceed the originating call’s timeout, and concurrent requests do not share unsuccessful refresh outcomes.

2 open issues
What changed in this PR

Adds expiry-gated bearer-token refresh and a single resend after a 401 in the shared authentication layer used by flowvault and skyvault.

Changes:

  • Adds a 60-second expiry gate, synchronized token access, and refresh-path logging.
  • Wires both vault clients to shared retry handling while leaving connection calls unchanged.
  • Adds tests for refresh eligibility, resend limits, concurrency, and interceptor ordering.
File Description
skyvault/​src/​main/​java/​com/​skyflow/​VaultClient.java Uses synchronized token reads for shared HTTP authentication.
flowvault/​src/​test/​java/​com/​skyflow/​utils/​FakeChain.java Exposes response-body closure for assertions.
flowvault/​src/​test/​java/​com/​skyflow/​AuthInterceptorTests.java Tests refresh behavior and interceptor ordering.
flowvault/​src/​main/​java/​com/​skyflow/​VaultClient.java Installs shared authentication inside transport retries.
common/​src/​test/​java/​com/​skyflow/​serviceaccount/​util/​TokenTests.java Tests expiry-window checks and malformed tokens.
common/​src/​test/​java/​com/​skyflow/​BaseVaultClientTests.java Tests refresh gating, caching, concurrency, and resend limits.
common/​src/​main/​java/​com/​skyflow/​serviceaccount/​util/​Token.java Adds isExpiringWithin.
common/​src/​main/​java/​com/​skyflow/​logs/​WarningLogs.java Adds refresh-failure warnings.
common/​src/​main/​java/​com/​skyflow/​logs/​InfoLogs.java Adds refresh-decision messages.
common/​src/​main/​java/​com/​skyflow/​BaseVaultClient.java Implements shared refresh-and-resend handling.

Review effort: Balanced

@promptless

promptless Bot commented Oct 26, 2026 •

Copy link
Copy Markdown

Promptless documentation updates

@github-actions

Copy link
Copy Markdown

✅ Gitleaks Findings: No secrets detected. Safe to proceed!

@github-actions

Copy link
Copy Markdown

Semgrep Findings: Issues with Error level severity are found (Error is Highest severity in Semgrep), Please resolve the issues before merging.

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.

🟢 Approval recommended

Static review found no unresolved blocking issues in the retry gates, credential exclusions, or concurrent refresh handling; test suites were not independently executed.

No open issues 🎉

2 resolved since last review

Review effort: Balanced

@github-actions

Copy link
Copy Markdown

✅ Gitleaks Findings: No secrets detected. Safe to proceed!

@github-actions

Copy link
Copy Markdown

Semgrep Findings: Issues with Error level severity are found (Error is Highest severity in Semgrep), Please resolve the issues before merging.

@yaswanth-pula-skyflow
yaswanth-pula-skyflow changed the base branch from main to flowvault-release/26.10.28 October 28, 2026 04:06
@yaswanth-pula-skyflow yaswanth-pula-skyflow changed the title SK-3253:Add gated retry on 401 status code for both skyvault & flowvault SDKs. SK-3253:Add gated retry on 401 status code for flowvault SDK. Oct 28, 2026
@yaswanth-pula-skyflow
yaswanth-pula-skyflow merged commit 23391b0 into flowvault-release/26.10.28 Oct 28, 2026
30 of 31 checks passed
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