Skip to content

Commit a0f3fcb

Browse files
Devesh-Skyflowclaudeskyflow-bharti
authored
Release/26.7.15 (#361)
* SK-2955 align upsert/upsertType with Flow-DB changes (docs, tests, error-message cleanup) (#346) Flow-DB now defaults record-level upsert to UPDATE (was REPLACE) and owns upsert-placement validation server-side. The SDK already serializes upsertType correctly and omits updateType when unset, so this is docs, tests, and validation hygiene only. - README: document upsertType is optional, default is now UPDATE, and UPDATE vs REPLACE semantics. - Samples: drop redundant explicit upsertType(UPDATE) (now the default) in BulkMultiTableInsert{Sync,Async}; keep REPLACE samples as-is. - Validations: defer upsert-placement checks to the backend (authoritative messages); SDK only guards empty upsert columns. - Tests: cover default-UPDATE omission at request/record level, both-level serialization, and updated placement tests to reflect deferral. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * [AUTOMATED] Private Release 2.1.1-dev-ce79ce1 * SK-3002 retry backoff support (#367) * SK-3002 add SkyflowRetryInterceptor (configurable retry count + backoff) Hand-written OkHttp interceptor replicating Fern's retry algorithm (exponential backoff + proportional jitter, factor 0.2 fixed). Exposes maxRetries / initialRetryDelayMillis / maxRetryDelayMillis; retries on 408/429/5xx. Carries a TODO to replace with Fern's generated interceptor once a version exposing the delay knobs is vendored. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * SK-3002 expose configurable timeout + retries (client & vault level) - VaultConfig: vault-level timeout/maxRetries/initialRetryDelayMillis/ maxRetryDelayMillis (nullable = inherit) - Skyflow.SkyflowClientBuilder: flat client-wide setters + propagation to existing controllers (mirrors addSkyflowCredentials) - VaultClient.updateExecutorInHTTP: set callTimeout + attach SkyflowRetryInterceptor; per-field precedence vault > client > SDK default (defaults 60s / 3 / 500ms / 2000ms) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * SK-3002 tests for configurable timeout + retries - SkyflowRetryInterceptorTests: retry count, stop-on-success, 408/429/5xx triggers, non-retryable passthrough, zero-retries - VaultClientHttpConfigTests: callTimeout applied to shared client, precedence (vault > client > default), bounded-not-zero regression guard, VaultConfig field getters/setters Note: pre-existing VaultClientTests#testSetBearerTokenWithEnvCredentials fails on Java 21 (PowerMock byte-buddy cannot instrument JDK security classes) — reproduced on base v3, unrelated to this change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * SK-3002 add sample for configurable timeout + retries Demonstrates client-wide defaults on Skyflow.builder() and per-vault overrides on VaultConfig, with precedence and unit notes. Compiles against the local SDK build (samples module pins a released version, so it builds once this change ships). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * SK-3002 add MockWebServer integration test (live timeout + retry proof) Drives an OkHttpClient built like VaultClient (callTimeout + SkyflowRetry Interceptor) against a real loopback MockWebServer: - retries 503 then succeeds (server sees 1+retries requests) - exhausts retries, returns last failure - no retry on 400 - callTimeout aborts a never-responding server (~1s, not hanging) -- the fix - observable backoff between retries Adds com.squareup.okhttp3:mockwebserver as a test dependency. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * SK-3002 remove MockWebServer test (breaks CI on PowerMock + Java 21) MockWebServer's static init loads JDK security providers, which the PowerMock/byte-buddy agent fails to instrument on Java 21 (IllegalClassFormatException: Unsupported class file major version 65) -> ExceptionInInitializerError in setUp. This is the same agent/JDK incompatibility that already fails testSetBearerTokenWithEnvCredentials. Retry/timeout behavior remains covered by the mocked-Chain unit tests (SkyflowRetryInterceptorTests) and the config/precedence tests (VaultClientHttpConfigTests), both green in CI. Also drops the mockwebserver test dependency. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * SK-3002 raise coverage for new timeout/retry code Cover the previously-untested new code paths flagged by Codecov: - Skyflow.builder() setters + propagateHttpConfig loop (config set before and after addVaultConfig) -> SkyflowClientBuilderHttpConfigTests - resolveInt/resolveLong vault + client branches via maxRetries + backoff precedence, asserted on the built SkyflowRetryInterceptor's fields - interceptor InterruptedException-during-backoff path (throws IOException, preserves interrupt flag) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * SK-3002-retry-backoff-support * SK-3002 use Fern v4 generated RetryInterceptor; rename knobs to initialRetryDelay/maxRetryDelay - Swap hand-written SkyflowRetryInterceptor for Fern's v4 generated RetryInterceptor (public 4-arg ctor: maxRetries, Optional<Long> initial/max delay, Optional<Double> jitter); delete SkyflowRetryInterceptor + its unit test - Rename public knobs initialRetryDelayMillis/maxRetryDelayMillis -> initialRetryDelay/ maxRetryDelay (Fern naming); still long ms, client + vault levels only - VaultClient attaches the generated RetryInterceptor on the shared client, passing resolved values as Optional (jitter Optional.empty -> Fern default 0.2). Gains Retry-After / X-RateLimit-Reset header awareness for free - Update VaultClientHttpConfigTests to reflect Fern's Duration fields; rename sample Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * SK-3002 fix CI coverage: prepend @{argLine} so JaCoCo agent attaches The v4-regen added a static <argLine> (--add-opens ...) to maven-surefire-plugin, which overwrote the argLine JaCoCo's prepare-agent injects. The coverage agent therefore never attached -> no jacoco.exec -> "Skipping JaCoCo ... missing execution data" -> no jacoco.xml -> Codecov "No coverage reports found" (build green, 439 tests pass, but upload fails). Prepend @{argLine} (Surefire late-binding of JaCoCo's property) so both the coverage agent and the --add-opens flags apply. Verified locally: jacoco.exec and jacoco.xml are generated again. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * SK-3002 default maxRetries=0 (retries opt-in) to avoid retrying non-idempotent writes Retries fire on 408/429/5xx for all operations regardless of HTTP verb, so auto-retrying a non-idempotent write (e.g. insert without upsert) after a 5xx/timeout could create a duplicate record. Default maxRetries to 0 so the unconfigured SDK does not retry; customers opt in by setting maxRetries. The 60s callTimeout still bounds every call. initialRetryDelay/maxRetryDelay defaults only take effect once maxRetries > 0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Devesh-Skyflow <devesh.bhardwaj@skyflow.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * [AUTOMATED] Private Release 2.1.1-dev-1236334 * SK-3002 retry backoff support (#368) * SK-3002 add SkyflowRetryInterceptor (configurable retry count + backoff) Hand-written OkHttp interceptor replicating Fern's retry algorithm (exponential backoff + proportional jitter, factor 0.2 fixed). Exposes maxRetries / initialRetryDelayMillis / maxRetryDelayMillis; retries on 408/429/5xx. Carries a TODO to replace with Fern's generated interceptor once a version exposing the delay knobs is vendored. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * SK-3002 expose configurable timeout + retries (client & vault level) - VaultConfig: vault-level timeout/maxRetries/initialRetryDelayMillis/ maxRetryDelayMillis (nullable = inherit) - Skyflow.SkyflowClientBuilder: flat client-wide setters + propagation to existing controllers (mirrors addSkyflowCredentials) - VaultClient.updateExecutorInHTTP: set callTimeout + attach SkyflowRetryInterceptor; per-field precedence vault > client > SDK default (defaults 60s / 3 / 500ms / 2000ms) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * SK-3002 tests for configurable timeout + retries - SkyflowRetryInterceptorTests: retry count, stop-on-success, 408/429/5xx triggers, non-retryable passthrough, zero-retries - VaultClientHttpConfigTests: callTimeout applied to shared client, precedence (vault > client > default), bounded-not-zero regression guard, VaultConfig field getters/setters Note: pre-existing VaultClientTests#testSetBearerTokenWithEnvCredentials fails on Java 21 (PowerMock byte-buddy cannot instrument JDK security classes) — reproduced on base v3, unrelated to this change. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * SK-3002 add sample for configurable timeout + retries Demonstrates client-wide defaults on Skyflow.builder() and per-vault overrides on VaultConfig, with precedence and unit notes. Compiles against the local SDK build (samples module pins a released version, so it builds once this change ships). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * SK-3002 add MockWebServer integration test (live timeout + retry proof) Drives an OkHttpClient built like VaultClient (callTimeout + SkyflowRetry Interceptor) against a real loopback MockWebServer: - retries 503 then succeeds (server sees 1+retries requests) - exhausts retries, returns last failure - no retry on 400 - callTimeout aborts a never-responding server (~1s, not hanging) -- the fix - observable backoff between retries Adds com.squareup.okhttp3:mockwebserver as a test dependency. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * SK-3002 remove MockWebServer test (breaks CI on PowerMock + Java 21) MockWebServer's static init loads JDK security providers, which the PowerMock/byte-buddy agent fails to instrument on Java 21 (IllegalClassFormatException: Unsupported class file major version 65) -> ExceptionInInitializerError in setUp. This is the same agent/JDK incompatibility that already fails testSetBearerTokenWithEnvCredentials. Retry/timeout behavior remains covered by the mocked-Chain unit tests (SkyflowRetryInterceptorTests) and the config/precedence tests (VaultClientHttpConfigTests), both green in CI. Also drops the mockwebserver test dependency. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * SK-3002 raise coverage for new timeout/retry code Cover the previously-untested new code paths flagged by Codecov: - Skyflow.builder() setters + propagateHttpConfig loop (config set before and after addVaultConfig) -> SkyflowClientBuilderHttpConfigTests - resolveInt/resolveLong vault + client branches via maxRetries + backoff precedence, asserted on the built SkyflowRetryInterceptor's fields - interceptor InterruptedException-during-backoff path (throws IOException, preserves interrupt flag) Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * SK-3002-retry-backoff-support * SK-3002 use Fern v4 generated RetryInterceptor; rename knobs to initialRetryDelay/maxRetryDelay - Swap hand-written SkyflowRetryInterceptor for Fern's v4 generated RetryInterceptor (public 4-arg ctor: maxRetries, Optional<Long> initial/max delay, Optional<Double> jitter); delete SkyflowRetryInterceptor + its unit test - Rename public knobs initialRetryDelayMillis/maxRetryDelayMillis -> initialRetryDelay/ maxRetryDelay (Fern naming); still long ms, client + vault levels only - VaultClient attaches the generated RetryInterceptor on the shared client, passing resolved values as Optional (jitter Optional.empty -> Fern default 0.2). Gains Retry-After / X-RateLimit-Reset header awareness for free - Update VaultClientHttpConfigTests to reflect Fern's Duration fields; rename sample Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * SK-3002 fix CI coverage: prepend @{argLine} so JaCoCo agent attaches The v4-regen added a static <argLine> (--add-opens ...) to maven-surefire-plugin, which overwrote the argLine JaCoCo's prepare-agent injects. The coverage agent therefore never attached -> no jacoco.exec -> "Skipping JaCoCo ... missing execution data" -> no jacoco.xml -> Codecov "No coverage reports found" (build green, 439 tests pass, but upload fails). Prepend @{argLine} (Surefire late-binding of JaCoCo's property) so both the coverage agent and the --add-opens flags apply. Verified locally: jacoco.exec and jacoco.xml are generated again. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * SK-3002 default maxRetries=0 (retries opt-in) to avoid retrying non-idempotent writes Retries fire on 408/429/5xx for all operations regardless of HTTP verb, so auto-retrying a non-idempotent write (e.g. insert without upsert) after a 5xx/timeout could create a duplicate record. Default maxRetries to 0 so the unconfigured SDK does not retry; customers opt in by setting maxRetries. The 60s callTimeout still bounds every call. initialRetryDelay/maxRetryDelay defaults only take effect once maxRetries > 0. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * SK-3002 rename retry delay knobs to Fern's public names: initialRetryDelayMillis / maxRetryDelayMillis Match Fern's public setter names exactly (initialRetryDelayMillis / maxRetryDelayMillis) so the unit (ms) is self-documenting and consistent with Fern. timeout stays in seconds (also matching Fern). Removes the mixed-unit footgun where the dropped `Millis` suffix made `initialRetryDelay(500)` look like seconds. Renamed across VaultConfig, Skyflow.SkyflowClientBuilder, VaultClient, the config tests, and the sample. Fern interceptor field reflection in tests kept as-is (Fern's field is `initialRetryDelay: Duration`, not the ctor param name). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> * SK-3002 classify client-side timeout as 408 in batch error records Timeouts previously surfaced in response.errors as code 500 with a raw "...ApiClientException: Network error..." message, indistinguishable from a server error. In the four bulk handlers, when a batch fails with a non-API exception, walk the cause chain for an InterruptedIOException (OkHttp's call/socket timeout) and report 408 + "Request timed out." instead of 500. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: skyflow-bharti <bharti.sagar@skyflow.com> * [AUTOMATED] Private Release 2.1.1-dev-3196451 --------- Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Co-authored-by: Devesh-Skyflow <Devesh-Skyflow@users.noreply.github.com> Co-authored-by: skyflow-bharti <118584001+skyflow-bharti@users.noreply.github.com> Co-authored-by: skyflow-bharti <bharti.sagar@skyflow.com>
1 parent a475727 commit a0f3fcb

87 files changed

Lines changed: 3879 additions & 357 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,11 @@ public class InsertSchema {
260260
**Note**:
261261
- The table name can be specified either at the request level `InsertRequest` or at the record level `InsertRecord`, but not both.
262262
- If table name is not specified at the request level `InsertRequest`, then it must be specified in all record objects.
263-
- If table name is specified at the request level `InsertRequest`, then upsert must also be specified at the request level.
264-
- If table name is specified at the record level `InsertRecord`, then upsert must also be specified at the record level `InsertRecord`.
263+
- Upsert must be specified in the same place as the table name: if table name is specified at the request level `InsertRequest`, specify upsert at the request level; if table name is specified at the record level `InsertRecord`, specify upsert at the record level `InsertRecord`.
264+
- `upsertType` is optional and can be set alongside `upsert` at either the request level or the record level (matching the table/upsert placement):
265+
- `UpsertType.UPDATE` — updates only the columns provided in the request on the matched row; other existing columns are retained.
266+
- `UpsertType.REPLACE` — replaces the matched row with the provided values; columns not provided are cleared.
267+
- If `upsertType` is not specified, the vault applies the default of `UPDATE`.
265268

266269
### An [example](https://github.com/skyflowapi/skyflow-java/blob/v3/samples/src/main/java/com/example/vault/BulkInsertSync.java) of a sync bulkInsert call
267270

pom.xml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,19 @@
182182
<groupId>org.apache.maven.plugins</groupId>
183183
<artifactId>maven-surefire-plugin</artifactId>
184184
<version>2.22.2</version>
185+
<configuration>
186+
<argLine>
187+
@{argLine}
188+
--add-opens java.base/java.io=ALL-UNNAMED
189+
--add-opens java.base/java.lang=ALL-UNNAMED
190+
--add-opens java.base/java.util=ALL-UNNAMED
191+
--add-opens java.base/java.util.concurrent=ALL-UNNAMED
192+
--add-opens java.base/java.net=ALL-UNNAMED
193+
--add-opens java.base/java.lang.reflect=ALL-UNNAMED
194+
--add-opens java.base/java.text=ALL-UNNAMED
195+
--add-opens java.base/sun.security.x509=ALL-UNNAMED
196+
</argLine>
197+
</configuration>
185198
</plugin>
186199
<plugin>
187200
<groupId>org.jacoco</groupId>

samples/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
<dependency>
1919
<groupId>com.skyflow</groupId>
2020
<artifactId>skyflow-java</artifactId>
21-
<version>3.0.0-beta.6</version>
21+
<version>3.0.0-beta.11</version>
2222
</dependency>
2323

2424
</dependencies>

samples/src/main/java/com/example/vault/BulkMultiTableInsertAsync.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import com.skyflow.config.VaultConfig;
66
import com.skyflow.enums.Env;
77
import com.skyflow.enums.LogLevel;
8-
import com.skyflow.enums.UpsertType;
98
import com.skyflow.vault.data.InsertRecord;
109
import com.skyflow.vault.data.InsertRequest;
1110
import com.skyflow.vault.data.InsertResponse;
@@ -59,7 +58,8 @@ public static void main(String[] args) {
5958
.data(recordData1)
6059
.table("<YOUR_TABLE_NAME>")
6160
.upsert(upsertColumns)
62-
.upsertType(UpsertType.UPDATE)
61+
// upsertType is optional; when omitted the vault defaults to UpsertType.UPDATE.
62+
// Set .upsertType(UpsertType.REPLACE) to replace the matched row instead.
6363
.build();
6464

6565
// Step 5: Prepare second record for insertion

samples/src/main/java/com/example/vault/BulkMultiTableInsertSync.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@
55
import com.skyflow.config.VaultConfig;
66
import com.skyflow.enums.Env;
77
import com.skyflow.enums.LogLevel;
8-
import com.skyflow.enums.UpsertType;
98
import com.skyflow.errors.SkyflowException;
109
import com.skyflow.vault.data.InsertRecord;
1110
import com.skyflow.vault.data.InsertRequest;
@@ -58,7 +57,8 @@ public static void main(String[] args) {
5857
.data(recordData1)
5958
.table("<YOUR_TABLE_NAME>")
6059
.upsert(upsertColumns)
61-
.upsertType(UpsertType.UPDATE)
60+
// upsertType is optional; when omitted the vault defaults to UpsertType.UPDATE.
61+
// Set .upsertType(UpsertType.REPLACE) to replace the matched row instead.
6262
.build();
6363

6464
// Step 5: Prepare second record for insertion
Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
package com.example.vault;
2+
3+
import com.skyflow.Skyflow;
4+
import com.skyflow.config.Credentials;
5+
import com.skyflow.config.VaultConfig;
6+
import com.skyflow.enums.Env;
7+
import com.skyflow.enums.LogLevel;
8+
import com.skyflow.errors.SkyflowException;
9+
10+
/**
11+
* This sample demonstrates how to configure HTTP timeout and retry behavior in the Skyflow Java SDK.
12+
*
13+
* <p>Configurable settings (all optional):
14+
* <ul>
15+
* <li>{@code timeout} – overall call timeout in <b>seconds</b> (bounds the whole
16+
* request including retries and backoff). Default: 60.</li>
17+
* <li>{@code maxRetries} – retry attempts after the first failure (retries on HTTP
18+
* 408 / 429 / 5xx). Default: 0 — retries are OFF unless you set this (avoids auto-retrying non-idempotent writes).</li>
19+
* <li>{@code initialRetryDelayMillis} – base backoff before the first retry, in <b>milliseconds</b>.
20+
* Default: 500.</li>
21+
* <li>{@code maxRetryDelayMillis} – cap on the (exponentially growing) backoff, in
22+
* <b>milliseconds</b>. Default: 2000.</li>
23+
* </ul>
24+
*
25+
* <p><b>Two levels + precedence:</b> set client-wide defaults on {@code Skyflow.builder()}, and/or
26+
* per-vault overrides on {@code VaultConfig}. The most specific value wins, resolved per field:
27+
* <b>per-vault &rarr; client-wide &rarr; SDK default</b>.
28+
*/
29+
public class TimeoutAndRetryConfigExample {
30+
31+
public static void main(String[] args) {
32+
try {
33+
// Step 1: Initialize credentials with the path to your service account key file
34+
String filePath = "<YOUR_CREDENTIALS_FILE_PATH>";
35+
Credentials credentials = new Credentials();
36+
credentials.setPath(filePath);
37+
38+
// Step 2: Configure the vault. Optionally override timeout/retry settings for THIS vault only.
39+
VaultConfig vaultConfig = new VaultConfig();
40+
vaultConfig.setVaultId("<YOUR_VAULT_ID>");
41+
vaultConfig.setClusterId("<YOUR_CLUSTER_ID>");
42+
vaultConfig.setEnv(Env.PROD);
43+
vaultConfig.setCredentials(credentials);
44+
// Per-vault overrides (optional). Any field left unset inherits the client-wide default below,
45+
// and then the SDK default.
46+
vaultConfig.setTimeout(30); // seconds – tighter overall ceiling for this vault
47+
vaultConfig.setMaxRetries(2); // fewer retries for this vault
48+
vaultConfig.setInitialRetryDelayMillis(500L);
49+
vaultConfig.setMaxRetryDelayMillis(1000L);
50+
51+
// Step 3: Create the Skyflow client. Client-wide defaults apply to every vault
52+
// unless that vault overrides them (as above).
53+
Skyflow skyflowClient = Skyflow.builder()
54+
.setLogLevel(LogLevel.ERROR)
55+
.timeout(60) // seconds – client-wide overall call timeout
56+
.maxRetries(3) // client-wide retry attempts
57+
.initialRetryDelayMillis(500L) // client-wide base backoff (ms)
58+
.maxRetryDelayMillis(2000L) // client-wide backoff cap (ms)
59+
.addVaultConfig(vaultConfig)
60+
.build();
61+
62+
// Step 4: Use the client as usual. Requests now fail fast at the configured timeout and
63+
// retry transient 408/429/5xx responses with exponential backoff + jitter.
64+
System.out.println("Skyflow client configured with custom timeout & retry settings: " + skyflowClient);
65+
66+
// Example (uncomment and fill in a real request to try it):
67+
// DetokenizeResponse response = skyflowClient.vault().detokenize(detokenizeRequest);
68+
// System.out.println(response);
69+
} catch (SkyflowException e) {
70+
// Step 5: Handle any errors that occur during the process
71+
System.err.println("Error in Skyflow operations: " + e.getMessage());
72+
}
73+
}
74+
}

v3/pom.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
</parent>
1212

1313
<artifactId>skyflow-java</artifactId>
14-
<version>3.0.0-beta.11</version>
14+
<version>2.1.1-dev.3196451</version>
1515
<packaging>jar</packaging>
1616
<name>${project.groupId}:${project.artifactId}</name>
1717
<description>Skyflow V3 SDK for the Java programming language</description>

v3/src/main/java/com/skyflow/Skyflow.java

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,11 @@ public VaultController vault() throws SkyflowException {
5555
public static final class SkyflowClientBuilder extends BaseSkyflowClientBuilder {
5656
private final LinkedHashMap<String, VaultConfig> vaultConfigMap;
5757
private final LinkedHashMap<String, VaultController> vaultClientsMap;
58+
// Client-wide HTTP config defaults (apply to all vaults unless a vault overrides). null => SDK default.
59+
private Integer timeout;
60+
private Integer maxRetries;
61+
private Long initialRetryDelayMillis;
62+
private Long maxRetryDelayMillis;
5863

5964
public SkyflowClientBuilder() {
6065
this.vaultConfigMap = new LinkedHashMap<>();
@@ -78,7 +83,9 @@ public SkyflowClientBuilder addVaultConfig(VaultConfig vaultConfig) throws Skyfl
7883
ErrorMessage.VaultIdAlreadyInConfigList.getMessage());
7984
} else {
8085
this.vaultConfigMap.put(vaultConfigCopy.getVaultId(), vaultConfigCopy); // add new config in map
81-
this.vaultClientsMap.put(vaultConfigCopy.getVaultId(), new VaultController(vaultConfigCopy, this.skyflowCredentials)); // add new controller with new config
86+
VaultController controller = new VaultController(vaultConfigCopy, this.skyflowCredentials); // new controller with new config
87+
controller.setCommonHttpConfig(this.timeout, this.maxRetries, this.initialRetryDelayMillis, this.maxRetryDelayMillis);
88+
this.vaultClientsMap.put(vaultConfigCopy.getVaultId(), controller);
8289
LogUtil.printInfoLog(Utils.parameterizedString(
8390
InfoLogs.VAULT_CONTROLLER_INITIALIZED.getLog(), vaultConfigCopy.getVaultId()));
8491
}
@@ -100,6 +107,40 @@ public SkyflowClientBuilder addSkyflowCredentials(Credentials credentials) throw
100107
return this;
101108
}
102109

110+
/** Client-wide overall call timeout in seconds. Applies to all vaults unless a vault overrides it. */
111+
public SkyflowClientBuilder timeout(int timeout) {
112+
this.timeout = timeout;
113+
propagateHttpConfig();
114+
return this;
115+
}
116+
117+
/** Client-wide retry attempt count. Applies to all vaults unless a vault overrides it. */
118+
public SkyflowClientBuilder maxRetries(int maxRetries) {
119+
this.maxRetries = maxRetries;
120+
propagateHttpConfig();
121+
return this;
122+
}
123+
124+
/** Client-wide base retry backoff in milliseconds. Applies to all vaults unless a vault overrides it. */
125+
public SkyflowClientBuilder initialRetryDelayMillis(long initialRetryDelayMillis) {
126+
this.initialRetryDelayMillis = initialRetryDelayMillis;
127+
propagateHttpConfig();
128+
return this;
129+
}
130+
131+
/** Client-wide retry backoff cap in milliseconds. Applies to all vaults unless a vault overrides it. */
132+
public SkyflowClientBuilder maxRetryDelayMillis(long maxRetryDelayMillis) {
133+
this.maxRetryDelayMillis = maxRetryDelayMillis;
134+
propagateHttpConfig();
135+
return this;
136+
}
137+
138+
private void propagateHttpConfig() {
139+
for (VaultController vault : this.vaultClientsMap.values()) {
140+
vault.setCommonHttpConfig(this.timeout, this.maxRetries, this.initialRetryDelayMillis, this.maxRetryDelayMillis);
141+
}
142+
}
143+
103144
@Override
104145
public SkyflowClientBuilder setLogLevel(LogLevel logLevel) {
105146
super.setLogLevel(logLevel);

v3/src/main/java/com/skyflow/VaultClient.java

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import java.util.ArrayList;
44
import java.util.List;
5+
import java.util.Optional;
56
import java.util.concurrent.TimeUnit;
67

78
import com.skyflow.config.Credentials;
@@ -19,6 +20,7 @@
1920
import com.skyflow.generated.rest.types.V1Upsert;
2021
import com.skyflow.logs.InfoLogs;
2122
import com.skyflow.serviceaccount.util.Token;
23+
import com.skyflow.generated.rest.core.RetryInterceptor;
2224
import com.skyflow.utils.Constants;
2325
import com.skyflow.utils.Utils;
2426
import com.skyflow.utils.logger.LogUtil;
@@ -45,6 +47,16 @@ public class VaultClient {
4547
private String apiKey;
4648
private OkHttpClient sharedHttpClient = null;
4749
private String currentVaultURL = null;
50+
// Client-wide (Skyflow builder) HTTP config defaults; null => fall back to the SDK defaults below.
51+
private Integer commonTimeout;
52+
private Integer commonMaxRetries;
53+
private Long commonInitialRetryDelayMillis;
54+
private Long commonMaxRetryDelayMillis;
55+
// SDK defaults, used when neither the vault-level nor the client-wide value is set.
56+
private static final int DEFAULT_TIMEOUT_SECONDS = 60;
57+
private static final int DEFAULT_MAX_RETRIES = 0; // retries OFF by default (opt-in) so non-idempotent writes aren't auto-retried
58+
private static final long DEFAULT_INITIAL_RETRY_DELAY_MILLIS = 500L;
59+
private static final long DEFAULT_MAX_RETRY_DELAY_MILLIS = 2000L;
4860

4961
protected VaultClient(VaultConfig vaultConfig, Credentials credentials) throws SkyflowException {
5062
super();
@@ -68,6 +80,20 @@ protected void setCommonCredentials(Credentials commonCredentials) throws Skyflo
6880
prioritiseCredentials();
6981
}
7082

83+
/**
84+
* Client-wide HTTP timeout/retry defaults from the Skyflow builder. Nulls out the cached client
85+
* so the next call rebuilds with the new values.
86+
*/
87+
protected void setCommonHttpConfig(Integer timeout, Integer maxRetries,
88+
Long initialRetryDelayMillis, Long maxRetryDelayMillis) {
89+
this.commonTimeout = timeout;
90+
this.commonMaxRetries = maxRetries;
91+
this.commonInitialRetryDelayMillis = initialRetryDelayMillis;
92+
this.commonMaxRetryDelayMillis = maxRetryDelayMillis;
93+
this.sharedHttpClient = null;
94+
this.apiClient = null;
95+
}
96+
7197
protected void setBearerToken() throws SkyflowException {
7298
prioritiseCredentials();
7399
Validations.validateCredentials(this.finalCredentials);
@@ -143,9 +169,19 @@ private void prioritiseCredentials() throws SkyflowException {
143169

144170
protected void updateExecutorInHTTP() {
145171
if (sharedHttpClient == null) {
172+
int timeoutSeconds = resolveInt(vaultConfig.getTimeout(), commonTimeout, DEFAULT_TIMEOUT_SECONDS);
173+
int maxRetries = resolveInt(vaultConfig.getMaxRetries(), commonMaxRetries, DEFAULT_MAX_RETRIES);
174+
long initialRetryDelayMillis = resolveLong(
175+
vaultConfig.getInitialRetryDelayMillis(), commonInitialRetryDelayMillis, DEFAULT_INITIAL_RETRY_DELAY_MILLIS);
176+
long maxRetryDelayMillis = resolveLong(
177+
vaultConfig.getMaxRetryDelayMillis(), commonMaxRetryDelayMillis, DEFAULT_MAX_RETRY_DELAY_MILLIS);
178+
146179
sharedHttpClient = new OkHttpClient.Builder()
147180
.connectionPool(new ConnectionPool(10, 1, TimeUnit.MINUTES))
148-
.addInterceptor(chain -> {
181+
.callTimeout(timeoutSeconds, TimeUnit.SECONDS) // overall ceiling; bounds the whole call incl. retries
182+
.addInterceptor(new RetryInterceptor( // OUTER: retries (Fern generated; jitter default 0.2)
183+
maxRetries, Optional.of(initialRetryDelayMillis), Optional.of(maxRetryDelayMillis), Optional.empty()))
184+
.addInterceptor(chain -> { // INNER: auth (reads this.token per request)
149185
Request requestWithAuth = chain.request().newBuilder()
150186
.header("Authorization", "Bearer " + this.token)
151187
.build();
@@ -156,6 +192,22 @@ protected void updateExecutorInHTTP() {
156192
}
157193
}
158194

195+
/** Resolve an int setting: vault-level override, else client-wide default, else SDK default. */
196+
private static int resolveInt(Integer vaultLevel, Integer clientLevel, int defaultValue) {
197+
if (vaultLevel != null) {
198+
return vaultLevel;
199+
}
200+
return clientLevel != null ? clientLevel : defaultValue;
201+
}
202+
203+
/** Resolve a long setting: vault-level override, else client-wide default, else SDK default. */
204+
private static long resolveLong(Long vaultLevel, Long clientLevel, long defaultValue) {
205+
if (vaultLevel != null) {
206+
return vaultLevel;
207+
}
208+
return clientLevel != null ? clientLevel : defaultValue;
209+
}
210+
159211
protected V1InsertRequest getBulkInsertRequestBody(com.skyflow.vault.data.InsertRequest request, VaultConfig config) {
160212
ArrayList<InsertRecord> records = request.getRecords();
161213
List<V1InsertRecordData> insertRecordDataList = new ArrayList<>();

v3/src/main/java/com/skyflow/config/VaultConfig.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,22 @@ public class VaultConfig implements Cloneable {
88
private String vaultURL;
99
private Env env;
1010
private Credentials credentials;
11+
// HTTP timeout & retry config (vault-level overrides). null => inherit client-wide default, then SDK default.
12+
private Integer timeout; // overall call timeout, in seconds
13+
private Integer maxRetries; // retry attempts after the first failure
14+
private Long initialRetryDelayMillis; // base backoff before the first retry, in ms
15+
private Long maxRetryDelayMillis; // cap on the (exponentially growing) backoff, in ms
1116

1217
public VaultConfig() {
1318
this.vaultId = null;
1419
this.clusterId = null;
1520
this.vaultURL = null;
1621
this.env = Env.PROD;
1722
this.credentials = null;
23+
this.timeout = null;
24+
this.maxRetries = null;
25+
this.initialRetryDelayMillis = null;
26+
this.maxRetryDelayMillis = null;
1827
}
1928

2029
public String getVaultId() {
@@ -57,6 +66,42 @@ public void setVaultURL(String vaultURL) {
5766
this.vaultURL = vaultURL;
5867
}
5968

69+
public Integer getTimeout() {
70+
return timeout;
71+
}
72+
73+
/** Overall call timeout in seconds for this vault. Overrides the client-wide default. */
74+
public void setTimeout(Integer timeout) {
75+
this.timeout = timeout;
76+
}
77+
78+
public Integer getMaxRetries() {
79+
return maxRetries;
80+
}
81+
82+
/** Number of retry attempts after the first failure for this vault. Overrides the client-wide default. */
83+
public void setMaxRetries(Integer maxRetries) {
84+
this.maxRetries = maxRetries;
85+
}
86+
87+
public Long getInitialRetryDelayMillis() {
88+
return initialRetryDelayMillis;
89+
}
90+
91+
/** Base retry backoff in milliseconds for this vault. Overrides the client-wide default. */
92+
public void setInitialRetryDelayMillis(Long initialRetryDelayMillis) {
93+
this.initialRetryDelayMillis = initialRetryDelayMillis;
94+
}
95+
96+
public Long getMaxRetryDelayMillis() {
97+
return maxRetryDelayMillis;
98+
}
99+
100+
/** Cap on retry backoff in milliseconds for this vault. Overrides the client-wide default. */
101+
public void setMaxRetryDelayMillis(Long maxRetryDelayMillis) {
102+
this.maxRetryDelayMillis = maxRetryDelayMillis;
103+
}
104+
60105
@Override
61106
public Object clone() throws CloneNotSupportedException {
62107
VaultConfig cloned = (VaultConfig) super.clone();

0 commit comments

Comments
 (0)