Skip to content

[FEATURE REQ] JMS - [JMS] No property combination yields sender=JmsPoolConnectionFactory + listener=ServiceBusJmsConnectionFactory #49308

@rojik-fiskaly

Description

@rojik-fiskaly

Problem

ServiceBusJmsConnectionFactoryConfiguration controls the sender connection factory and ServiceBusJmsContainerConfiguration controls the listener connection factory, but both decision tables are driven by the same set
of properties (spring.jms.servicebus.pool.enabled / spring.jms.cache.enabled). Because the properties are shared, there is no combination that independently configures:

  • SenderJmsPoolConnectionFactory
  • ListenerServiceBusJmsConnectionFactory

Why this combination is required

Sender must use JmsPoolConnectionFactory

The Azure documentation for Spring JMS support (Connections) explicitly recommends using JmsPoolConnectionFactory
to handle the case where the broker drops idle connections and the producer receives The MessageProducer was closed due to an unrecoverable error.

JmsPoolConnectionFactory avoids this by proactively evicting connections (and their attached producers) on an idle timeout, before the broker drops them.

Listener must use ServiceBusJmsConnectionFactory

On Standard tier Azure Service Bus, topic subscriptions only work with ServiceBusJmsConnectionFactory as the listener connection factory. Other connection factories (CachingConnectionFactory,
JmsPoolConnectionFactory) require shared durable subscriptions, which are a Premium-tier-only feature (see #43279). Wrapping the listener factory breaks topic subscription for Standard tier users entirely.

We use Standard tier in development environments and Premium tier in production, but we need a single configuration that works across all environments without tier-specific overrides.

Current workaround

We work around this by setting spring.jms.cache.enabled=false to flip the sender decision table to a raw ServiceBusJmsConnectionFactory, then manually declaring a @Primary JmsPoolConnectionFactory bean that wraps it:

@Bean
@Primary
@ConditionalOnClass(JmsPoolConnectionFactory.class)
@ConditionalOnBooleanProperty(prefix = "spring.jms.cache", name = "enabled", havingValue = false)
public JmsPoolConnectionFactory senderConnectionFactory(ServiceBusJmsConnectionFactory rawConnectionFactory) {
    JmsPoolConnectionFactory pool = new JmsPoolConnectionFactory();
    pool.setConnectionFactory(rawConnectionFactory);
    pool.setMaxConnections(1);
    pool.setConnectionIdleTimeout(8 * 60 * 1000); // below broker's ~10 min idle disconnect
    pool.setUseAnonymousProducers(false);
    return pool;
}

This works but requires manual configuration and relies on an internal property (spring.jms.cache.enabled=false) whose side effects are not obvious.

Metadata

Metadata

Assignees

No one assigned

    Labels

    customer-reportedIssues that are reported by GitHub users external to the Azure organization.needs-triageWorkflow: This is a new issue that needs to be triaged to the appropriate team.questionThe issue doesn't require a change to the product in order to be resolved. Most issues start as that

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions