Align startup of Quarkus with the regular startup to ensure boostrap locks are created.

Also fixing an issue where DBLockGlobalLockProviderFactory held on to an old session, which lead to a closed DB connection on Quarkus.

Closes #16642
This commit is contained in:
Alexander Schwartz 2023-01-27 10:23:08 +01:00 committed by Michal Hajas
parent eebbeb26bc
commit 7933f0489d
5 changed files with 17 additions and 25 deletions

View file

@ -40,7 +40,7 @@ public class LiquibaseDBLockProvider implements DBLockProvider {
private static final Logger logger = Logger.getLogger(LiquibaseDBLockProvider.class); private static final Logger logger = Logger.getLogger(LiquibaseDBLockProvider.class);
// 10 should be sufficient // 10 should be sufficient
private int DEFAULT_MAX_ATTEMPTS = 10; private final int DEFAULT_MAX_ATTEMPTS = 10;
private final LiquibaseDBLockProviderFactory factory; private final LiquibaseDBLockProviderFactory factory;
@ -83,9 +83,6 @@ public class LiquibaseDBLockProvider implements DBLockProvider {
// Assumed transaction was rolled-back and we want to start with new DB connection // Assumed transaction was rolled-back and we want to start with new DB connection
private void restart() { private void restart() {
safeCloseConnection(); safeCloseConnection();
this.dbConnection = null;
this.lockService = null;
initialized = false;
lazyInit(); lazyInit();
} }
@ -187,6 +184,9 @@ public class LiquibaseDBLockProvider implements DBLockProvider {
if (dbConnection != null) { if (dbConnection != null) {
try { try {
dbConnection.close(); dbConnection.close();
dbConnection = null;
lockService = null;
initialized = false;
} catch (SQLException e) { } catch (SQLException e) {
logger.warn("Failed to close connection", e); logger.warn("Failed to close connection", e);
} }

View file

@ -21,7 +21,6 @@ import org.jboss.logging.Logger;
import org.keycloak.models.KeycloakSession; import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionTaskWithResult; import org.keycloak.models.KeycloakSessionTaskWithResult;
import org.keycloak.models.locking.GlobalLockProvider; import org.keycloak.models.locking.GlobalLockProvider;
import org.keycloak.models.utils.KeycloakModelUtils;
import java.time.Duration; import java.time.Duration;
import java.util.Objects; import java.util.Objects;
@ -69,8 +68,12 @@ public class DBLockGlobalLockProvider implements GlobalLockProvider {
LOG.debug("DBLockGlobalLockProvider does not support setting timeToWaitForLock per lock."); LOG.debug("DBLockGlobalLockProvider does not support setting timeToWaitForLock per lock.");
} }
try { if (dbLockProvider.getCurrentLock() != null) {
throw new IllegalStateException("this lock is not reentrant, already locked for " + dbLockProvider.getCurrentLock());
}
dbLockProvider.waitForLock(stringToNamespace(lockName)); dbLockProvider.waitForLock(stringToNamespace(lockName));
try {
return task.run(session); return task.run(session);
} finally { } finally {
releaseLock(lockName); releaseLock(lockName);

View file

@ -28,15 +28,11 @@ import org.keycloak.provider.EnvironmentDependentProviderFactory;
public class DBLockGlobalLockProviderFactory implements GlobalLockProviderFactory, EnvironmentDependentProviderFactory { public class DBLockGlobalLockProviderFactory implements GlobalLockProviderFactory, EnvironmentDependentProviderFactory {
public static final String PROVIDER_ID = "dblock"; public static final String PROVIDER_ID = "dblock";
private DBLockManager dbLockManager;
@Override @Override
public GlobalLockProvider create(KeycloakSession session) { public GlobalLockProvider create(KeycloakSession session) {
if (dbLockManager == null) { DBLockManager dbLockManager = new DBLockManager(session);
dbLockManager = new DBLockManager(session);
dbLockManager.checkForcedUnlock(); dbLockManager.checkForcedUnlock();
}
return new DBLockGlobalLockProvider(session, dbLockManager.getDBLock()); return new DBLockGlobalLockProvider(session, dbLockManager.getDBLock());
} }

View file

@ -21,8 +21,8 @@ import java.util.Set;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import javax.ws.rs.ApplicationPath; import javax.ws.rs.ApplicationPath;
import org.keycloak.exportimport.ExportImportManager;
import org.keycloak.models.utils.PostMigrationEvent; import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.quarkus.runtime.integration.QuarkusKeycloakSessionFactory; import org.keycloak.quarkus.runtime.integration.QuarkusKeycloakSessionFactory;
import org.keycloak.services.resources.KeycloakApplication; import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.quarkus.runtime.services.resources.QuarkusWelcomeResource; import org.keycloak.quarkus.runtime.services.resources.QuarkusWelcomeResource;
@ -36,17 +36,10 @@ public class QuarkusKeycloakApplication extends KeycloakApplication {
} }
@Override @Override
protected void startup() { public KeycloakSessionFactory createSessionFactory() {
QuarkusKeycloakSessionFactory instance = QuarkusKeycloakSessionFactory.getInstance(); QuarkusKeycloakSessionFactory instance = QuarkusKeycloakSessionFactory.getInstance();
sessionFactory = instance;
instance.init(); instance.init();
ExportImportManager exportImportManager = bootstrap(); return instance;
if (exportImportManager.isRunExport()) {
exportImportManager.runExport();
}
sessionFactory.publish(new PostMigrationEvent(sessionFactory));
} }
@Override @Override

View file

@ -82,7 +82,7 @@ public class KeycloakApplication extends Application {
protected Set<Object> singletons = new HashSet<>(); protected Set<Object> singletons = new HashSet<>();
protected Set<Class<?>> classes = new HashSet<>(); protected Set<Class<?>> classes = new HashSet<>();
protected static KeycloakSessionFactory sessionFactory; private static KeycloakSessionFactory sessionFactory;
public KeycloakApplication() { public KeycloakApplication() {
@ -237,7 +237,7 @@ public class KeycloakApplication extends Application {
} }
public static KeycloakSessionFactory createSessionFactory() { protected KeycloakSessionFactory createSessionFactory() {
DefaultKeycloakSessionFactory factory = new DefaultKeycloakSessionFactory(); DefaultKeycloakSessionFactory factory = new DefaultKeycloakSessionFactory();
factory.init(); factory.init();
return factory; return factory;