Skip to content

Commit 93d5eec

Browse files
committed
feat(java): synchronize getAccessToken for threwad safety
1 parent d89bab1 commit 93d5eec

3 files changed

Lines changed: 27 additions & 2 deletions

File tree

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ The `ConfidentialClient` refreshes access tokens proactively before their actual
187187
Default behaviour:
188188
- A 30 second (30,000 ms) proactive offset is applied automatically.
189189
- Calls to `getAccessToken()` (or `getAccessToken(false)`) reuse the cached token while it is still considered valid under this adjusted expiry.
190-
- `getAccessToken(true)` forces a fresh token unless one was very recently refreshed (within 5 seconds) to avoid unnecessary duplicate requests.
190+
- `getAccessToken(true)` forces a fresh token unless one was very recently refreshed (within 5 seconds) to avoid unnecessary duplicate requests from concurrent threads.
191191

192192
You can override the proactive offset by configuring it in `RequestOptions`:
193193

src/main/java/com/factset/sdk/utils/authentication/ConfidentialClient.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -194,7 +194,7 @@ protected ConfidentialClient(final Configuration config, final TokenRequestBuild
194194
* @throws AccessTokenException If it can't make a successful request or parse the TokenRequest.
195195
* @throws SigningJwsException If the signing of the JWS fails.
196196
*/
197-
public String getAccessToken(boolean forceRefresh) throws AccessTokenException, SigningJwsException {
197+
public synchronized String getAccessToken(boolean forceRefresh) throws AccessTokenException, SigningJwsException {
198198
if (this.isCachedTokenValid()) {
199199
if (!forceRefresh) {
200200
LOGGER.info("Retrieved access token which expires in: {} seconds", TimeUnit.MILLISECONDS.toSeconds(this.accessTokenExpireTime - System.currentTimeMillis()));

src/test/java/com/factset/sdk/utils/authentication/ConfidentialClientTest.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,31 @@ void getAccessTokenForceRefreshThenCachedReturnsCorrectTokens() throws Exception
326326
verify(harness.httpRequestMock, times(1)).send();
327327
}
328328

329+
@Test
330+
void getAccessTokenTwoDifferentThreadsSimultaneouslyOnlyFetchesOnce() throws Exception {
331+
TestHarness harness = createClientWithTokens(899, "threadedToken");
332+
333+
Runnable task = () -> {
334+
String token;
335+
try {
336+
token = harness.client.getAccessToken();
337+
} catch (AccessTokenException | SigningJwsException e) {
338+
throw new RuntimeException(e);
339+
}
340+
assertEquals("threadedToken", token);
341+
};
342+
343+
Thread thread1 = new Thread(task);
344+
Thread thread2 = new Thread(task);
345+
346+
thread1.start();
347+
thread2.start();
348+
349+
thread1.join();
350+
thread2.join();
351+
352+
verify(harness.httpRequestMock, times(1)).send();
353+
}
329354

330355
@Test
331356
void forceRefreshWithinGracePeriodReturnsCachedToken() throws Exception {

0 commit comments

Comments
 (0)