Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ public class SecretCacheConfiguration {
/** The default version stage to use when retrieving secret values. */
public static final String DEFAULT_VERSION_STAGE = "AWSCURRENT";

/**
* The default maximum jitter value in milliseconds to use when forcing a refresh.
* This prevents continuous refreshNow() calls by adding a random sleep.
*/
public static final long DEFAULT_FORCE_REFRESH_JITTER = 100;

/** The client this cache instance will use for accessing AWS Secrets Manager. */
private SecretsManagerClient client = null;

Expand All @@ -60,6 +66,13 @@ public class SecretCacheConfiguration {
*/
private String versionStage = DEFAULT_VERSION_STAGE;

/**
* When forcing a refresh using the refreshNow method, a random sleep
* will be performed using this value. This helps prevent code from
* executing a refreshNow in a continuous loop without waiting.
*/
private long forceRefreshJitterMillis = DEFAULT_FORCE_REFRESH_JITTER;

/**
* Default constructor for the SecretCacheConfiguration object.
*
Expand Down Expand Up @@ -237,4 +250,45 @@ public SecretCacheConfiguration withVersionStage(String versionStage) {
return this;
}

/**
* Returns the refresh jitter that is used when force refreshing secrets.
*
* @return The maximum jitter sleep time in milliseconds used with refreshing secrets.
*/
public long getForceRefreshJitterMillis() {
return this.forceRefreshJitterMillis;
}

/**
* Sets the maximum sleep time in milliseconds between force refresh calls.
* This value is used to prevent continuous refreshNow() calls in tight loops
* by adding a random sleep between half the configured value and the full value.
* The value must be greater than or equal to zero.
*
* @param forceRefreshJitterMillis
* The maximum sleep time in milliseconds between force refresh calls.
* @throws IllegalArgumentException if the value is negative
*/
public void setForceRefreshJitterMillis(long forceRefreshJitterMillis) {
if (forceRefreshJitterMillis < 0) {
throw new IllegalArgumentException("Force refresh jitter must be greater than or equal to zero");
}
this.forceRefreshJitterMillis = forceRefreshJitterMillis;
}

/**
* Sets the maximum sleep time in milliseconds between force refresh calls.
* This value is used to prevent continuous refreshNow() calls in tight loops
* by adding a random sleep between half the configured value and the full value.
*
* @param forceRefreshJitterMillis
* The maximum sleep time in milliseconds between force refresh calls.
* @return The updated ClientConfiguration object with the new refresh sleep time.
* @throws IllegalArgumentException if the value is negative
*/
public SecretCacheConfiguration withForceRefreshJitterMillis(long forceRefreshJitterMillis) {
this.setForceRefreshJitterMillis(forceRefreshJitterMillis);
return this;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,6 @@ public abstract class SecretCacheObject<T> {
*/
private static final long BACKOFF_PLATEAU = EXCEPTION_BACKOFF * 128;

/**
* When forcing a refresh using the refreshNow method, a random sleep
* will be performed using this value. This helps prevent code from
* executing a refreshNow in a continuous loop without waiting.
*/
private static final long FORCE_REFRESH_JITTER_SLEEP = 5000;

/** The secret identifier for this cached object. */
protected final String secretId;

Expand Down Expand Up @@ -215,10 +208,11 @@ public boolean refreshNow() throws InterruptedException {
// When forcing a refresh, always sleep with a random jitter
// to prevent coding errors that could be calling refreshNow
// in a loop.
long jitter = this.config.getForceRefreshJitterMillis();
long sleep = ThreadLocalRandom.current()
.nextLong(
FORCE_REFRESH_JITTER_SLEEP / 2,
FORCE_REFRESH_JITTER_SLEEP + 1);
jitter / 2,
jitter + 1);
// Make sure we are not waiting for the next refresh after an
// exception. If we are, sleep based on the retry delay of
// the refresh to prevent a hard loop in attempting to refresh a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,30 @@ public void secretCacheConstructorTest() {
} catch (Exception e) {
}
}

@Test
public void testForceRefreshJitterConfiguration() {
// Test default value
SecretCacheConfiguration config = new SecretCacheConfiguration();
Assert.assertEquals(config.getForceRefreshJitterMillis(), SecretCacheConfiguration.DEFAULT_FORCE_REFRESH_JITTER);

// Test setting a custom value
long customJitter = 250L;
config.setForceRefreshJitterMillis(customJitter);
Assert.assertEquals(config.getForceRefreshJitterMillis(), customJitter);

// Test zero is valid
config.setForceRefreshJitterMillis(0);
Assert.assertEquals(config.getForceRefreshJitterMillis(), 0);
}

@Test(expectedExceptions = IllegalArgumentException.class,
expectedExceptionsMessageRegExp = "Force refresh jitter must be greater than or equal to zero")
public void testForceRefreshJitterValidation() {
// Test that negative values throw an exception
SecretCacheConfiguration config = new SecretCacheConfiguration();
config.setForceRefreshJitterMillis(-1);
}

@Test
public void basicSecretCacheTest() {
Expand Down