vault-credentialstore-lib/src/main/java/com/streamsets/datacollector/vault/Vault.java
public String read(String path, String key, long delay) {
    if (!secrets.containsKey(path)) {
      VaultClient vault = new VaultClient(getConfig());
      Secret secret;

      try {
        secret = vault.logical().read(path);
      } catch (VaultException e) {
        LOG.error(e.toString(), e);
        throw new VaultRuntimeException(e.toString());
      }

      // Record the expiration date of this lease
      String leaseId;
      if (secret.isRenewable()) {
        // Only renewable secrets seem to have a leaseId
        leaseId = secret.getLeaseId();
      } else {
        // So for non-renewable secrets we'll store the path with an extra / so that we can purge them correctly.
        leaseId = path + "/";
      }
      leases.put(leaseId, System.currentTimeMillis() + (secret.getLeaseDuration() * 1000));

      secrets.put(path, secret);

      try {
        Thread.sleep(delay);
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
      }
    }

    Map<String, Object> data = secrets.get(path).getData();
    String value = getSecretValue(data, key).orElseThrow(() -> new VaultRuntimeException("Value not found for key"));
    LOG.trace("CredentialStore '{}' Vault, retrieved value for key '{}'", csId, key);
    return value;
  }
public String read(String path, String key, long delay) {
    if (!secrets.containsKey(path)) {
      VaultClient vault = new VaultClient(getConfig());
      Secret secret;

      try {
        secret = vault.logical().read(path);
      } catch (VaultException e) {
        LOG.error(e.toString(), e);
        throw new VaultRuntimeException(e.toString());
      }

      // Record the expiration date of this lease
      String leaseId;
      if (secret.isRenewable()) {
        // Only renewable secrets seem to have a leaseId
        leaseId = secret.getLeaseId();
      } else {
        // So for non-renewable secrets we'll store the path with an extra / so that we can purge them correctly.
        leaseId = path + "/";
      }
      leases.put(leaseId, System.currentTimeMillis() + (secret.getLeaseDuration() * 1000));

      secrets.put(path, secret);

      try {
        Thread.sleep(delay);
      } catch (InterruptedException e) {
        Thread.currentThread().interrupt();
      }
    }

    Map<String, Object> data = secrets.get(path).getData();
    String value = getSecretValue(data, key).orElseThrow(() -> new VaultRuntimeException("Value not found for key"));
    LOG.trace("CredentialStore '{}' Vault, retrieved value for key '{}'", csId, key);
    return value;
  }
Reads a secret from the local cache if it hasn't expired and returns the value for the specified key.
If the secret isn't cached or has expired, it requests it from Vault again.

This version of the method will also add the specified delay in milliseconds before returning, but only
if the value wasn't already locally cached. This is because certain backends such as AWS will return
a secret (access keys for example) before they have propagated to all AWS services. For AWS a delay of up to 5
or 10 seconds may be necessary. If you receive a 403 from AWS services you probably need to increase the delay.

@param path path in Vault to read
@param key key of the property of the secret represented by the path to return
@param delay delay in milliseconds to wait before returning the value if it wasn't already cached.
@return value of the specified key for the requested secret.