Created
March 20, 2025 10:19
-
-
Save jkuipers/8810b7151ef7a2697ab7e89d2aa5232e to your computer and use it in GitHub Desktop.
Template class for managing authentication tokens while preventing thundering herd problems on token expiry
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import org.slf4j.Logger; | |
import org.slf4j.LoggerFactory; | |
import java.util.concurrent.locks.Lock; | |
import java.util.concurrent.locks.ReentrantLock; | |
public abstract class AbstractTokenManager<T> { | |
private static final long MIN_MILLIS_INDICATING_REFRESHED = 10_000L; | |
protected final Logger logger = LoggerFactory.getLogger(getClass()); | |
/** Used to prevent a thundering herd problem when multiple threads want to refresh an expired token */ | |
private final Lock tokenLock = new ReentrantLock(); | |
private volatile T token; | |
private long lastRefresh; | |
private boolean forceRequestOnRefresh; | |
public T currentToken() { | |
if (token == null) { | |
refreshToken(); | |
} | |
return token; | |
} | |
public void refreshToken() { | |
tokenLock.lock(); | |
try { | |
if (!forceRequestOnRefresh && alreadyRefreshed()) { | |
logger.debug("Token already refreshed"); | |
return; | |
} | |
T newToken = doFetchToken(); | |
if (newToken != null) { | |
logTokenReceived(newToken); | |
this.token = newToken; | |
this.lastRefresh = System.currentTimeMillis(); | |
} else { | |
logger.warn("Did not receive new token"); | |
} | |
} finally { | |
tokenLock.unlock(); | |
} | |
} | |
protected void logTokenReceived(T token) { | |
logger.info("Got authentication token"); | |
} | |
protected abstract T doFetchToken(); | |
protected void setForceRequestOnRefresh(boolean forceRequestOnRefresh) { | |
this.forceRequestOnRefresh = forceRequestOnRefresh; | |
} | |
private boolean alreadyRefreshed() { | |
return token != null && (System.currentTimeMillis() - lastRefresh < MIN_MILLIS_INDICATING_REFRESHED); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment