I have deployed an Stateful EJB 3 on Wildfly that participates in a JTA transaction. This EJB is an extension User provider for Keycloak.
One of the EJB operations is invoked at some point and could produce a RuntimeException. I need the global transaction to commit so I added a try-catch block in the ejb method.
@Stateful
@Local(EjbUserStorageProvider.class)
public class EjbUserStorageProvider implements UserStorageProvider,
UserLookupProvider,
UserRegistrationProvider,
UserQueryProvider,
CredentialInputUpdater,
CredentialInputValidator,
OnUserCache
{
...
@Override
public int getUsersCount(RealmModel realm) {
try {
Object count = em.createNamedQuery("getUserCount").getSingleResult();
return ((Number)count).intValue();
} catch(RuntimeException e) {
e.printStackTrace();
return 0;
}
}
}
The problem is that, despite capturing the exception, the transaction is rolledback.
This is the problematic bit:
org.keycloak.models.utils.KeycloakModelUtils
public static void runJobInTransaction(KeycloakSessionFactory factory, KeycloakSessionTask task) {
KeycloakSession session = factory.create();
KeycloakTransaction tx = session.getTransactionManager();
try {
tx.begin();
task.run(session);
if (tx.isActive()) {
if (tx.getRollbackOnly()) {
tx.rollback();
} else {
tx.commit();
}
}
} catch (RuntimeException re) {
if (tx.isActive()) {
tx.rollback();
}
throw re;
} finally {
session.close();
}
}
For some reason tx.getRollbackOnly()
returns true so the JTA transaction is rolledback.
How could I prevent the transaction from being marked as rollback only?
UPDATE
I tried using @Transactional but was ignored:
@Transactional(value = Transactional.TxType.NEVER, dontRollbackOn = {RuntimeException.class, PersistenceException.class})
@Override
public int getUsersCount(RealmModel realm) {
I also used @TransactionAttribute(NOT_SUPPORTED)
but in this case Keycloak can't start:
09:36:30,784 ERROR [org.jboss.as.ejb3.invocation] (ServerService Thread Pool -- 51) WFLYEJB0034: EJB Invocation failed on component EjbUserStorageProvider for method public int es.mma.edm.keycloak.storage.user.EjbUserStorageProvider.getUsersCount(org.keycloak.models.RealmModel): javax.ejb.ConcurrentAccessTimeoutException: WFLYEJB0228: EJB 3.1 FR 4.3.14.1 concurrent access timeout on EjbUserStorageProvider - could not obtain lock within 5000 MILLISECONDS
at [email protected]//org.jboss.as.ejb3.component.stateful.StatefulSessionSynchronizationInterceptor.processInvocation(StatefulSessionSynchronizationInterceptor.java:94)
at [email protected]//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at [email protected]//org.jboss.as.ee.concurrent.ConcurrentContextInterceptor.processInvocation(ConcurrentContextInterceptor.java:45)
at [email protected]//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at [email protected]//org.jboss.invocation.InitialInterceptor.processInvocation(InitialInterceptor.java:40)
at [email protected]//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at [email protected]//org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:53)
at [email protected]//org.jboss.as.ee.component.interceptors.ComponentDispatcherInterceptor.processInvocation(ComponentDispatcherInterceptor.java:52)
at [email protected]//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at [email protected]//org.jboss.as.ejb3.component.stateful.StatefulComponentInstanceInterceptor.processInvocation(StatefulComponentInstanceInterceptor.java:59)
at [email protected]//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at [email protected]//org.jboss.as.ejb3.component.interceptors.AdditionalSetupInterceptor.processInvocation(AdditionalSetupInterceptor.java:54)
at [email protected]//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at [email protected]//org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInNoTx(CMTTxInterceptor.java:216)
at [email protected]//org.jboss.as.ejb3.tx.CMTTxInterceptor.notSupported(CMTTxInterceptor.java:337)
at [email protected]//org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:142)
at [email protected]//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at [email protected]//org.jboss.as.ejb3.component.interceptors.CurrentInvocationContextInterceptor.processInvocation(CurrentInvocationContextInterceptor.java:41)
at [email protected]//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at [email protected]//org.jboss.as.ejb3.component.invocationmetrics.WaitTimeInterceptor.processInvocation(WaitTimeInterceptor.java:47)
at [email protected]//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at [email protected]//org.jboss.as.ejb3.security.SecurityContextInterceptor.processInvocation(SecurityContextInterceptor.java:100)
at [email protected]//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at [email protected]//org.jboss.as.ejb3.deployment.processors.StartupAwaitInterceptor.processInvocation(StartupAwaitInterceptor.java:22)
at [email protected]//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at [email protected]//org.jboss.as.ejb3.component.interceptors.ShutDownInterceptorFactory$1.processInvocation(ShutDownInterceptorFactory.java:64)
at [email protected]//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at [email protected]//org.jboss.as.ejb3.component.interceptors.LoggingInterceptor.processInvocation(LoggingInterceptor.java:67)
at [email protected]//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at [email protected]//org.jboss.as.ee.component.NamespaceContextInterceptor.processInvocation(NamespaceContextInterceptor.java:50)
at [email protected]//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at [email protected]//org.jboss.invocation.ContextClassLoaderInterceptor.processInvocation(ContextClassLoaderInterceptor.java:60)
at [email protected]//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at [email protected]//org.jboss.invocation.InterceptorContext.run(InterceptorContext.java:438)
at [email protected]//org.wildfly.security.manager.WildFlySecurityManager.doChecked(WildFlySecurityManager.java:619)
at [email protected]//org.jboss.invocation.AccessCheckingInterceptor.processInvocation(AccessCheckingInterceptor.java:57)
at [email protected]//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at [email protected]//org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:53)
at [email protected]//org.jboss.as.ee.component.ViewService$View.invoke(ViewService.java:198)
at [email protected]//org.jboss.as.ee.component.ViewDescription$1.processInvocation(ViewDescription.java:185)
at [email protected]//org.jboss.as.ee.component.ProxyInvocationHandler.invoke(ProxyInvocationHandler.java:81)
at deployment.edm-keycloak-user-storage.jar//es.mma.edm.keycloak.storage.user.EjbUserStorageProvider$$$view1.getUsersCount(Unknown Source)
at [email protected]//org.keycloak.storage.UserStorageManager.getUsersCount(UserStorageManager.java:453)
at [email protected]//org.keycloak.models.cache.infinispan.UserCacheSession.getUsersCount(UserCacheSession.java:543)
at [email protected]//org.keycloak.models.cache.infinispan.UserCacheSession.getUsersCount(UserCacheSession.java:548)
at [email protected]//org.keycloak.services.managers.ApplianceBootstrap.isNoMasterUser(ApplianceBootstrap.java:55)
at [email protected]//org.keycloak.services.resources.KeycloakApplication$2.run(KeycloakApplication.java:168)
at org.keycloak.keycloak-server-spi-private@4.8.3.Final-redhat-00001//org.keycloak.models.utils.KeycloakModelUtils.runJobInTransaction(KeycloakModelUtils.java:227)
at [email protected]//org.keycloak.services.resources.KeycloakApplication.<init>(KeycloakApplication.java:164)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at java.base/jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
at java.base/jdk.internal.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:490)
at [email protected]//org.jboss.resteasy.core.ConstructorInjectorImpl.construct(ConstructorInjectorImpl.java:154)
at [email protected]//org.jboss.resteasy.spi.ResteasyProviderFactory.createProviderInstance(ResteasyProviderFactory.java:2757)
at [email protected]//org.jboss.resteasy.spi.ResteasyDeployment.createApplication(ResteasyDeployment.java:363)
at [email protected]//org.jboss.resteasy.spi.ResteasyDeployment.startInternal(ResteasyDeployment.java:276)
at [email protected]//org.jboss.resteasy.spi.ResteasyDeployment.start(ResteasyDeployment.java:88)
at [email protected]//org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.init(ServletContainerDispatcher.java:119)
at [email protected]//org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.init(HttpServletDispatcher.java:36)
at [email protected]//io.undertow.servlet.core.LifecyleInterceptorInvocation.proceed(LifecyleInterceptorInvocation.java:117)
at [email protected]//org.wildfly.extension.undertow.secu
与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…