private synchronized void refreshTokenAndStorageClients() {
    azureMetrics.absTokenRefreshAttemptCount.inc();
    try {
      // if a task is already scheduled to refresh token then remove it.
      if (scheduledFutureRef.get() != null) {
        scheduledFutureRef.get().cancel(false);
        scheduledFutureRef.set(null);
      }

      // Refresh Token
      refreshToken();

      // Create new async storage clients with refreshed token.
      BlobServiceAsyncClient blobServiceAsyncClient = createBlobStorageAsyncClient();
      setAsyncClientReferences(blobServiceAsyncClient);

      logger.info("Token refresh done.");

      // schedule a task to refresh token again and create new storage sync and async clients before it expires.
      scheduledFutureRef.set(tokenRefreshScheduler.schedule(this::refreshTokenAndStorageClients,
          (long) ((accessTokenRef.get().getExpiresAt().toEpochSecond() - OffsetDateTime.now().toEpochSecond())
              * azureCloudConfig.azureStorageClientRefreshFactor), TimeUnit.SECONDS));
    } catch (MalformedURLException | InterruptedException | ExecutionException ex) {
      logger.error("Error building ABS blob service client: {}", ex.getMessage());
      throw new IllegalStateException(ex);
    }
  }
Refreshes AD authentication token and creates a new ABS client with the new token. Also, it schedules a task
for repeating this step before the obtained token expires.
ambry-cloud/src/main/java/com/github/ambry/cloud/azure/ADAuthBasedStorageClient.java