Use separate transactions for each bulk update of offline sessions in PersisterLastSessionRefreshStore to avoid deadlocks
closes #13684
This commit is contained in:
parent
2002fd983b
commit
254483bc5d
1 changed files with 12 additions and 10 deletions
|
@ -19,6 +19,7 @@ package org.keycloak.models.sessions.infinispan.changes.sessions;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
import java.util.TreeSet;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import org.jboss.logging.Logger;
|
import org.jboss.logging.Logger;
|
||||||
|
@ -26,6 +27,7 @@ import org.keycloak.common.util.Time;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.session.UserSessionPersisterProvider;
|
import org.keycloak.models.session.UserSessionPersisterProvider;
|
||||||
|
import org.keycloak.models.utils.KeycloakModelUtils;
|
||||||
import org.keycloak.models.utils.SessionTimeoutHelper;
|
import org.keycloak.models.utils.SessionTimeoutHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,19 +61,19 @@ public class PersisterLastSessionRefreshStore extends AbstractLastSessionRefresh
|
||||||
logger.debugf("Updating %d userSessions with lastSessionRefresh: %d", refreshesToSend.size(), lastSessionRefresh);
|
logger.debugf("Updating %d userSessions with lastSessionRefresh: %d", refreshesToSend.size(), lastSessionRefresh);
|
||||||
}
|
}
|
||||||
|
|
||||||
UserSessionPersisterProvider persister = kcSession.getProvider(UserSessionPersisterProvider.class);
|
// Separate transaction for each bulk update request to avoid deadlocks
|
||||||
|
|
||||||
for (Map.Entry<String, Set<String>> entry : sessionIdsByRealm.entrySet()) {
|
for (Map.Entry<String, Set<String>> entry : sessionIdsByRealm.entrySet()) {
|
||||||
RealmModel realm = kcSession.realms().getRealm(entry.getKey());
|
KeycloakModelUtils.runJobInTransaction(kcSession.getKeycloakSessionFactory(), (kcSession2) -> {
|
||||||
|
UserSessionPersisterProvider persister = kcSession2.getProvider(UserSessionPersisterProvider.class);
|
||||||
|
RealmModel realm = kcSession2.realms().getRealm(entry.getKey());
|
||||||
|
|
||||||
// Case when realm was deleted in the meantime. UserSessions were already deleted as well (callback for realm deletion)
|
// If realm is null, it means that realm was deleted in the meantime. UserSessions were already deleted as well (callback for realm deletion)
|
||||||
if (realm == null) {
|
if (realm != null) {
|
||||||
continue;
|
Set<String> userSessionIds = new TreeSet<>(entry.getValue());
|
||||||
}
|
|
||||||
|
|
||||||
Set<String> userSessionIds = entry.getValue();
|
|
||||||
|
|
||||||
persister.updateLastSessionRefreshes(realm, lastSessionRefresh, userSessionIds, offline);
|
persister.updateLastSessionRefreshes(realm, lastSessionRefresh, userSessionIds, offline);
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue