Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to read RoutingContext from CustomTenantResolver #44168

Open
amustafa91 opened this issue Oct 29, 2024 · 19 comments · May be fixed by #44547
Open

Unable to read RoutingContext from CustomTenantResolver #44168

amustafa91 opened this issue Oct 29, 2024 · 19 comments · May be fixed by #44547
Labels
area/hibernate-orm Hibernate ORM area/security kind/enhancement New feature or request triage/needs-reproducer We are waiting for a reproducer.

Comments

@amustafa91
Copy link

amustafa91 commented Oct 29, 2024

Describe the bug

I am trying to read the tenant from RoutingContext, to resolve the database connection based on tenantId, but getting this error

jakarta.enterprise.inject.IllegalProductException: Normal scoped producer method may not return null: io.quarkus.vertx.http.runtime.CurrentVertxRequest.getCurrent()       
        at io.quarkus.vertx.http.runtime.CurrentVertxRequest_ProducerMethod_getCurrent_6dc23d16d53ba5c34e1e7b6f54290fd7b9aebd76_Bean.doCreate(Unknown Source)
        at io.quarkus.vertx.http.runtime.CurrentVertxRequest_ProducerMethod_getCurrent_6dc23d16d53ba5c34e1e7b6f54290fd7b9aebd76_Bean.create(Unknown Source)
        at io.quarkus.vertx.http.runtime.CurrentVertxRequest_ProducerMethod_getCurrent_6dc23d16d53ba5c34e1e7b6f54290fd7b9aebd76_Bean.create(Unknown Source)
        at io.quarkus.arc.impl.RequestContext.getIfActive(RequestContext.java:74)
        at io.quarkus.arc.impl.ClientProxies.getDelegate(ClientProxies.java:30)
        at io.vertx.ext.web.CurrentVertxRequest_ProducerMethod_getCurrent_6dc23d16d53ba5c34e1e7b6f54290fd7b9aebd76_ClientProxy.arc$delegate(Unknown Source)
        at io.vertx.ext.web.CurrentVertxRequest_ProducerMethod_getCurrent_6dc23d16d53ba5c34e1e7b6f54290fd7b9aebd76_ClientProxy.get(Unknown Source)
        at org.acme.project.solver.CustomTenantResolver.resolveTenantId(CustomTenantResolver.java:23)
        at org.acme.project.solver.CustomTenantResolver_ClientProxy.resolveTenantId(Unknown Source)
        at io.quarkus.hibernate.orm.runtime.tenant.HibernateCurrentTenantIdentifierResolver.resolveCurrentTenantIdentifier(HibernateCurrentTenantIdentifierResolver.java:37)
        at org.hibernate.internal.SessionFactoryImpl$SessionBuilderImpl.<init>(SessionFactoryImpl.java:1211)
        at org.hibernate.internal.SessionFactoryImpl.withOptions(SessionFactoryImpl.java:607)
        at org.hibernate.internal.SessionFactoryImpl.openSession(SessionFactoryImpl.java:583)
        at org.hibernate.internal.SessionFactoryImpl.openSession(SessionFactoryImpl.java:154)
        at io.quarkus.hibernate.orm.runtime.RequestScopedSessionHolder.lambda$getOrCreateSession$0(RequestScopedSessionHolder.java:21)
        at java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1220)
        at io.quarkus.hibernate.orm.runtime.RequestScopedSessionHolder.getOrCreateSession(RequestScopedSessionHolder.java:21)
        at io.quarkus.hibernate.orm.runtime.RequestScopedSessionHolder_ClientProxy.getOrCreateSession(Unknown Source)
        at io.quarkus.hibernate.orm.runtime.session.TransactionScopedSession.acquireSession(TransactionScopedSession.java:104)
        at io.quarkus.hibernate.orm.runtime.session.TransactionScopedSession.createQuery(TransactionScopedSession.java:366)



        at org.hibernate.engine.spi.SessionLazyDelegator.createQuery(SessionLazyDelegator.java:548)
        at org.hibernate.engine.spi.SessionLazyDelegator.createQuery(SessionLazyDelegator.java:66)
        at org.hibernate.Session_3a974b6a18ac399f675913d732c105426414d370_Synthetic_ClientProxy.createQuery(Unknown Source)
        at io.quarkus.hibernate.orm.panache.common.runtime.CommonPanacheQueryImpl.createBaseQuery(CommonPanacheQueryImpl.java:353)
        at io.quarkus.hibernate.orm.panache.common.runtime.CommonPanacheQueryImpl.createQuery(CommonPanacheQueryImpl.java:315)
        at io.quarkus.hibernate.orm.panache.common.runtime.CommonPanacheQueryImpl.list(CommonPanacheQueryImpl.java:266)
        at io.quarkus.hibernate.orm.panache.runtime.PanacheQueryImpl.list(PanacheQueryImpl.java:149)
        at org.acme.project.solver.CacheResolver.refreshCache(CacheResolver.java:22)
        at org.acme.project.solver.AppLifecycleBean.onStart(AppLifecycleBean.java:16)
        at org.acme.project.solver.AppLifecycleBean_Observer_onStart_a58341e9b5ff8692203684dfc1ea68ef736fee23.notify(Unknown Source)
        at io.quarkus.arc.impl.EventImpl$Notifier.notifyObservers(EventImpl.java:346)
        at io.quarkus.arc.impl.EventImpl$Notifier.notify(EventImpl.java:328)
        at io.quarkus.arc.impl.EventImpl.fire(EventImpl.java:82)
        at io.quarkus.arc.runtime.ArcRecorder.fireLifecycleEvent(ArcRecorder.java:155)
        at io.quarkus.arc.runtime.ArcRecorder.handleLifecycleEvents(ArcRecorder.java:106)
        at io.quarkus.deployment.steps.LifecycleEventsBuildStep$startupEvent1144526294.deploy_0(Unknown Source)
        at io.quarkus.deployment.steps.LifecycleEventsBuildStep$startupEvent1144526294.deploy(Unknown Source)
        ... 13 more 

Expected behavior

Read RoutingContext keys from CustomTenantResolver

Actual behavior

Getting jakarta.enterprise.inject.IllegalProductException: Normal scoped producer method may not return null: io.quarkus.vertx.http.runtime.CurrentVertxRequest.getCurrent()

How to Reproduce?

import io.quarkus.hibernate.orm.PersistenceUnitExtension;
import io.quarkus.hibernate.orm.runtime.tenant.TenantResolver;
import io.vertx.ext.web.RoutingContext;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;

@PersistenceUnitExtension
@RequestScoped
public class CustomTenantResolver implements TenantResolver {

    @Inject
    RoutingContext context;

    @Override
    public String getDefaultTenantId() {
        return "default";
    }

    @Override
    public String resolveTenantId() {
        return context.get("tenantId");
    }
}

Setting the tenant Id in my OIDC resolver

import org.eclipse.microprofile.config.ConfigProvider;
import io.smallrye.mutiny.Uni;
import io.quarkus.oidc.OidcRequestContext;
import io.quarkus.oidc.OidcTenantConfig;
import io.quarkus.oidc.TenantConfigResolver;
import io.vertx.ext.web.RoutingContext;
import io.vertx.mutiny.core.Vertx;

@ApplicationScoped
public class CustomTenantOIDCResolver implements TenantConfigResolver {

    @Inject
    Vertx vertx;

    @Override
    public Uni<OidcTenantConfig> resolve(RoutingContext context, OidcRequestContext<OidcTenantConfig> requestContext) {
        String path = context.request().path();
        String[] parts = path.split("/");

        if (parts.length == 0) {
            // Resolve to default tenant configuration
            return null;
        }

        if (parts.length > 1) {
            return Uni.createFrom().item(createTenantConfig(parts[1], context));
        }

        // Resolve to default tenant configuration
        return null;
    }

    private Supplier<OidcTenantConfig> createTenantConfig(String clientId, RoutingContext context) {
        final OidcTenantConfig config = new OidcTenantConfig();
        List<Tenant> tenants = CacheResolver.tenants;
        tenants.stream().filter(t -> t.getFrontendClientId().equals(clientId)).findFirst().ifPresent(t -> {
            config.setTenantId(clientId);
            String authServer = ConfigProvider.getConfig().getValue("quarkus.oidc.auth-server-url", String.class);
            String baseAuthServer = authServer.substring(0, authServer.lastIndexOf("/"));
            config.setAuthServerUrl(baseAuthServer + "/" + clientId);
            config.setClientId(t.getBackendClientId());
            OidcTenantConfig.Credentials credentials = new OidcTenantConfig.Credentials();
            credentials.setSecret(t.getSecretId());
            config.setCredentials(credentials);
            context.put("clientId", config.getClientId().get());
            context.put("tenantId", config.getTenantId().get());
        });
        return () -> config;
    }

}

My database connection resolver

import io.agroal.api.AgroalDataSource;
import io.agroal.api.configuration.supplier.AgroalConnectionFactoryConfigurationSupplier;
import io.agroal.api.configuration.supplier.AgroalConnectionPoolConfigurationSupplier;
import io.agroal.api.configuration.supplier.AgroalDataSourceConfigurationSupplier;
import io.agroal.api.security.NamePrincipal;
import io.agroal.api.security.SimplePassword;
import io.quarkus.hibernate.orm.PersistenceUnitExtension;
import io.quarkus.hibernate.orm.runtime.customized.QuarkusConnectionProvider;
import io.quarkus.hibernate.orm.runtime.tenant.TenantConnectionResolver;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.context.control.ActivateRequestContext;
import org.eclipse.microprofile.config.inject.ConfigProperty;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;

import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;

@ApplicationScoped
@ActivateRequestContext
@PersistenceUnitExtension
public class DataSourceTenantConnectionResolver implements TenantConnectionResolver {
    // @Inject
    // Instance<RoutingContext> contextInstance;

    @ConfigProperty(name = "quarkus.datasource.jdbc.url")
    String url;
    @ConfigProperty(name = "quarkus.datasource.username")
    String username;
    @ConfigProperty(name = "quarkus.datasource.password")
    String password;
    private final Map<String, ConnectionProvider> map = new HashMap<>();

    @Override
    public ConnectionProvider resolve(String tenantId) {
        System.out.println("resolve ConnectionProvider " + tenantId);
        if (map.containsKey(tenantId)) {
            return map.get(tenantId);
        }
        ConnectionProvider provider;
        provider = new QuarkusConnectionProvider(createDataSource(url, "mydb", username, password));
        map.put(tenantId, provider);
        return provider;
    }

    private AgroalDataSource createDataSource(
            String url, String database, String username, String password) {
        try {
            AgroalDataSourceConfigurationSupplier configurationSupplier = new AgroalDataSourceConfigurationSupplier();
            AgroalConnectionPoolConfigurationSupplier connectionPoolConfig = configurationSupplier
                    .connectionPoolConfiguration();
            connectionPoolConfig.maxSize(1000);

            AgroalConnectionFactoryConfigurationSupplier connectionFactoryConfig = connectionPoolConfig
                    .connectionFactoryConfiguration();
            connectionFactoryConfig.jdbcUrl(url);
            connectionFactoryConfig.principal(new NamePrincipal(username));
            connectionFactoryConfig.credential(new SimplePassword(password));

            return AgroalDataSource.from(configurationSupplier.get());
        } catch (SQLException | RuntimeException e) {
            throw new IllegalStateException("Exception while creating datasource for " + url, e);
        }
    }
}

Output of uname -a or ver

No response

Output of java -version

No response

Quarkus version or git rev

No response

Build tool (ie. output of mvnw --version or gradlew --version)

No response

Additional information

I tried every solution on Internet with no luck

@amustafa91 amustafa91 added the kind/bug Something isn't working label Oct 29, 2024
@geoand
Copy link
Contributor

geoand commented Oct 30, 2024

My assumption is that what's going on here is that there is no active web request, but I'll leave it to the SMEs. @yrodiere and @sberyozkin

@amustafa91
Copy link
Author

amustafa91 commented Oct 30, 2024

It's not working on both, runtime and on request

I am running this code on Quarkus 3.0

and unfortunately, I am unable to upgrade to the latest version as I am using Optaplanner

@geoand
Copy link
Contributor

geoand commented Oct 30, 2024

I am running this code on Quarkus 3.0

This version is very old and it completely unsupported at this point.

I am unable to upgrade to the latest version as I am using Optaplanner

Optaplanner does not work with newer versions of Quarkus?

@amustafa91
Copy link
Author

amustafa91 commented Oct 30, 2024

Optaplanner does not work with newer versions of Quarkus?

when I upgrade to quarkus 3.15.1 I get this error, also I am running the latest version of Optaplanner 9.44

here's the error

2024-10-30 16:40:17,515 ERROR [io.qua.dep.dev.IsolatedDevModeMain] (main) Failed to start quarkus: java.lang.NoClassDefFoundError: io/quarkus/devconsole/spi/DevConsoleRouteBuildItem
        at java.base/java.lang.Class.forName0(Native Method)
        at java.base/java.lang.Class.forName(Class.java:467)
        at io.quarkus.deployment.util.ServiceUtil.classesNamedIn(ServiceUtil.java:30)
        at io.quarkus.deployment.ExtensionLoader.loadStepsFrom(ExtensionLoader.java:165)
        at io.quarkus.deployment.QuarkusAugmentor.run(QuarkusAugmentor.java:107)
        at io.quarkus.runner.bootstrap.AugmentActionImpl.runAugment(AugmentActionImpl.java:350)
        at io.quarkus.runner.bootstrap.AugmentActionImpl.createInitialRuntimeApplication(AugmentActionImpl.java:272)
        at io.quarkus.runner.bootstrap.AugmentActionImpl.createInitialRuntimeApplication(AugmentActionImpl.java:62)
        at io.quarkus.deployment.dev.IsolatedDevModeMain.firstStart(IsolatedDevModeMain.java:91)
        at io.quarkus.deployment.dev.IsolatedDevModeMain.accept(IsolatedDevModeMain.java:430)
        at io.quarkus.deployment.dev.IsolatedDevModeMain.accept(IsolatedDevModeMain.java:57)
        at io.quarkus.bootstrap.app.CuratedApplication.runInCl(CuratedApplication.java:138)
        at io.quarkus.bootstrap.app.CuratedApplication.runInAugmentClassLoader(CuratedApplication.java:93)
        at io.quarkus.deployment.dev.DevModeMain.start(DevModeMain.java:131)
        at io.quarkus.deployment.dev.DevModeMain.main(DevModeMain.java:62)
Caused by: java.lang.ClassNotFoundException: io.quarkus.devconsole.spi.DevConsoleRouteBuildItem
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:520)
        at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:533)
        at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:481)
        ... 15 more

@geoand
Copy link
Contributor

geoand commented Oct 30, 2024

And there is no newer version of Optaplanner?

@amustafa91
Copy link
Author

amustafa91 commented Oct 30, 2024

I have the latest version of Optaplanner, it's 9.44
I tried to install clean Quarkus instance, with latest version of Optaplanner and now I am getting the below error (I got this error before some weeks when I tried to upgrade)

java.lang.RuntimeException: Failed to load steps from class org.optaplanner.quarkus.deployment.OptaPlannerProcessor
        at io.quarkus.deployment.ExtensionLoader.loadStepsFrom(ExtensionLoader.java:169)
        at io.quarkus.deployment.QuarkusAugmentor.run(QuarkusAugmentor.java:107)
        at io.quarkus.runner.bootstrap.AugmentActionImpl.runAugment(AugmentActionImpl.java:350)
        at io.quarkus.runner.bootstrap.AugmentActionImpl.createInitialRuntimeApplication(AugmentActionImpl.java:272)
        at io.quarkus.runner.bootstrap.AugmentActionImpl.createInitialRuntimeApplication(AugmentActionImpl.java:62)
        at io.quarkus.deployment.dev.IsolatedDevModeMain.firstStart(IsolatedDevModeMain.java:89)
        at io.quarkus.deployment.dev.IsolatedDevModeMain.accept(IsolatedDevModeMain.java:428)
        at io.quarkus.deployment.dev.IsolatedDevModeMain.accept(IsolatedDevModeMain.java:55)
        at io.quarkus.bootstrap.app.CuratedApplication.runInCl(CuratedApplication.java:138)
        at io.quarkus.bootstrap.app.CuratedApplication.runInAugmentClassLoader(CuratedApplication.java:93)
        at io.quarkus.deployment.dev.DevModeMain.start(DevModeMain.java:131)
        at io.quarkus.deployment.dev.DevModeMain.main(DevModeMain.java:62)
Caused by: java.lang.NoClassDefFoundError: io/quarkus/devconsole/spi/DevConsoleRuntimeTemplateInfoBuildItem
        at java.base/java.lang.Class.getDeclaredMethods0(Native Method)
        at java.base/java.lang.Class.privateGetDeclaredMethods(Class.java:3578)
        at java.base/java.lang.Class.getDeclaredMethods(Class.java:2676)
        at io.quarkus.deployment.ExtensionLoader.getMethods(ExtensionLoader.java:934)
        at io.quarkus.deployment.ExtensionLoader.loadStepsFromClass(ExtensionLoader.java:437)
        at io.quarkus.deployment.ExtensionLoader.loadStepsFrom(ExtensionLoader.java:167)
        ... 11 more
Caused by: java.lang.ClassNotFoundException: io.quarkus.devconsole.spi.DevConsoleRuntimeTemplateInfoBuildItem
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
        at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
        at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:569)
        at io.quarkus.bootstrap.classloading.QuarkusClassLoader.loadClass(QuarkusClassLoader.java:517)
        ... 17 more

@geoand
Copy link
Contributor

geoand commented Oct 30, 2024

In that case you should probably consider Timefold

@amustafa91
Copy link
Author

Unfortunately, I am unable to move to different engines, as I am in the last phase of the project

@geoand
Copy link
Contributor

geoand commented Oct 30, 2024

Even if this were a bug and we fixed it, there is absolutely no chance of backporting the change to anything before 3.15

@amustafa91
Copy link
Author

amustafa91 commented Oct 31, 2024

I fixed dependency issues, and upgraded to 3.15.1 and I still get the same error

2024-10-31 16:15:53,061 ERROR [io.qua.run.Application] (Quarkus Main Thread) Failed to start application: java.lang.RuntimeException: Failed to start quarkus
        at io.quarkus.runner.ApplicationImpl.doStart(Unknown Source)
        at io.quarkus.runtime.Application.start(Application.java:101)
        at io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:119)
        at io.quarkus.runtime.Quarkus.run(Quarkus.java:71)
        at io.quarkus.runtime.Quarkus.run(Quarkus.java:44)
        at io.quarkus.runtime.Quarkus.run(Quarkus.java:124)
        at io.quarkus.runner.GeneratedMain.main(Unknown Source)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.base/java.lang.reflect.Method.invoke(Method.java:568)
        at io.quarkus.runner.bootstrap.StartupActionImpl$1.run(StartupActionImpl.java:116)
        at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: jakarta.enterprise.inject.IllegalProductException: Normal scoped producer method may not return null: io.quarkus.vertx.http.runtime.CurrentVertxRequest.getCurrent()       
        at io.quarkus.vertx.http.runtime.CurrentVertxRequest_ProducerMethod_getCurrent_bcI9FtU7pcNOHntvVCkP17muvXY_Bean.doCreate(Unknown Source)
        at io.quarkus.vertx.http.runtime.CurrentVertxRequest_ProducerMethod_getCurrent_bcI9FtU7pcNOHntvVCkP17muvXY_Bean.create(Unknown Source)
        at io.quarkus.vertx.http.runtime.CurrentVertxRequest_ProducerMethod_getCurrent_bcI9FtU7pcNOHntvVCkP17muvXY_Bean.create(Unknown Source)
        at io.quarkus.arc.impl.RequestContext$1.get(RequestContext.java:79)
        at io.quarkus.arc.impl.RequestContext$1.get(RequestContext.java:75)
        at io.quarkus.arc.generator.Default_jakarta_enterprise_context_RequestScoped_ContextInstances.c13(Unknown Source)
        at io.quarkus.arc.generator.Default_jakarta_enterprise_context_RequestScoped_ContextInstances.computeIfAbsent(Unknown Source)
        at io.quarkus.arc.impl.RequestContext.getIfActive(RequestContext.java:75)
        at io.quarkus.arc.impl.ClientProxies.getSingleContextDelegate(ClientProxies.java:28)
        at io.vertx.ext.web.CurrentVertxRequest_ProducerMethod_getCurrent_bcI9FtU7pcNOHntvVCkP17muvXY_ClientProxy.arc$delegate(Unknown Source)
        at io.vertx.ext.web.CurrentVertxRequest_ProducerMethod_getCurrent_bcI9FtU7pcNOHntvVCkP17muvXY_ClientProxy.get(Unknown Source)
        at org.acme.project.solver.CustomTenantResolver.resolveTenantId(CustomTenantResolver.java:23)
        at org.acme.project.solver.CustomTenantResolver_ClientProxy.resolveTenantId(Unknown Source)
        at io.quarkus.hibernate.orm.runtime.tenant.HibernateCurrentTenantIdentifierResolver.resolveCurrentTenantIdentifier(HibernateCurrentTenantIdentifierResolver.java:38)
        at io.quarkus.hibernate.orm.runtime.tenant.HibernateCurrentTenantIdentifierResolver.resolveCurrentTenantIdentifier(HibernateCurrentTenantIdentifierResolver.java:19)
        at org.hibernate.internal.SessionFactoryImpl$SessionBuilderImpl.<init>(SessionFactoryImpl.java:1286)
        at org.hibernate.internal.SessionFactoryImpl.withOptions(SessionFactoryImpl.java:662)
        at org.hibernate.internal.SessionFactoryImpl.openSession(SessionFactoryImpl.java:638)
        at org.hibernate.internal.SessionFactoryImpl.openSession(SessionFactoryImpl.java:166)
        at io.quarkus.hibernate.orm.runtime.RequestScopedSessionHolder.lambda$getOrCreateSession$0(RequestScopedSessionHolder.java:21)
        at java.base/java.util.HashMap.computeIfAbsent(HashMap.java:1220)
        at io.quarkus.hibernate.orm.runtime.RequestScopedSessionHolder.getOrCreateSession(RequestScopedSessionHolder.java:21)
        at io.quarkus.hibernate.orm.runtime.RequestScopedSessionHolder_ClientProxy.getOrCreateSession(Unknown Source)
        at io.quarkus.hibernate.orm.runtime.session.TransactionScopedSession.acquireSession(TransactionScopedSession.java:105)
        at io.quarkus.hibernate.orm.runtime.session.TransactionScopedSession.createSelectionQuery(TransactionScopedSession.java:1276)
        at org.hibernate.engine.spi.SessionLazyDelegator.createSelectionQuery(SessionLazyDelegator.java:749)
        at org.hibernate.Session_OpdLahisOZ9nWRPXMsEFQmQU03A_Synthetic_ClientProxy.createSelectionQuery(Unknown Source)
        at io.quarkus.hibernate.orm.panache.common.runtime.CommonPanacheQueryImpl.createBaseQuery(CommonPanacheQueryImpl.java:387)
        at io.quarkus.hibernate.orm.panache.common.runtime.CommonPanacheQueryImpl.createQuery(CommonPanacheQueryImpl.java:348)
        at io.quarkus.hibernate.orm.panache.common.runtime.CommonPanacheQueryImpl.list(CommonPanacheQueryImpl.java:301)
        at io.quarkus.hibernate.orm.panache.runtime.PanacheQueryImpl.list(PanacheQueryImpl.java:150)
        at org.acme.project.solver.CacheResolver.refreshCache(CacheResolver.java:22)
        at org.acme.project.solver.AppLifecycleBean.onStart(AppLifecycleBean.java:16)
        at org.acme.project.solver.AppLifecycleBean_Observer_onStart_gLFdVSsyS-Bx3elRx0VC3psS0V4.notify(Unknown Source)
        at io.quarkus.arc.impl.EventImpl$Notifier.notifyObservers(EventImpl.java:351)
        at io.quarkus.arc.impl.EventImpl$Notifier.notify(EventImpl.java:333)
        at io.quarkus.arc.impl.EventImpl.fire(EventImpl.java:80)
        at io.quarkus.arc.runtime.ArcRecorder.fireLifecycleEvent(ArcRecorder.java:156)
        at io.quarkus.arc.runtime.ArcRecorder.handleLifecycleEvents(ArcRecorder.java:107)
        at io.quarkus.deployment.steps.LifecycleEventsBuildStep$startupEvent1144526294.deploy_0(Unknown Source)
        at io.quarkus.deployment.steps.LifecycleEventsBuildStep$startupEvent1144526294.deploy(Unknown Source)
        ... 13 more

@geoand
Copy link
Contributor

geoand commented Oct 31, 2024

Great you were able to upgrade!

Any chance you can put a small sample project together that makes it trivial for us to reproduce the problem?

@michalvavrik
Copy link
Member

#44168 (comment) stacktrace shows that you are requesting RoutingContext during application startup when no HTTP request is active. You cannot use RoutingContext directly, instead, you need to inject CurrentVertxRequest and when it returns non-null RoutingContext then an HTTP request is active.

@amustafa91
Copy link
Author

It was tested on startup and on request and the request was null

I found git repo and worked with me,
https://github.com/MossabTN/quarkus-dynamic-multi-tenant

@michalvavrik
Copy link
Member

michalvavrik commented Nov 3, 2024

It was tested on startup and on request and the request was null

  1. I cannot see CurrentVertxRequest in your project https://github.com/search?q=repo%3AMossabTN%2Fquarkus-dynamic-multi-tenant+CurrentVertxRequest&type=code
  2. If you activate CDI request context yourself, it means that Quarkus did not prepare it for you (because Quarkus doesn't have available SecurityIdentity or RoutingContext)

I found git repo and worked with me, https://github.com/MossabTN/quarkus-dynamic-multi-tenant

I can run linked project in next weeks, but I cannot run it ATM (busy). Maybe someone will have time sooner. If you want quick tips, I suggest following:

  • use CurrentVertxRequest because you also request RoutingContext outside of activate HTTP request
  • as you use CDI request context very early, try to disable proactive authentication quarkus.http.auth.proactive=false, please see https://quarkus.io/guides/security-proactive-authentication for details and make sure authentication happens using security annotations

Just from reading your code I am not sure when CustomTenantResolver comes into action, if it is triggered for other things than authentication very early, then this might not help.

@geoand
Copy link
Contributor

geoand commented Nov 4, 2024

@amustafa91 the only way we can meaningfully help is if you attach a sample project that exhibits the problematic behavior and provide trivial steps to do so.

Currently, all indications point to the fact that there is no active HTTP request

@geoand geoand added the triage/needs-reproducer We are waiting for a reproducer. label Nov 4, 2024
@Eyeownyew
Copy link

Eyeownyew commented Nov 9, 2024

#44168 (comment) stacktrace shows that you are requesting RoutingContext during application startup when no HTTP request is active. You cannot use RoutingContext directly, instead, you need to inject CurrentVertxRequest and when it returns non-null RoutingContext then an HTTP request is active.

Thank you for this.
I encountered a similar issue when using io.quarkus.scheduler.Scheduled annotation. This worked:

@PersistenceUnitExtension
@RequestScoped
public class CustomTenantResolver implements TenantResolver {

  @Inject
  CurrentVertxRequest vertxRequest;

  @Override
  public String getDefaultTenantId() {
    Log.info("getDefaultTenantId returning default");
    return "default";
  }

  @Override
  public String resolveTenantId() {
    String defaultTenantId = getDefaultTenantId();
    if (vertxRequest == null || vertxRequest.getCurrent() == null) {
      return defaultTenantId;
    }
    // CustomTenantConfigResolver has already calculated the tenant id and saved it as a RoutingContext `tenantId` attribute:
    return vertxRequest.getCurrent().get("tenantId", defaultTenantId);
  }
}

@TomCools
Copy link

@amustafa91, Tom from the Timefold team here. Just FYI, moving from Timefold to Optaplanner can be done by running an OpenRewrite script. Timefold is a fork of OptaPlanner so you don't have to change much. We are compatible with the latest versions of Quarkus.

See: https://docs.timefold.ai/timefold-solver/latest/upgrading-timefold-solver/upgrade-from-optaplanner

@gsmet
Copy link
Member

gsmet commented Nov 16, 2024

@michalvavrik @yrodiere I don't think there's anything to fix here but maybe we could find a place to document this?

@gsmet gsmet added kind/enhancement New feature or request and removed kind/bug Something isn't working labels Nov 16, 2024
@michalvavrik
Copy link
Member

@michalvavrik @yrodiere I don't think there's anything to fix here but maybe we could find a place to document this?

I have checked same situation that is tested in security JPA io.quarkus.security.jpa.CustomHibernateTenantResolver and I think the situation is clear, let's document it. It can take few iterations, but we can proceed here: #44547

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/hibernate-orm Hibernate ORM area/security kind/enhancement New feature or request triage/needs-reproducer We are waiting for a reproducer.
Projects
None yet
6 participants