quarkus: Infinispan can't be manually started with Quarkus 1.3.0

Describe the bug When launching the application that uses Infinispan directly (not through infinispan-embedded), the startup fails to loading metrics:

2020-03-17 13:35:10,563 ERROR [io.qua.application] (main) Failed to start application: java.lang.IllegalStateException: Display name differs from previous usage
	at io.smallrye.metrics.MetricsRegistryImpl.verifyMetadataEquality(MetricsRegistryImpl.java:203)
	at io.smallrye.metrics.MetricsRegistryImpl.register(MetricsRegistryImpl.java:151)
	at io.quarkus.smallrye.metrics.runtime.SmallRyeMetricsRecorder.garbageCollectionMetrics(SmallRyeMetricsRecorder.java:250)
	at io.quarkus.smallrye.metrics.runtime.SmallRyeMetricsRecorder.registerBaseMetrics(SmallRyeMetricsRecorder.java:110)
	at io.quarkus.deployment.steps.SmallRyeMetricsProcessor$registerBaseAndVendorMetrics18.deploy_0(SmallRyeMetricsProcessor$registerBaseAndVendorMetrics18.zig:65)
	at io.quarkus.deployment.steps.SmallRyeMetricsProcessor$registerBaseAndVendorMetrics18.deploy(SmallRyeMetricsProcessor$registerBaseAndVendorMetrics18.zig:36)
	at io.quarkus.runner.ApplicationImpl.doStart(ApplicationImpl.zig:138)
	at io.quarkus.runtime.Application.start(Application.java:90)
	at io.quarkus.runtime.Application.run(Application.java:228)
	at io.quarkus.runner.GeneratedMain.main(GeneratedMain.zig:41)

This is visible here because of #7907 that causes the displayName to differ from the one that Infinispan loaded, since Infinispan’s new DefaultCacheManager(is) loads its own metrics before Quarkus:

DefaultMetadata{name='gc.total', type=counter, unit='none', reusable=true, description='Displays the total number of collections that have occurred. This attribute lists -1 if the collection count is undefined for this collector.', displayName='Garbage Collection Count'}
 
register:116, MetricsRegistryImpl (io.smallrye.metrics)
register:74, JmxRegistrar (io.smallrye.metrics.setup)
register:58, JmxRegistrar (io.smallrye.metrics.setup)
init:50, JmxRegistrar (io.smallrye.metrics.setup)
start:66, ApplicationMetricsRegistry (org.infinispan.metrics.impl)
start:41, CorePackageImpl$2 (org.infinispan.metrics.impl)
start:39, CorePackageImpl$2 (org.infinispan.metrics.impl)
invokeStart:587, BasicComponentRegistryImpl (org.infinispan.factories.impl)
doStartWrapper:578, BasicComponentRegistryImpl (org.infinispan.factories.impl)
startWrapper:547, BasicComponentRegistryImpl (org.infinispan.factories.impl)
access$700:30, BasicComponentRegistryImpl (org.infinispan.factories.impl)
running:770, BasicComponentRegistryImpl$ComponentWrapper (org.infinispan.factories.impl)
startDependencies:605, BasicComponentRegistryImpl (org.infinispan.factories.impl)
doStartWrapper:569, BasicComponentRegistryImpl (org.infinispan.factories.impl)
startWrapper:547, BasicComponentRegistryImpl (org.infinispan.factories.impl)
access$700:30, BasicComponentRegistryImpl (org.infinispan.factories.impl)
running:770, BasicComponentRegistryImpl$ComponentWrapper (org.infinispan.factories.impl)
startDependencies:605, BasicComponentRegistryImpl (org.infinispan.factories.impl)
doStartWrapper:569, BasicComponentRegistryImpl (org.infinispan.factories.impl)
startWrapper:547, BasicComponentRegistryImpl (org.infinispan.factories.impl)
access$700:30, BasicComponentRegistryImpl (org.infinispan.factories.impl)
running:770, BasicComponentRegistryImpl$ComponentWrapper (org.infinispan.factories.impl)
startDependencies:605, BasicComponentRegistryImpl (org.infinispan.factories.impl)
doStartWrapper:569, BasicComponentRegistryImpl (org.infinispan.factories.impl)
startWrapper:547, BasicComponentRegistryImpl (org.infinispan.factories.impl)
access$700:30, BasicComponentRegistryImpl (org.infinispan.factories.impl)
running:770, BasicComponentRegistryImpl$ComponentWrapper (org.infinispan.factories.impl)
registerComponentInternal:121, AbstractComponentRegistry (org.infinispan.factories)
registerComponent:110, AbstractComponentRegistry (org.infinispan.factories)
registerComponent:102, AbstractComponentRegistry (org.infinispan.factories)
cacheManagerStarting:106, LifecycleManager (org.infinispan.query.core.impl)
modulesManagerStarting:271, GlobalComponentRegistry (org.infinispan.factories)
access$000:65, GlobalComponentRegistry (org.infinispan.factories)
start:361, GlobalComponentRegistry$ModuleInitializer (org.infinispan.factories)
start:173, CorePackageImpl$11 (org.infinispan.factories)
start:171, CorePackageImpl$11 (org.infinispan.factories)
invokeStart:587, BasicComponentRegistryImpl (org.infinispan.factories.impl)
doStartWrapper:578, BasicComponentRegistryImpl (org.infinispan.factories.impl)
startWrapper:547, BasicComponentRegistryImpl (org.infinispan.factories.impl)
access$700:30, BasicComponentRegistryImpl (org.infinispan.factories.impl)
running:770, BasicComponentRegistryImpl$ComponentWrapper (org.infinispan.factories.impl)
preStart:254, GlobalComponentRegistry (org.infinispan.factories)
start:238, AbstractComponentRegistry (org.infinispan.factories)
internalStart:742, DefaultCacheManager (org.infinispan.manager)
start:713, DefaultCacheManager (org.infinispan.manager)
<init>:391, DefaultCacheManager (org.infinispan.manager)
<init>:335, DefaultCacheManager (org.infinispan.manager)
<init>:322, DefaultCacheManager (org.infinispan.manager)
init:64, IspnCacheManager (org.hawkular.alerts.cache)

And there the displayName is correct, while with Quarkus it isn’t. I’m not sure what changed between 1.2.1.Final and 1.3.0.Final (Infinispan 10.0.0 -> 10.1.2.Final), but now the metrics are loaded multiple times and that breaks things.

Expected behavior Infinispan would continue working as it did before.

Actual behavior See above.

To Reproduce Steps to reproduce the behavior:

  1. https://github.com/burmanm/custom-policies-engine/tree/infinispan_changes
  2. @Singleton’s static { } blocks loads: cacheManager = new DefaultCacheManager(is);
  3. Kaboom?

Configuration

Screenshots

Additional context

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 24 (18 by maintainers)

Most upvoted comments

@burmanm you’re bringing up some interesting points, we should probably write up some more about how we expect such designs to evolve; but I won’t presume to write any general recommendations yet as many of these are novel ideas: for proper guidance to emerge we’ll need more feedback like these and see what works best.

To put things into perspective: while this specific problem might have been solved already by #7921 , it’s probably best you keep in mind that you’re doing something we don’t support and don’t have integration tests for, so it’s possible it will break again without notice. Let me try to explain why and how we expect designs to change - but again I won’t presume we have thought of all aspects, so hopefully you’ll be able to help figuring this all out.

In Quarkus it’s fine to use 3rd party libraries which don’t have an extension, but in this case:

  • [obviously] we don’t test for them
  • we can’t help you making them work in GraalVM native image
  • you won’t benefit from Live Reload capabilities, e.g. if the Infinispan configuration file is changed Quarkus won’t reload
  • the specific component will not benefit from our optimisations, so possibly booting slower and consuming more runtime memory

For most “normal” Java code that people typically develop in house this is not a problem; an extension is only going to be needed for highly dynamic code, complex frameworks, libraries using bytecode enhancement, instrumentation, etc…

So while encapsulation is of course a highly valuable concept, I don’t think we can compare instantiation of a complex service like an in-memory data grid cluster component with a straight-forward encapsulation need: such a component needs tight integration with the platform so its initialization, but also integration with management, metrics, operations need to “tie in” into the core platform. Typically one uses a service lookup for such aspects, and you’re expected to have your own custom code “lookup” some service which is started and managed by the platform.

Wouldn’t it be better to use the dependency injection mechanism? Quarkus offers great decoupling of services via CDI - in fact most of our own intregration is relying on it.

Offload the initialization and management details of such a component to the platform, and have your component simply inject a reference to the caches. Your other non-Quarkus services can easily provide a simimlar factory, thath’s hardly figthing good OO principles.

Wouldn’t that be better?

That doesn’t seem to be the case.

I ran some experiments with #7921 included and I no longer can reproduce the problem. Perhaps @burmanm could you check it too and then we can close this issue?