Spring Rabbit - Semaphore允许泄漏导致"没有可用的渠道"例外

时间:2017-08-18 10:14:15

标签: spring-amqp spring-rabbit

我们为消费者使用CachingConnectionFactory。随着每一次连接丢失,我都看到一个checkoutPermit被获取并且它从未被释放。所以,让我们说如果我们使用默认缓存通道大小为25,下次当连接在丢弃后恢复时,可用许可证的数量将为24.经过一段时间后,许可证的数量为0因此导致异常 AmqpTimeoutException("没有可用频道")

我在版本1.6.10-RELEASE,1.7.3-RELEASE和2.0.0-BUILD-SNAPSHOT中观察到了这种行为。

我们是否有可能以错误的方式使用该库,我们应该关注checkoutPermit的手动释放,可能是通过关闭我们自己的频道? (在连接丢弃后永远不会调用releasePermitIfNecessary)

提前致谢。

示例(使用1.7.3-RELEASE)

配置

@Configuration
public class Config {

    @Bean
    public CachingConnectionFactory cachingConnectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory("localhost");
        connectionFactory.setUsername("username");
        connectionFactory.setPassword("password");
        connectionFactory.setVirtualHost("vhost");
        connectionFactory.setChannelCheckoutTimeout(1200);
        connectionFactory.setConnectionTimeout(1000);
        connectionFactory.setPort(5672);
        return connectionFactory;
    }

    @Bean
    public SimpleMessageListenerContainer simpleMessageListenerContainer(CachingConnectionFactory cachingConnectionFactory) {
        SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
        container.setConnectionFactory(cachingConnectionFactory);
        container.setQueueNames("test.queue");
        container.setMessageListener(new MessageListenerAdapter(new TestHandler()));
        container.start();
        return container;
    }

}

处理程序(仅用于测试)

public class TestHandler {

    public String handleMessage(byte[] textBytes) {
        String text = new String(textBytes);
        System.out.println("Received: " + text);
        return text;
    }

}

我在RabbitMQ和我的app之间使用代理测试连接丢弃,我在那里手动断开与RabbitMQ的连接。

1 个答案:

答案 0 :(得分:1)

确认。

这绝对是个错误。当我们失去连接时,我们也失去了所有的频道。因此,我们必须重置相关的许可证。

请提出一张带有正确说明的JIRA票。

同时我想作为一种解决方法,您不应该使用etChannelCheckoutTimeout(1200)并将其保留为0,默认值是什么:

/**
 * Sets the channel checkout timeout. When greater than 0, enables channel limiting
 * in that the {@link #channelCacheSize} becomes the total number of available channels per
 * connection rather than a simple cache size. Note that changing the {@link #channelCacheSize}
 * does not affect the limit on existing connection(s), invoke {@link #destroy()} to cause a
 * new connection to be created with the new limit.
 * <p>
 * Since 1.5.5, also applies to getting a connection when the cache mode is CONNECTION.
 * @param channelCheckoutTimeout the timeout in milliseconds; default 0 (channel limiting not enabled).
 * @since 1.4.2
 * @see #setConnectionLimit(int)
 */
public void setChannelCheckoutTimeout(long channelCheckoutTimeout) {