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:
parent
03e0fb0601
commit
d9dfe74e8b
3 changed files with 24 additions and 54 deletions
|
@ -135,11 +135,10 @@ public class InfinispanUserLoginFailureProviderFactory implements UserLoginFailu
|
||||||
InfinispanConnectionProvider ispn = session.getProvider(InfinispanConnectionProvider.class);
|
InfinispanConnectionProvider ispn = session.getProvider(InfinispanConnectionProvider.class);
|
||||||
|
|
||||||
Cache<LoginFailureKey, SessionEntityWrapper<LoginFailureEntity>> loginFailuresCache = ispn.getCache(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME);
|
Cache<LoginFailureKey, SessionEntityWrapper<LoginFailureEntity>> loginFailuresCache = ispn.getCache(InfinispanConnectionProvider.LOGIN_FAILURE_CACHE_NAME);
|
||||||
checkRemoteCache(session, loginFailuresCache, (RealmModel realm) ->
|
checkRemoteCache(session, loginFailuresCache, SessionTimeouts::getLoginFailuresLifespanMs, SessionTimeouts::getLoginFailuresMaxIdleMs);
|
||||||
Time.toMillis(realm.getMaxDeltaTimeSeconds()), 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) {
|
SessionFunction<V> lifespanMsLoader, SessionFunction<V> maxIdleTimeMsLoader) {
|
||||||
Set<RemoteStore> remoteStores = InfinispanUtil.getRemoteStores(ispnCache);
|
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());
|
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);
|
RemoteCacheSessionListener hotrodListener = RemoteCacheSessionListener.createListener(session, ispnCache, remoteCache, lifespanMsLoader, maxIdleTimeMsLoader, null);
|
||||||
remoteCache.addClientListener(hotrodListener);
|
remoteCache.addClientListener(hotrodListener);
|
||||||
|
|
|
@ -317,37 +317,27 @@ public class InfinispanUserSessionProviderFactory implements UserSessionProvider
|
||||||
InfinispanConnectionProvider ispn = session.getProvider(InfinispanConnectionProvider.class);
|
InfinispanConnectionProvider ispn = session.getProvider(InfinispanConnectionProvider.class);
|
||||||
|
|
||||||
Cache<String, SessionEntityWrapper<UserSessionEntity>> sessionsCache = ispn.getCache(InfinispanConnectionProvider.USER_SESSION_CACHE_NAME);
|
Cache<String, SessionEntityWrapper<UserSessionEntity>> sessionsCache = ispn.getCache(InfinispanConnectionProvider.USER_SESSION_CACHE_NAME);
|
||||||
RemoteCache sessionsRemoteCache = checkRemoteCache(session, sessionsCache, (RealmModel realm) -> {
|
RemoteCache sessionsRemoteCache = checkRemoteCache(session, sessionsCache, SessionTimeouts::getUserSessionLifespanMs, SessionTimeouts::getUserSessionMaxIdleMs);
|
||||||
// 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);
|
|
||||||
|
|
||||||
if (sessionsRemoteCache != null) {
|
if (sessionsRemoteCache != null) {
|
||||||
lastSessionRefreshStore = new CrossDCLastSessionRefreshStoreFactory().createAndInit(session, sessionsCache, false);
|
lastSessionRefreshStore = new CrossDCLastSessionRefreshStoreFactory().createAndInit(session, sessionsCache, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
Cache<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>> clientSessionsCache = ispn.getCache(InfinispanConnectionProvider.CLIENT_SESSION_CACHE_NAME);
|
Cache<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>> clientSessionsCache = ispn.getCache(InfinispanConnectionProvider.CLIENT_SESSION_CACHE_NAME);
|
||||||
checkRemoteCache(session, clientSessionsCache, (RealmModel realm) -> {
|
checkRemoteCache(session, clientSessionsCache, SessionTimeouts::getClientSessionLifespanMs, SessionTimeouts::getClientSessionMaxIdleMs);
|
||||||
// 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);
|
|
||||||
|
|
||||||
Cache<String, SessionEntityWrapper<UserSessionEntity>> offlineSessionsCache = ispn.getCache(InfinispanConnectionProvider.OFFLINE_USER_SESSION_CACHE_NAME);
|
Cache<String, SessionEntityWrapper<UserSessionEntity>> offlineSessionsCache = ispn.getCache(InfinispanConnectionProvider.OFFLINE_USER_SESSION_CACHE_NAME);
|
||||||
RemoteCache offlineSessionsRemoteCache = checkRemoteCache(session, offlineSessionsCache, (RealmModel realm) -> {
|
RemoteCache offlineSessionsRemoteCache = checkRemoteCache(session, offlineSessionsCache, this::deriveOfflineSessionCacheEntryLifespanMs, SessionTimeouts::getOfflineSessionMaxIdleMs);
|
||||||
return Time.toMillis(realm.getOfflineSessionIdleTimeout());
|
|
||||||
}, this::deriveOfflineSessionCacheEntryLifespanMs, SessionTimeouts::getOfflineSessionMaxIdleMs);
|
|
||||||
|
|
||||||
if (offlineSessionsRemoteCache != null) {
|
if (offlineSessionsRemoteCache != null) {
|
||||||
offlineLastSessionRefreshStore = new CrossDCLastSessionRefreshStoreFactory().createAndInit(session, offlineSessionsCache, true);
|
offlineLastSessionRefreshStore = new CrossDCLastSessionRefreshStoreFactory().createAndInit(session, offlineSessionsCache, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
Cache<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>> offlineClientSessionsCache = ispn.getCache(InfinispanConnectionProvider.OFFLINE_CLIENT_SESSION_CACHE_NAME);
|
Cache<UUID, SessionEntityWrapper<AuthenticatedClientSessionEntity>> offlineClientSessionsCache = ispn.getCache(InfinispanConnectionProvider.OFFLINE_CLIENT_SESSION_CACHE_NAME);
|
||||||
checkRemoteCache(session, offlineClientSessionsCache, (RealmModel realm) -> {
|
checkRemoteCache(session, offlineClientSessionsCache, this::deriveOfflineClientSessionCacheEntryLifespanOverrideMs, SessionTimeouts::getOfflineClientSessionMaxIdleMs);
|
||||||
return Time.toMillis(realm.getOfflineSessionIdleTimeout());
|
|
||||||
}, 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) {
|
SessionFunction<V> lifespanMsLoader, SessionFunction<V> maxIdleTimeMsLoader) {
|
||||||
Set<RemoteStore> remoteStores = InfinispanUtil.getRemoteStores(ispnCache);
|
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());
|
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;
|
Runnable onFailover = null;
|
||||||
if (useCaches && MultiSiteUtils.isPersistentSessionsEnabled()) {
|
if (useCaches && MultiSiteUtils.isPersistentSessionsEnabled()) {
|
||||||
|
|
|
@ -51,12 +51,11 @@ public class RemoteCacheInvoker {
|
||||||
|
|
||||||
public static final Logger logger = Logger.getLogger(RemoteCacheInvoker.class);
|
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) {
|
public void addRemoteCache(String cacheName, RemoteCache remoteCache) {
|
||||||
RemoteCacheContext ctx = new RemoteCacheContext(remoteCache, maxIdleLoader);
|
remoteCaches.put(cacheName, remoteCache);
|
||||||
remoteCaches.put(cacheName, ctx);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Set<String> getRemoteCacheNames() {
|
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) {
|
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);
|
RemoteCache remoteCache = remoteCaches.get(cacheName);
|
||||||
if (context == null) {
|
if (remoteCache == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,10 +79,7 @@ public class RemoteCacheInvoker {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
long loadedMaxIdleTimeMs = context.maxIdleTimeLoader.getMaxIdleTimeMs(realm);
|
long maxIdleTimeMs = getMaxIdleTimeMs(task);
|
||||||
|
|
||||||
// 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;
|
|
||||||
|
|
||||||
if (logger.isTraceEnabled()) {
|
if (logger.isTraceEnabled()) {
|
||||||
logger.tracef("Running task '%s' on remote cache '%s' . Key is '%s'", operation, cacheName, key);
|
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) -> {
|
Retry.executeWithBackoff((int iteration) -> {
|
||||||
|
|
||||||
try {
|
try {
|
||||||
runOnRemoteCache(topology, context.remoteCache, maxIdleTimeMs, key, task, sessionWrapper);
|
runOnRemoteCache(topology, remoteCache, maxIdleTimeMs, key, task, sessionWrapper);
|
||||||
} catch (HotRodClientException re) {
|
} catch (HotRodClientException re) {
|
||||||
if (logger.isDebugEnabled()) {
|
if (logger.isDebugEnabled()) {
|
||||||
logger.debugf(re, "Failed running task '%s' on remote cache '%s' . Key: '%s', iteration '%s'. Will try to retry the task",
|
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);
|
}, 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) {
|
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();
|
SessionUpdateTask.CacheOperation operation = task.getOperation();
|
||||||
|
@ -195,27 +199,4 @@ public class RemoteCacheInvoker {
|
||||||
private String logTopologyData(TopologyInfo topology, int iteration) {
|
private String logTopologyData(TopologyInfo topology, int iteration) {
|
||||||
return topology.toString() + ", replaceIteration: " + 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);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue