quarkiverse / quarkus-ironjacamar

IronJacamar is an implementation of the Jakarta Connector Architecture specification
https://docs.quarkiverse.io/quarkus-ironjacamar/dev/index.html
Apache License 2.0
4 stars 2 forks source link

Pool does not prefill #123

Closed vsevel closed 2 months ago

vsevel commented 3 months ago

I have a jms application sending and receiving jms messages using the artemis ra.

I have the following configuration:

quarkus:
  ironjacamar:
    ra:
      kind: artemis
      config:
        connection-parameters: host=x;port=x;protocols=CORE;connect-timeout-millis=10000,host=x;port=x;protocols=CORE;connect-timeout-millis=10000
        protocol-manager-factory: org.apache.activemq.artemis.core.protocol.hornetq.client.HornetQClientProtocolManagerFactory
        user: x
        password: x
      cm:
        pool:
          config:
            min-size: 1
            initial-size: 1
            prefill: true
            strict-min: true
    activation-spec:
      myqueue:
        config:
          destination-type: jakarta.jms.Queue
          destination: jms.queue.x
          max-session: '10'
          rebalance-connections: 'true'

when I start the application without an active producer, and I get the ironjacamar pool stats, I do not see any connection created.

            IronJacamarContainer container = ...
            PoolStatistics stats = container.getConnectionManager().getPool().getStatistics();
            int activeCount = stats.getActiveCount();  ==> 0

I would have expected this to be one.

looking deeper, I can see that without an active producer asking for a context, there is no pool initialization happening.

after I activated a jms producer, I debugged the pool initialization sequence. I ended up stopping in SemaphoreArrayListManagedConnectionPool:

initialize:177, SemaphoreArrayListManagedConnectionPool (org.jboss.jca.core.connectionmanager.pool.mcp)
init:191, ManagedConnectionPoolFactory (org.jboss.jca.core.connectionmanager.pool.mcp)
create:173, ManagedConnectionPoolFactory (org.jboss.jca.core.connectionmanager.pool.mcp)
getManagedConnectionPool:353, AbstractPool (org.jboss.jca.core.connectionmanager.pool)
getConnection:645, AbstractPool (org.jboss.jca.core.connectionmanager.pool)
getManagedConnection:624, AbstractConnectionManager (org.jboss.jca.core.connectionmanager)
getManagedConnection:440, TxConnectionManagerImpl (org.jboss.jca.core.connectionmanager.tx)
allocateConnection:789, AbstractConnectionManager (org.jboss.jca.core.connectionmanager)
allocateConnection:792, ActiveMQRASessionFactoryImpl (org.apache.activemq.artemis.ra)
createSession:482, ActiveMQRASessionFactoryImpl (org.apache.activemq.artemis.ra)
createSession:673, ActiveMQRASessionFactoryImpl (org.apache.activemq.artemis.ra)
createSession:678, ActiveMQRASessionFactoryImpl (org.apache.activemq.artemis.ra)
validateUser:422, ActiveMQRAConnectionFactoryImpl (org.apache.activemq.artemis.ra)
createContext:379, ActiveMQRAConnectionFactoryImpl (org.apache.activemq.artemis.ra)
createContext:369, ActiveMQRAConnectionFactoryImpl (org.apache.activemq.artemis.ra)
createContext:364, ActiveMQRAConnectionFactoryImpl (org.apache.activemq.artemis.ra)
send:52, MyJMSProducer (com.x.)

and specifically this block of code:

      // Schedule managed connection pool for prefill
      if ((pc.isPrefill() || pc.isStrictMin()) && p instanceof PrefillPool && pc.getInitialSize() > 0)
      {
         PoolFiller.fillPool(new FillRequest(this, pc.getInitialSize()));
      }

the condition is false because p is a PoolByCri, which implements Pool but not PrefillPool.

if PoolByCri can be prefilled, it must be through another mean. or all the prefill configuration parameters have no effect. the second point is that there must be an active producer that triggers getting a connection, else the pool is not initialized. when I set the prefill config params, I would expect the pool to be prefilled, even if I have no active producer.

the hidden requirement behind this issue, is to be able to produce a light health check based on pool stats, as opposed to creating a jms session on a connection.

see also https://github.com/quarkiverse/quarkus-artemis/issues/591#issuecomment-2271071427

gastaldi commented 3 months ago

In this case you may need to change the pool strategy: https://docs.quarkiverse.io/quarkus-ironjacamar/dev/index.html#quarkus-ironjacamar_quarkus-ironjacamar-ra-cm-pool-strategy and use one-pool (which should prefill in this case)

vsevel commented 3 months ago

what is the difference? I tried but even after I shut down the broker, the active count stays > 0. I suppose the pool does not regularly if the created connection are still valid?

gastaldi commented 3 months ago

In your example project, can you give it a try if org.jboss.jca.core.connectionmanager.pool.validator.ConnectionValidator would maintain the pool? You can start it by calling ConnectionValidator.getInstance().start()

You also need to set quarkus.ironjacamar.ra.cm.pool.config.background-validation and quarkus.ironjacamar.ra.cm.pool.config.background-validation-millis

vsevel commented 3 months ago

still does not work. the SemaphoreArrayListManagedConnectionPool only gets initialized when I start sending a message through my producer. here is the call stack:

initialize:183, SemaphoreArrayListManagedConnectionPool (org.jboss.jca.core.connectionmanager.pool.mcp)
init:191, ManagedConnectionPoolFactory (org.jboss.jca.core.connectionmanager.pool.mcp)
create:173, ManagedConnectionPoolFactory (org.jboss.jca.core.connectionmanager.pool.mcp)
getManagedConnectionPool:353, AbstractPool (org.jboss.jca.core.connectionmanager.pool)
getConnection:645, AbstractPool (org.jboss.jca.core.connectionmanager.pool)
getManagedConnection:624, AbstractConnectionManager (org.jboss.jca.core.connectionmanager)
getManagedConnection:440, TxConnectionManagerImpl (org.jboss.jca.core.connectionmanager.tx)
allocateConnection:789, AbstractConnectionManager (org.jboss.jca.core.connectionmanager)
allocateConnection:792, ActiveMQRASessionFactoryImpl (org.apache.activemq.artemis.ra)
createSession:482, ActiveMQRASessionFactoryImpl (org.apache.activemq.artemis.ra)
createSession:673, ActiveMQRASessionFactoryImpl (org.apache.activemq.artemis.ra)
createSession:678, ActiveMQRASessionFactoryImpl (org.apache.activemq.artemis.ra)
validateUser:422, ActiveMQRAConnectionFactoryImpl (org.apache.activemq.artemis.ra)
createContext:379, ActiveMQRAConnectionFactoryImpl (org.apache.activemq.artemis.ra)
createContext:369, ActiveMQRAConnectionFactoryImpl (org.apache.activemq.artemis.ra)
createContext:364, ActiveMQRAConnectionFactoryImpl (org.apache.activemq.artemis.ra)
send:52, MyJMSProducer
send$$superforward:-1, MyJMSProducer_Subclass
apply:-1, MyJMSProducer_Subclass$$function$$1
proceed:73, AroundInvokeInvocationContext (io.quarkus.arc.impl)
proceed:62, AroundInvokeInvocationContext (io.quarkus.arc.impl)
invokeInOurTx:136, TransactionalInterceptorBase (io.quarkus.narayana.jta.runtime.interceptor)
invokeInOurTx:107, TransactionalInterceptorBase (io.quarkus.narayana.jta.runtime.interceptor)
doIntercept:38, TransactionalInterceptorRequired (io.quarkus.narayana.jta.runtime.interceptor)
intercept:61, TransactionalInterceptorBase (io.quarkus.narayana.jta.runtime.interceptor)
intercept:32, TransactionalInterceptorRequired (io.quarkus.narayana.jta.runtime.interceptor)
intercept:-1, TransactionalInterceptorRequired_Bean (io.quarkus.narayana.jta.runtime.interceptor)
invoke:42, InterceptorInvocation (io.quarkus.arc.impl)
perform:30, AroundInvokeInvocationContext (io.quarkus.arc.impl)
performAroundInvoke:27, InvocationContexts (io.quarkus.arc.impl)
send:-1, MyJMSProducer_Subclass
send:-1, MyJMSProducer_ClientProxy
sendJMSMessage:142, GreetingResource
invoke:-1, GreetingResource$quarkusrestinvoker$sendJMSMessage_e1724160a7d06891ea25841dbe3f0e6637864a8b 
handle:29, InvocationHandler (org.jboss.resteasy.reactive.server.handlers)
invokeHandler:141, QuarkusResteasyReactiveRequestContext (io.quarkus.resteasy.reactive.server.runtime)
run:147, AbstractResteasyReactiveContext (org.jboss.resteasy.reactive.common.core)
runWith:635, VertxCoreRecorder$14 (io.quarkus.vertx.core.runtime)
doRunWith:2516, EnhancedQueueExecutor$Task (org.jboss.threads)
run:2495, EnhancedQueueExecutor$Task (org.jboss.threads)
run:1521, EnhancedQueueExecutor$ThreadBody (org.jboss.threads)
run:11, DelegatingRunnable (org.jboss.threads)
run:11, ThreadLocalResettingRunnable (org.jboss.threads)
run:30, FastThreadLocalRunnable (io.netty.util.concurrent)
runWith:1596, Thread (java.lang)
run:1583, Thread (java.lang)
vsevel commented 3 months ago

a side comment on background-validation-millis: it is a duration. so when you do background-validation-millis=5000, it is interpreted as 5000 seconds not 5. might have been more appropriate to leave the type as long insted of duration.

gastaldi commented 3 months ago

a side comment on background-validation-millis: it is a duration. so when you do background-validation-millis=5000, it is interpreted as 5000 seconds not 5. might have been more appropriate to leave the type as long insted of duration.

You can also set to 5s to be more specific, but yeah, I agree. Mind opening a PR? I created #124 based on your comment

gastaldi commented 2 months ago

@vsevel that's intentional, IronJacamar will not initialize connections unless some service requests it.

A @Startup bean opening and closing the ConnectionFactory would be enough to trigger the pool initialization

vsevel commented 2 months ago

so closing with works as expected