Skip to content

Commit f0582e8

Browse files
Add Configuration Option to Disable Async Token Refresh (#478)
## What changes are proposed in this pull request? This PR adds a new configuration option to control asynchronous token refresh behavior in the Databricks SDK for Java. ## Changes - Added `disableAsyncTokenRefresh` configuration to `DatabricksConfig` with environment variable `DATABRICKS_DISABLE_ASYNC_TOKEN_REFRESH` - **Async token refresh is enabled by default** for optimal performance ## To disable async token refresh **Environment Variable:** ```bash export DATABRICKS_DISABLE_ASYNC_TOKEN_REFRESH=true ``` **Programmatic:** ```java DatabricksConfig config = new DatabricksConfig() .setDisableAsyncTokenRefresh(true); ``` ## How is this tested? Existing unit and integration tests. --------- Co-authored-by: Parth Bansal <[email protected]>
1 parent 3836135 commit f0582e8

15 files changed

+82
-34
lines changed

NEXT_CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
## Release v0.55.0
44

55
### New Features and Improvements
6+
* Enabled asynchronous token refreshes by default. A new `disable_async_token_refresh` configuration option has been added to allow disabling this feature if necessary.
7+
To disable asynchronous token refresh, set the environment variable `DATABRICKS_DISABLE_ASYNC_TOKEN_REFRESH=true` or configure it within your configuration object.
8+
The previous `DATABRICKS_ENABLE_EXPERIMENTAL_ASYNC_TOKEN_REFRESH` option has been removed as asynchronous refresh is now the default behavior.
69

710
### Bug Fixes
811

databricks-sdk-java/src/main/java/com/databricks/sdk/core/AzureCliCredentialsProvider.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,10 @@ public CachedTokenSource tokenSourceFor(DatabricksConfig config, String resource
5252
protected CachedTokenSource getTokenSource(DatabricksConfig config, List<String> cmd) {
5353
CliTokenSource tokenSource =
5454
new CliTokenSource(cmd, "tokenType", "accessToken", "expiresOn", config.getEnv());
55-
CachedTokenSource cachedTokenSource = new CachedTokenSource.Builder(tokenSource).build();
55+
CachedTokenSource cachedTokenSource =
56+
new CachedTokenSource.Builder(tokenSource)
57+
.setAsyncDisabled(config.getDisableAsyncTokenRefresh())
58+
.build();
5659
cachedTokenSource.getToken(); // Check if the CLI is installed and to validate the config.
5760
return cachedTokenSource;
5861
}

databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksCliCredentialsProvider.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,10 @@ public OAuthHeaderFactory configure(DatabricksConfig config) {
4949
return null;
5050
}
5151

52-
CachedTokenSource cachedTokenSource = new CachedTokenSource.Builder(tokenSource).build();
52+
CachedTokenSource cachedTokenSource =
53+
new CachedTokenSource.Builder(tokenSource)
54+
.setAsyncDisabled(config.getDisableAsyncTokenRefresh())
55+
.build();
5356
cachedTokenSource.getToken(); // We need this for checking if databricks CLI is installed.
5457

5558
return OAuthHeaderFactory.fromTokenSource(cachedTokenSource);

databricks-sdk-java/src/main/java/com/databricks/sdk/core/DatabricksConfig.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,10 @@ public class DatabricksConfig {
159159
@ConfigAttribute(env = "DATABRICKS_OIDC_TOKEN_ENV", auth = "env-oidc")
160160
private String oidcTokenEnv;
161161

162+
/** Disable asynchronous token refresh when set to true. */
163+
@ConfigAttribute(env = "DATABRICKS_DISABLE_ASYNC_TOKEN_REFRESH")
164+
private Boolean disableAsyncTokenRefresh;
165+
162166
public Environment getEnv() {
163167
return env;
164168
}
@@ -575,6 +579,15 @@ public DatabricksConfig setOidcTokenEnv(String oidcTokenEnv) {
575579
return this;
576580
}
577581

582+
public boolean getDisableAsyncTokenRefresh() {
583+
return disableAsyncTokenRefresh != null && disableAsyncTokenRefresh;
584+
}
585+
586+
public DatabricksConfig setDisableAsyncTokenRefresh(boolean disableAsyncTokenRefresh) {
587+
this.disableAsyncTokenRefresh = disableAsyncTokenRefresh;
588+
return this;
589+
}
590+
578591
public boolean isAzure() {
579592
if (azureWorkspaceResourceId != null) {
580593
return true;

databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/AzureGithubOidcCredentialsProvider.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,10 @@ public OAuthHeaderFactory configure(DatabricksConfig config) {
4646
config.getEffectiveAzureLoginAppId(),
4747
idToken.get(),
4848
"urn:ietf:params:oauth:client-assertion-type:jwt-bearer");
49-
CachedTokenSource cachedTokenSource = new CachedTokenSource.Builder(tokenSource).build();
49+
CachedTokenSource cachedTokenSource =
50+
new CachedTokenSource.Builder(tokenSource)
51+
.setAsyncDisabled(config.getDisableAsyncTokenRefresh())
52+
.build();
5053
return OAuthHeaderFactory.fromTokenSource(cachedTokenSource);
5154
}
5255

databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/AzureServicePrincipalCredentialsProvider.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,8 @@ private static CachedTokenSource tokenSourceFor(DatabricksConfig config, String
7070
.withEndpointParametersSupplier(() -> endpointParams)
7171
.withAuthParameterPosition(AuthParameterPosition.BODY)
7272
.build();
73-
return new CachedTokenSource.Builder(clientCredentials).build();
73+
return new CachedTokenSource.Builder(clientCredentials)
74+
.setAsyncDisabled(config.getDisableAsyncTokenRefresh())
75+
.build();
7476
}
7577
}

databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/CachedTokenSource.java

Lines changed: 10 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,7 @@ private enum TokenState {
4040
// The token source to use for refreshing the token.
4141
private final TokenSource tokenSource;
4242
// Whether asynchronous refresh is enabled.
43-
private boolean asyncEnabled =
44-
Boolean.parseBoolean(System.getenv("DATABRICKS_ENABLE_EXPERIMENTAL_ASYNC_TOKEN_REFRESH"));
43+
private boolean asyncDisabled = false;
4544
// Duration before expiry to consider a token as 'stale'.
4645
private final Duration staleDuration;
4746
// Additional buffer before expiry to consider a token as expired.
@@ -50,15 +49,15 @@ private enum TokenState {
5049
private final ClockSupplier clockSupplier;
5150

5251
// The current OAuth token. May be null if not yet fetched.
53-
private volatile Token token;
52+
protected volatile Token token;
5453
// Whether a refresh is currently in progress (for async refresh).
5554
private boolean refreshInProgress = false;
5655
// Whether the last refresh attempt succeeded.
5756
private boolean lastRefreshSucceeded = true;
5857

5958
private CachedTokenSource(Builder builder) {
6059
this.tokenSource = builder.tokenSource;
61-
this.asyncEnabled = builder.asyncEnabled;
60+
this.asyncDisabled = builder.asyncDisabled;
6261
this.staleDuration = builder.staleDuration;
6362
this.expiryBuffer = builder.expiryBuffer;
6463
this.clockSupplier = builder.clockSupplier;
@@ -73,7 +72,7 @@ private CachedTokenSource(Builder builder) {
7372
*/
7473
public static class Builder {
7574
private final TokenSource tokenSource;
76-
private boolean asyncEnabled = false;
75+
private boolean asyncDisabled = false;
7776
private Duration staleDuration = DEFAULT_STALE_DURATION;
7877
private Duration expiryBuffer = DEFAULT_EXPIRY_BUFFER;
7978
private ClockSupplier clockSupplier = new UtcClockSupplier();
@@ -110,11 +109,11 @@ public Builder setToken(Token token) {
110109
* current token. When disabled, all refreshes are performed synchronously and will block the
111110
* calling thread.
112111
*
113-
* @param asyncEnabled True to enable asynchronous refresh, false to disable.
112+
* @param asyncDisabled True to disable asynchronous refresh, false to enable.
114113
* @return This builder instance for method chaining.
115114
*/
116-
public Builder setAsyncEnabled(boolean asyncEnabled) {
117-
this.asyncEnabled = asyncEnabled;
115+
public Builder setAsyncDisabled(boolean asyncDisabled) {
116+
this.asyncDisabled = asyncDisabled;
118117
return this;
119118
}
120119

@@ -182,10 +181,10 @@ public CachedTokenSource build() {
182181
* @return The current valid token
183182
*/
184183
public Token getToken() {
185-
if (asyncEnabled) {
186-
return getTokenAsync();
184+
if (asyncDisabled) {
185+
return getTokenBlocking();
187186
}
188-
return getTokenBlocking();
187+
return getTokenAsync();
189188
}
190189

191190
/**

databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/DataPlaneTokenSource.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ public class DataPlaneTokenSource {
1717
private final HttpClient httpClient;
1818
private final TokenSource cpTokenSource;
1919
private final String host;
20+
private final boolean asyncDisabled;
2021
private final ConcurrentHashMap<TokenSourceKey, CachedTokenSource> sourcesCache;
2122
/**
2223
* Caching key for {@link EndpointTokenSource}, based on endpoint and authorization details. This
@@ -42,11 +43,13 @@ static TokenSourceKey create(String endpoint, String authDetails) {
4243
* @throws NullPointerException if any parameter is null.
4344
* @throws IllegalArgumentException if the host is empty.
4445
*/
45-
public DataPlaneTokenSource(HttpClient httpClient, TokenSource cpTokenSource, String host) {
46+
public DataPlaneTokenSource(
47+
HttpClient httpClient, TokenSource cpTokenSource, String host, boolean asyncDisabled) {
4648
this.httpClient = Objects.requireNonNull(httpClient, "HTTP client cannot be null");
4749
this.cpTokenSource =
4850
Objects.requireNonNull(cpTokenSource, "Control plane token source cannot be null");
4951
this.host = Objects.requireNonNull(host, "Host cannot be null");
52+
this.asyncDisabled = asyncDisabled;
5053

5154
if (host.isEmpty()) {
5255
throw new IllegalArgumentException("Host cannot be empty");
@@ -85,6 +88,7 @@ public Token getToken(String endpoint, String authDetails) {
8588
new CachedTokenSource.Builder(
8689
new EndpointTokenSource(
8790
this.cpTokenSource, k.authDetails(), this.httpClient, this.host))
91+
.setAsyncDisabled(asyncDisabled)
8892
.build());
8993

9094
return specificSource.getToken();

databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/ExternalBrowserCredentialsProvider.java

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,10 @@ public OAuthHeaderFactory configure(DatabricksConfig config) {
7878
Optional.of(config.getEffectiveOAuthRedirectUrl()),
7979
Optional.of(tokenCache));
8080

81-
CachedTokenSource cachedTokenSource = new CachedTokenSource.Builder(tokenSource).build();
81+
CachedTokenSource cachedTokenSource =
82+
new CachedTokenSource.Builder(tokenSource)
83+
.setAsyncDisabled(config.getDisableAsyncTokenRefresh())
84+
.build();
8285
LOGGER.debug("Using cached token, will immediately refresh");
8386
cachedTokenSource.getToken();
8487
return OAuthHeaderFactory.fromTokenSource(cachedTokenSource);
@@ -128,6 +131,9 @@ CachedTokenSource performBrowserAuth(
128131
Optional.ofNullable(config.getEffectiveOAuthRedirectUrl()),
129132
Optional.ofNullable(tokenCache));
130133

131-
return new CachedTokenSource.Builder(tokenSource).setToken(token).build();
134+
return new CachedTokenSource.Builder(tokenSource)
135+
.setToken(token)
136+
.setAsyncDisabled(config.getDisableAsyncTokenRefresh())
137+
.build();
132138
}
133139
}

databricks-sdk-java/src/main/java/com/databricks/sdk/core/oauth/GithubOidcCredentialsProvider.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,10 @@ public HeaderFactory configure(DatabricksConfig config) throws DatabricksExcepti
5858
.build())
5959
.build();
6060

61-
CachedTokenSource cachedTokenSource = new CachedTokenSource.Builder(clientCredentials).build();
61+
CachedTokenSource cachedTokenSource =
62+
new CachedTokenSource.Builder(clientCredentials)
63+
.setAsyncDisabled(config.getDisableAsyncTokenRefresh())
64+
.build();
6265

6366
return () -> {
6467
Map<String, String> headers = new HashMap<>();

0 commit comments

Comments
 (0)