Set idle time the same as for the internal cache, but extend it for refreshes

Closes #32100

Signed-off-by: Alexander Schwartz <aschwart@redhat.com>
Signed-off-by: Michal Hajas <mhajas@redhat.com>
Co-authored-by: Michal Hajas <mhajas@redhat.com>
This commit is contained in:
Alexander Schwartz 2024-09-09 10:47:56 +02:00 committed by GitHub
parent 03e0fb0601
commit d9dfe74e8b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 24 additions and 54 deletions

View file

@ -135,11 +135,10 @@ public class InfinispanUserLoginFailureProviderFactory implements UserLoginFailu
InfinispanConnectionProvider ispn = session.getProvider(InfinispanConnectionProvider.class);
Cache<LoginFailureKey, SessionEntityWrapper<LoginFailureEntity>> loginFailuresCache = ispn.getCache(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME);
checkRemoteCache(session, loginFailuresCache, (RealmModel realm) ->
Time.toMillis(realm.getMaxDeltaTimeSeconds()), SessionTimeouts::getLoginFailuresLifespanMs, SessionTimeouts::getLoginFailuresMaxIdleMs);
checkRemoteCache(session, loginFailuresCache, SessionTimeouts::getLoginFailuresLifespanMs, SessionTimeouts::getLoginFailuresMaxIdleMs);
}
private <K, V extends SessionEntity> RemoteCache checkRemoteCache(KeycloakSession session, Cache<K, SessionEntityWrapper<V>> ispnCache, RemoteCacheInvoker.MaxIdleTimeLoader maxIdleLoader,
private <K, V extends SessionEntity> RemoteCache checkRemoteCache(KeycloakSession session, Cache<K, SessionEntityWrapper<V>> ispnCache,
SessionFunction<V> lifespanMsLoader, SessionFunction<V> maxIdleTimeMsLoader) {
Set<RemoteStore> remoteStores = InfinispanUtil.getRemoteStores(ispnCache);
@ -155,7 +154,7 @@ public class InfinispanUserLoginFailureProviderFactory implements UserLoginFailu
throw new IllegalStateException("No remote cache available for the infinispan cache: " + ispnCache.getName());
}
remoteCacheInvoker.addRemoteCache(ispnCache.getName(), remoteCache, maxIdleLoader);
remoteCacheInvoker.addRemoteCache(ispnCache.getName(), remoteCache);
RemoteCacheSessionListener hotrodListener = RemoteCacheSessionListener.createListener(session, ispnCache, remoteCache, lifespanMsLoader, maxIdleTimeMsLoader, null);
remoteCache.addClientListener(hotrodListener);

View file

@ -317,37 +317,27 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
InfinispanConnectionProvider ispn = session.getProvider(InfinispanConnectionProvider.class);
Cache<String, SessionEntityWrapper<UserSessionEntity>> sessionsCache = ispn.getCache(InfinispanConnectionProvider.USER_SESSION_CACHE_NAME);
RemoteCache sessionsRemoteCache = checkRemoteCache(session, sessionsCache, (RealmModel realm) -> {
// We won't write to the remoteCache during token refresh, so the timeout needs to be longer.
return Time.toMillis(realm.getSsoSessionMaxLifespan());
}, SessionTimeouts::getUserSessionLifespanMs, SessionTimeouts::getUserSessionMaxIdleMs);
RemoteCache sessionsRemoteCache = checkRemoteCache(session, sessionsCache, SessionTimeouts::getUserSessionLifespanMs, SessionTimeouts::getUserSessionMaxIdleMs);
if (sessionsRemoteCache != null) {
lastSessionRefreshStore = new CrossDCLastSessionRefreshStoreFactory().createAndInit(session, sessionsCache, false);
}
Cache<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>> clientSessionsCache = ispn.getCache(InfinispanConnectionProvider.CLIENT_SESSION_CACHE_NAME);
checkRemoteCache(session, clientSessionsCache, (RealmModel realm) -> {
// We won't write to the remoteCache during token refresh, so the timeout needs to be longer.
return Time.toMillis(realm.getSsoSessionMaxLifespan());
}, SessionTimeouts::getClientSessionLifespanMs, SessionTimeouts::getClientSessionMaxIdleMs);
checkRemoteCache(session, clientSessionsCache, SessionTimeouts::getClientSessionLifespanMs, SessionTimeouts::getClientSessionMaxIdleMs);
Cache<String, SessionEntityWrapper<UserSessionEntity>> offlineSessionsCache = ispn.getCache(InfinispanConnectionProvider.OFFLINE_USER_SESSION_CACHE_NAME);
RemoteCache offlineSessionsRemoteCache = checkRemoteCache(session, offlineSessionsCache, (RealmModel realm) -> {
return Time.toMillis(realm.getOfflineSessionIdleTimeout());
}, this::deriveOfflineSessionCacheEntryLifespanMs, SessionTimeouts::getOfflineSessionMaxIdleMs);
RemoteCache offlineSessionsRemoteCache = checkRemoteCache(session, offlineSessionsCache, this::deriveOfflineSessionCacheEntryLifespanMs, SessionTimeouts::getOfflineSessionMaxIdleMs);
if (offlineSessionsRemoteCache != null) {
offlineLastSessionRefreshStore = new CrossDCLastSessionRefreshStoreFactory().createAndInit(session, offlineSessionsCache, true);
}
Cache<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>> offlineClientSessionsCache = ispn.getCache(InfinispanConnectionProvider.OFFLINE_CLIENT_SESSION_CACHE_NAME);
checkRemoteCache(session, offlineClientSessionsCache, (RealmModel realm) -> {
return Time.toMillis(realm.getOfflineSessionIdleTimeout());
}, this::deriveOfflineClientSessionCacheEntryLifespanOverrideMs, SessionTimeouts::getOfflineClientSessionMaxIdleMs);
checkRemoteCache(session, offlineClientSessionsCache, this::deriveOfflineClientSessionCacheEntryLifespanOverrideMs, SessionTimeouts::getOfflineClientSessionMaxIdleMs);
}
private <K, V extends SessionEntity> RemoteCache checkRemoteCache(KeycloakSession session, Cache<K, SessionEntityWrapper<V>> ispnCache, RemoteCacheInvoker.MaxIdleTimeLoader maxIdleLoader,
private <K, V extends SessionEntity> RemoteCache checkRemoteCache(KeycloakSession session, Cache<K, SessionEntityWrapper<V>> ispnCache,
SessionFunction<V> lifespanMsLoader, SessionFunction<V> maxIdleTimeMsLoader) {
Set<RemoteStore> remoteStores = InfinispanUtil.getRemoteStores(ispnCache);
@ -363,7 +353,7 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
throw new IllegalStateException("No remote cache available for the infinispan cache: " + ispnCache.getName());
}
remoteCacheInvoker.addRemoteCache(ispnCache.getName(), remoteCache, maxIdleLoader);
remoteCacheInvoker.addRemoteCache(ispnCache.getName(), remoteCache);
Runnable onFailover = null;
if (useCaches && MultiSiteUtils.isPersistentSessionsEnabled()) {

View file

@ -51,12 +51,11 @@ public class RemoteCacheInvoker {
public static final Logger logger = Logger.getLogger(RemoteCacheInvoker.class);
private final Map<String, RemoteCacheContext> remoteCaches = new HashMap<>();
private final Map<String, RemoteCache> remoteCaches = new HashMap<>();
public void addRemoteCache(String cacheName, RemoteCache remoteCache, MaxIdleTimeLoader maxIdleLoader) {
RemoteCacheContext ctx = new RemoteCacheContext(remoteCache, maxIdleLoader);
remoteCaches.put(cacheName, ctx);
public void addRemoteCache(String cacheName, RemoteCache remoteCache) {
remoteCaches.put(cacheName, remoteCache);
}
public Set<String> getRemoteCacheNames() {
@ -65,8 +64,8 @@ public class RemoteCacheInvoker {
public <K, V extends SessionEntity> void runTask(KeycloakSession kcSession, RealmModel realm, String cacheName, K key, MergedUpdate<V> task, SessionEntityWrapper<V> sessionWrapper) {
RemoteCacheContext context = remoteCaches.get(cacheName);
if (context == null) {
RemoteCache remoteCache = remoteCaches.get(cacheName);
if (remoteCache == null) {
return;
}
@ -80,10 +79,7 @@ public class RemoteCacheInvoker {
return;
}
long loadedMaxIdleTimeMs = context.maxIdleTimeLoader.getMaxIdleTimeMs(realm);
// Increase the timeout to ensure that entry won't expire on remoteCache in case that write of some entities to remoteCache is postponed (eg. userSession.lastSessionRefresh)
final long maxIdleTimeMs = loadedMaxIdleTimeMs + 1800000;
long maxIdleTimeMs = getMaxIdleTimeMs(task);
if (logger.isTraceEnabled()) {
logger.tracef("Running task '%s' on remote cache '%s' . Key is '%s'", operation, cacheName, key);
@ -94,7 +90,7 @@ public class RemoteCacheInvoker {
Retry.executeWithBackoff((int iteration) -> {
try {
runOnRemoteCache(topology, context.remoteCache, maxIdleTimeMs, key, task, sessionWrapper);
runOnRemoteCache(topology, remoteCache, maxIdleTimeMs, key, task, sessionWrapper);
} catch (HotRodClientException re) {
if (logger.isDebugEnabled()) {
logger.debugf(re, "Failed running task '%s' on remote cache '%s' . Key: '%s', iteration '%s'. Will try to retry the task",
@ -108,6 +104,14 @@ public class RemoteCacheInvoker {
}, 10, 10);
}
private static <V extends SessionEntity> long getMaxIdleTimeMs(MergedUpdate<V> task) {
long maxIdleTimeMs = task.getMaxIdleTimeMs();
if (maxIdleTimeMs > 0) {
// Increase the timeout to ensure that entry won't expire on remoteCache in case that write of some entities to remoteCache is postponed (eg. userSession.lastSessionRefresh)
maxIdleTimeMs += 1800000;
}
return maxIdleTimeMs;
}
private <K, V extends SessionEntity> void runOnRemoteCache(TopologyInfo topology, RemoteCache<K, SessionEntityWrapper<V>> remoteCache, long maxIdleMs, K key, MergedUpdate<V> task, SessionEntityWrapper<V> sessionWrapper) {
SessionUpdateTask.CacheOperation operation = task.getOperation();
@ -195,27 +199,4 @@ public class RemoteCacheInvoker {
private String logTopologyData(TopologyInfo topology, int iteration) {
return topology.toString() + ", replaceIteration: " + iteration;
}
private static class RemoteCacheContext {
private final RemoteCache remoteCache;
private final MaxIdleTimeLoader maxIdleTimeLoader;
public RemoteCacheContext(RemoteCache remoteCache, MaxIdleTimeLoader maxIdleLoader) {
this.remoteCache = remoteCache;
this.maxIdleTimeLoader = maxIdleLoader;
}
}
@FunctionalInterface
public interface MaxIdleTimeLoader {
long getMaxIdleTimeMs(RealmModel realm);
}
}