Skip to content

SK-3133: Use the generated RetryInterceptor + fix logging/dotenv latency bottlenecks - #424

Open
Devesh-Skyflow wants to merge 3 commits into
mainfrom
devesh/sk-3133
Open

SK-3133: Use the generated RetryInterceptor + fix logging/dotenv latency bottlenecks#424
Devesh-Skyflow wants to merge 3 commits into
mainfrom
devesh/sk-3133

Conversation

@Devesh-Skyflow

Copy link
Copy Markdown
Collaborator

Why

com.skyflow.generated.rest.core.RetryInterceptor (Fern-generated) now has a 4-arg constructor supporting configurable initialRetryDelayMillis/maxRetryDelayMillis/jitterFactor, and scopes its backoff counter per call rather than per interceptor instance. Those were exactly the two gaps SkyflowRetryInterceptor was hand-written to work around (see its removed javadoc). With the gaps closed, maintaining a parallel hand-written implementation is redundant, and the generated one is strictly more capable - it also honors Retry-After / X-RateLimit-Reset response headers, which the hand-written version never did.

What changed

  • flowvault/.../generated/rest/core/RetryInterceptor.java updated to the version Fern would produce today (matches the unmerged saileshwar/update-flowvault-generated-code branch and the old v3 module's post-SK-3002 version) - configurable delays, header-aware backoff, per-request maxRetries override via request tag.
  • VaultClient now constructs the generated interceptor instead of SkyflowRetryInterceptor, passing the resolved maxRetries/initialRetryDelayMillis/maxRetryDelayMillis. Jitter is hardcoded for now: a RETRY_JITTER_FACTOR = 0.2 constant on VaultClient is passed explicitly as Optional.of(RETRY_JITTER_FACTOR) rather than relying on RetryInterceptor's own internal default - that keeps the hardcode visible and owned in our code instead of implicitly inherited from generated code we don't maintain (and which is free to change on a future regeneration). Not yet exposed as a VaultConfig/builder setting.
  • The generated interceptor doesn't validate maxRetries itself (a negative value would silently behave as zero retries instead of failing), so VaultClient now guards that explicitly to preserve the existing "negative maxRetriesSkyflowException" contract.
  • Deleted SkyflowRetryInterceptor + its unit tests (254 lines). That logic now lives only in the generated class, which is excluded from coverage/javadoc like the rest of com.skyflow.generated.*.
  • Updated HttpConfigTests/AuthInterceptorTests for the new type. The generated interceptor exposes no getters, so tests that need to read back what it was constructed with do it via reflection rather than adding hand-written accessors to a file meant to stay a faithful Fern output.

Testing

Full flowvault module test suite: 710/710 passing, BUILD SUCCESS (mvn -pl flowvault -am test).

Tech debt

Jitter is still not configurable per-vault/client-wide - a natural following change would add jitterFactor to VaultConfig/Skyflow.builder() and thread it through, but that's deliberately out of scope here per the ask ("set jitter as hardcoded for now").

Also in this PR: two more latency fixes from a round-trip SDK audit

Found while tracing the request path for an unrelated customer-latency investigation; folded in here since they're the same class of fix (blocking work hidden on the hot path) and this branch was already open.

  • Async console logging. LogUtil's ConsoleHandler wrote and flushed to the console synchronously, under a lock shared by every calling thread. printInfoLog/etc. fire several times per request, so enabling INFO/DEBUG logging turned console output into a per-request blocking-I/O + contention point. A new AsyncConsoleHandler now hands each LogRecord to a single background daemon thread via a bounded, non-blocking queue. Applied to both the common/flowvault LogUtil and skyvault's separate copy.
  • Memoized .env lookups. VaultController.resolveSettingFromEnvironment fell back to Dotenv.load() (an uncached filesystem read) twice per bulk call whenever the batch-size/concurrency-limit env vars weren't set - i.e. on every single insert/detokenize/tokenize/deleteTokens call. The same pattern existed in BaseVaultClient/ConnectionClient's credential fallback and Utils.getEnvVaultUrl. BaseUtils.resolveEnvOrDotenv now loads .env at most once per JVM (a project's .env doesn't change while the process runs), with a resetDotenvCacheForTests() escape hatch for the tests that intentionally rewrite .env mid-run.

Testing: full common + skyvault + flowvault suites, 1450/1450 passing (165+575+710), BUILD SUCCESS.

🤖 Generated with Claude Code

Devesh-Skyflow and others added 2 commits September 8, 2026 11:34
The generated com.skyflow.generated.rest.core.RetryInterceptor now
supports everything the hand-written SkyflowRetryInterceptor existed
to work around: a configurable initial/max retry delay via its 4-arg
constructor, and a per-call (not per-instance) backoff counter, so a
shared OkHttpClient no longer exhausts its retry budget once for its
whole lifetime. It also picks up Retry-After / X-RateLimit-Reset
header handling for free.

- VaultClient now constructs the generated RetryInterceptor, passing
  the resolved maxRetries/initialRetryDelayMillis/maxRetryDelayMillis.
  Jitter is left at the generated interceptor's own default (0.2) -
  not yet exposed as a VaultConfig/builder setting.
- The generated interceptor doesn't validate maxRetries itself (a
  negative value would silently behave as zero retries), so
  VaultClient now guards that explicitly to preserve the existing
  "negative maxRetries -> SkyflowException" contract.
- Deleted SkyflowRetryInterceptor and its unit tests; that logic now
  lives only in the generated class (excluded from coverage/javadoc
  like the rest of com.skyflow.generated.*).
- Updated HttpConfigTests/AuthInterceptorTests to the new type. The
  generated interceptor exposes no getters, so tests that need to
  read back what it was constructed with do it via reflection rather
  than adding hand-written accessors to generated code.

All 710 flowvault tests pass.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…ryInterceptor's default

RetryInterceptor is generated code we don't maintain, so its internal
DEFAULT_JITTER_FACTOR is free to change on a future regeneration.
Passing Optional.of(RETRY_JITTER_FACTOR) from VaultClient keeps the
0.2 hardcode visible and owned in our own code instead of implicitly
inherited by passing Optional.empty().

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@Devesh-Skyflow

Devesh-Skyflow commented Sep 8, 2026

Copy link
Copy Markdown
Collaborator Author

Supersedes #423 (same commits, moved to devesh/sk-3133 so there's one branch/one PR). Tracked by SK-3133.

@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown

Gitleaks Findings: No secrets detected. Safe to proceed!

@github-actions

github-actions Bot commented Sep 8, 2026

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.

…t path

Both were found during a round-trip latency audit of the SDK's request path
(same audit that flagged the retry-interceptor duplication this branch fixes).

- LogUtil's ConsoleHandler writes and flushes to the console synchronously,
  under a lock shared by every calling thread. LogUtil.printInfoLog/etc. fire
  several times per request (setBearerToken reuse/expiry, request validation,
  per-batch triggers, request-resolved), so enabling INFO/DEBUG logging turned
  console output into a per-request blocking-I/O + contention point. A new
  AsyncConsoleHandler now hands each LogRecord to a single background daemon
  thread via a bounded, non-blocking queue; the calling thread only enqueues.
  Applied to both the common/flowvault LogUtil and skyvault's separate copy.

- Several settings/credentials lookups fell back to Dotenv.load() when an env
  var wasn't set: VaultController.resolveSettingFromEnvironment did this twice
  per bulk call (batch size + concurrency limit), unconditionally, on every
  single insert/detokenize/tokenize/deleteTokens call -- Dotenv.load() re-reads
  the .env file from disk every time it's invoked, so this was uncached,
  blocking disk I/O on the hot path. The same pattern existed in
  BaseVaultClient/ConnectionClient's credential fallback and
  Utils.getEnvVaultUrl. BaseUtils.resolveEnvOrDotenv now memoizes the loaded
  (or absent) .env for the life of the JVM -- a project's .env doesn't change
  while the process runs, so there's no reason to keep re-reading it -- with a
  resetDotenvCacheForTests() escape hatch for the handful of tests that
  intentionally rewrite .env mid-run to exercise both branches.

Testing: full common + skyvault + flowvault suites, 1450/1450 passing
(165+575+710), BUILD SUCCESS.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Sep 8, 2026

Copy link
Copy Markdown

Gitleaks Findings: No secrets detected. Safe to proceed!

@github-actions

github-actions Bot commented Sep 8, 2026

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 Sep 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 85.26316% with 14 lines in your changes missing coverage. Please review.
✅ Project coverage is 91.89%. Comparing base (d0dea2f) to head (82d0cc7).

Files with missing lines Patch % Lines
...mon/src/main/java/com/skyflow/utils/BaseUtils.java 73.91% 2 Missing and 4 partials ⚠️
.../com/skyflow/utils/logger/AsyncConsoleHandler.java 87.09% 3 Missing and 1 partial ⚠️
.../com/skyflow/utils/logger/AsyncConsoleHandler.java 87.09% 3 Missing and 1 partial ⚠️
Additional details and impacted files
@@             Coverage Diff              @@
##               main     #424      +/-   ##
============================================
- Coverage     91.99%   91.89%   -0.11%     
- Complexity        0      493     +493     
============================================
  Files           158      159       +1     
  Lines          6631     6671      +40     
  Branches        893      890       -3     
============================================
+ Hits           6100     6130      +30     
- Misses          351      358       +7     
- Partials        180      183       +3     
Flag Coverage Δ
common 88.19% <82.14%> (-0.23%) ⬇️
flowvault 90.21% <100.00%> (-0.05%) ⬇️
skyvault 94.86% <87.87%> (-0.09%) ⬇️
unittests-flowvault 90.20% <75.00%> (?)

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

Components Coverage Δ
Module: common 88.19% <82.14%> (-0.23%) ⬇️
Module: skyvault 94.86% <87.87%> (-0.09%) ⬇️
Module: flowvault 90.21% <100.00%> (-0.05%) ⬇️
Service Account 87.36% <ø> (ø)
Vault Data 92.62% <ø> (ø)
Vault Tokens 99.03% <ø> (ø)
Vault Connection 100.00% <ø> (ø)
Vault Controller 85.47% <100.00%> (+0.11%) ⬆️
Detect 100.00% <ø> (ø)
Audit 100.00% <ø> (ø)
BIN Lookup 100.00% <ø> (ø)
Config 96.26% <ø> (ø)
Utils 90.34% <84.09%> (-0.45%) ⬇️
Errors 100.00% <ø> (ø)
Enums 100.00% <ø> (ø)
Logs 95.60% <ø> (ø)
Files with missing lines Coverage Δ
...mon/src/main/java/com/skyflow/BaseVaultClient.java 87.75% <100.00%> (+1.21%) ⬆️
...rc/main/java/com/skyflow/utils/logger/LogUtil.java 83.01% <100.00%> (ø)
...owvault/src/main/java/com/skyflow/VaultClient.java 97.53% <100.00%> (+0.09%) ⬆️
...owvault/src/main/java/com/skyflow/utils/Utils.java 92.78% <100.00%> (+0.15%) ⬆️
.../com/skyflow/vault/controller/VaultController.java 77.54% <100.00%> (+0.15%) ⬆️
...lt/src/main/java/com/skyflow/ConnectionClient.java 89.13% <100.00%> (-0.24%) ⬇️
...rc/main/java/com/skyflow/utils/logger/LogUtil.java 79.24% <100.00%> (ø)
.../com/skyflow/utils/logger/AsyncConsoleHandler.java 87.09% <87.09%> (ø)
.../com/skyflow/utils/logger/AsyncConsoleHandler.java 87.09% <87.09%> (ø)
...mon/src/main/java/com/skyflow/utils/BaseUtils.java 76.85% <73.91%> (-0.70%) ⬇️

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 d0dea2f...82d0cc7. Read the comment docs.

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

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.

1 participant