Skip to content
Merged
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 @@ -57,6 +57,9 @@ public class PartitionKeyResolver implements AutoCloseable {
/** Cooldown period after permanent failure before allowing another discovery attempt (5 min). */
static final long PERMANENT_FAILURE_COOLDOWN_MS = 5 * 60 * 1000;

/** Maximum jitter as a percentage of the base delay (20%). */
static final double MAX_JITTER_PERCENT = 0.2;

private final ConcurrentHashMap<String, String> cache;
private final Set<String> discoveryInProgress;
private final ConcurrentHashMap<String, FailureRecord> failedTables;
Expand Down Expand Up @@ -218,12 +221,13 @@ private void discoverWithRetry(String tableName, DynamoDbClient client) {
return;
}

long jitteredDelay = calculateJitteredDelay(delay);
logger.log(
Level.FINE,
"Transient error discovering partition key for table {0}, retry {1}/{2} after {3}ms: {4}",
new Object[] {tableName, attempt, MAX_RETRIES, delay, e.getMessage()});
new Object[] {tableName, attempt, MAX_RETRIES, jitteredDelay, e.getMessage()});

sleep(delay);
sleep(jitteredDelay);
delay = Math.min(delay * 2, MAX_RETRY_DELAY_MS);

} catch (Exception e) {
Expand All @@ -242,6 +246,7 @@ private void discoverWithRetry(String tableName, DynamoDbClient client) {
return;
}

long jitteredDelay = calculateJitteredDelay(delay);
if (logger.isLoggable(Level.FINE)) {
logger.log(
Level.FINE,
Expand All @@ -252,12 +257,12 @@ private void discoverWithRetry(String tableName, DynamoDbClient client) {
+ "/"
+ MAX_RETRIES
+ " after "
+ delay
+ jitteredDelay
+ "ms",
e);
}

sleep(delay);
sleep(jitteredDelay);
delay = Math.min(delay * 2, MAX_RETRY_DELAY_MS);
}
}
Expand Down Expand Up @@ -286,6 +291,20 @@ private boolean isPermanentFailure(DynamoDbException e) {
return e.statusCode() >= 400 && e.statusCode() < 500 && e.statusCode() != 429;
}

/**
* Calculates a jittered delay to prevent thundering herd.
*
* @param baseDelay the base delay in milliseconds
* @return the jittered delay in milliseconds
*/
private long calculateJitteredDelay(long baseDelay) {
// Add random jitter: base delay ± up to MAX_JITTER_PERCENT
double jitterRange = baseDelay * MAX_JITTER_PERCENT;
double jitter =
(Math.random() * 2 - 1) * jitterRange; // Random value in [-jitterRange, +jitterRange]
return Math.max(1, Math.round(baseDelay + jitter)); // Ensure minimum 1ms delay
}

/**
* Sleeps for the specified duration, handling interruption.
*
Expand Down
Loading