apache / camel-quarkus

Apache Camel Quarkus
https://camel.apache.org
Apache License 2.0
251 stars 186 forks source link

Infinispan with dev services enabled can lead to jakarta.enterprise.inject.CreationException #5965

Open jamesnetherton opened 3 months ago

jamesnetherton commented 3 months ago

Bug description

Consider a Camel Quarkus Infinispan application configured with the bare minimum configuration like:

camel.component.infinispan.hosts = localhost

Then a simple route like:

from("direct:cachePut")
    .setHeader("CamelInfinispanKey").constant("foo")
    .setHeader("CamelInfinispanValue").constant("bar")
    .to("infinispan:test?operation=PUT")
    .log("Cache PUT : ${header.CamelInfinispanKey} = ${header.CamelInfinispanValue}");

In the logs at runtime we see:

Autowired property: cacheContainer on component: infinispan as exactly one instance of type: org.infinispan.client.hotrod.RemoteCacheManager (org.infinispan.client.hotrod.RemoteCacheManager_3e5ozT9gyWKQ9VvCN1iNcOXJaqs_Synthetic_ClientProxy) found in the registry

Meaning that for some reason, the Quarkus Infinispan extension has created a RemoteCacheManager bean, even though we never set any quarkus.infinispan configuration in application.properties.

This leads to an exception being thrown when the cache put operation occurs:

jakarta.enterprise.inject.CreationException: Null contextual instance was produced by a normal scoped synthetic bean: SYNTHETIC bean [class=org.infinispan.client.hotrod.RemoteCacheManager

The error goes away if you set quarkus.infinispan-client.devservices.enabled=false. So there's something about having dev services enabled that leads to the creation of the unwanted RemoteCacheManager bean.

jamesnetherton commented 3 months ago

I created a reproducer project here:

https://github.com/jamesnetherton/infinispan-demo

jamesnetherton commented 3 months ago

@karesti any ideas about this?

karesti commented 3 months ago

@jamesnetherton yes, the dev services creates a default remote cache manager without any configuration and then when we use a cache in the code, the cache is also created by default. My question is: do you need to use dev services AND this bean not to be created but being provided by camel quarkus ?

karesti commented 3 months ago

@jamesnetherton bean that won't be a synthetic bean in this case.

jamesnetherton commented 3 months ago

My question is: do you need to use dev services AND this bean not to be created but being provided by camel quarkus ?

The problem is that devservices is enabled by default. Which isn't really desirable for minimal code, k8s based deployments like camel-k.

So users have to either explicitly disable devservices or disable the Camel RemoteCacheManager auto discovery.

karesti commented 3 months ago

I afraid that having dev services not enabled by default is the dev services default behaviour, I can't change that for Infinispan. But I can do that if I detect the use of Camel in the Infinispan extension

karesti commented 3 months ago

@jamesnetherton in the Infinispan extension, I already enable and so stuff depending on extensions that might be present. I have an idea that might be done in the camel quarkus extension

karesti commented 3 months ago

@jamesnetherton maybe this can provide in the camel infinispan quarkus extension something like this https://github.com/quarkiverse/quarkus-langchain4j/blob/main/infinispan/deployment/src/main/java/io/quarkiverse/langchain4j/infinispan/DevServicesConfigBuilderCustomizer.java#L1

jamesnetherton commented 3 months ago

@jamesnetherton maybe this can provide in the camel infinispan quarkus extension something like this

Yes, I was thinking about something like that. I need to experiment a little.

karesti commented 3 months ago

something like

public class InfinispanDevServicesConfigBuilderCustomizer implements SmallRyeConfigBuilderCustomizer {
    @Override
    public void configBuilder(final SmallRyeConfigBuilder builder) {
        // use a priority of 50 to make sure that this is overridable by any of the standard methods
        builder.withSources(
                new PropertiesConfigSource(
                        Map.of("quarkus.infinispan-client.devservices.enabled", false),
                        "quarkus-camel-infinispan", 50));
    }
}
karesti commented 3 months ago

In the Infinispan extesion, I do have this code as well:

 // dev mode client name for default
        if (infinispanClientsBuildTimeConfig.defaultInfinispanClient.devService.devservices.enabled) {
            clientNames.add(DEFAULT_INFINISPAN_CLIENT_NAME);
        }

I could disable the creation of the infinispan bean if the camel feature is present, since all this is delegated to the client.

this way dev services will spin up a infinispan container after all, but without creating the bean that is not needed for this use case. We could configure the

camel.component.infinispan.hosts = ${INFINISPAN_HOST:localhost}
camel.component.infinispan.username = admin
camel.component.infinispan.password = password
camel.component.infinispan.secure = true

In the dev services override connecting this way to the infinispan spinned up by the dev services

For what is having a cache created on startup, we can also provide a property with a default cache to be present in the server with dev services

karesti commented 3 months ago

@jamesnetherton I'm going to implement the liked issue (to be backported)

then I would suggest making use of spinning a server with Quarkus and adding extra config with a SmallRyeConfigBuilderCustomizer or whatever else for Dev Mode