Java Rabbit SimpleMessageListenerContainer赢得';不要关机

Java Rabbit SimpleMessageListenerContainer赢得';不要关机,java,rabbitmq,spring-amqp,Java,Rabbitmq,Spring Amqp,从开始,我们有一个兔子凭据失效的场景,我们需要在CachingConnectionFactory上调用resetConnection(),以获取一组新的凭据 我们在一个ShutdownSignalException处理程序中这样做,它基本上可以工作。不起作用的是,我们还需要重新启动侦听器。我们有以下几种: @RabbitListener( id = ABC, bindings = @QueueBinding(value = @Queue(value="myQ", durable=

从开始,我们有一个兔子凭据失效的场景,我们需要在
CachingConnectionFactory
上调用
resetConnection()
,以获取一组新的凭据

我们在一个
ShutdownSignalException
处理程序中这样做,它基本上可以工作。不起作用的是,我们还需要重新启动侦听器。我们有以下几种:

@RabbitListener(
    id = ABC,
    bindings = @QueueBinding(value = @Queue(value="myQ", durable="true"),
        exchange = @Exchange(value="myExchange", durable="true"),
        key = "myKey"),
    containerFactory = "customQueueContainerFactory"
)
public void process(...) {
   ...
}
(还)给人的印象是,我们只需要做:

@Autowired RabbitListenerEndpointRegistry registry;
@Autowired CachingConnectionFactory connectionFactory;

@Override
public void shutdownCompleted(ShutdownSignalException cause) {
    refreshRabbitMQCredentials();
}

public void refreshRabbitMQCredentials() {
    registry.stop();  // do this first

    // Fetch credentials, update username/pass
    connectionFactory.resetConnection(); // then this

    registry.start();  // finally restart
}
问题是,在通过
SimpleMessageListenerContainer
调试之后,当第一个容器调用了
doShutdown()
时,Spring尝试取消
阻塞队列消费者

因为底层的
通道
仍然报告为打开状态-即使RabbitMQ UI没有报告任何连接或通道处于打开状态-一个取消事件被发送到
ChannelN.basicCancel()
内的代理,但该通道随后会永久阻塞以获得回复,因此,容器关闭被完全阻止

我已尝试将
任务执行器
(a
Executors.newCachedThreadPool()
)注入容器中,并调用
shutdownNow()
或中断它们,但这些都不会影响通道的阻塞等待

看起来我唯一能解除通道阻塞的方法是在取消期间触发一个额外的
ShutdownSignalException
,但是(a)我不知道如何才能做到这一点,(b)看起来我必须在再次尝试关闭之前并行启动所有侦听器的取消)


更新2:

这似乎是某种种族状况。移除容器停止/启动后,如果我向
SimpleMessageListenerContainer.restart()
添加一个仅线程的断点,让
resetConnection()跑过去,然后释放断点,那么我可以看到事情开始恢复:

16:18:47,208 INFO  u.c.c.c.r.RabbitMQReauthenticator - CachingConnectionFactory reset
// Get ready to release the SMLC.restart() breakpoint...
16:19:02,072 INFO  o.s.a.r.c.CachingConnectionFactory - Attempting to connect to: rabbitmq.service.consul:5672
16:19:02,083 INFO  o.s.a.r.c.CachingConnectionFactory - Created new connection: connectionFactory#7489bca4:1/SimpleConnection@68546c13 [delegate=amqp://cert-configserver-132a07c2-94f3-0099-4de1-f0b1a9875d5a@127.0.0.1:5672/, localPort= 33350]
16:19:02,086 INFO  o.s.amqp.rabbit.core.RabbitAdmin - Auto-declaring a non-durable, auto-delete, or exclusive Queue ...
16:19:02,095 DEBUG u.c.c.c.r.ReauthenticatingChannelListener - Active connection check succeeded for channel AMQChannel(amqp://cert-configserver-132a07c2-94f3-0099-4de1-f0b1a9875d5a@127.0.0.1:5672/,1)
16:19:02,120 INFO  o.s.amqp.rabbit.core.RabbitAdmin - Auto-declaring a non-durable, auto-delete, or exclusive Queue (springCloudBus...
在这种情况下,我现在必须解决如何延迟容器重新启动,直到刷新完成(即我的
ShutdownSignalException
处理程序完成),或者以某种方式使刷新阻塞


更新3:


我的整个问题(这是一个症状)通过以下方式得到解决:

根本不清楚为什么频道会报告为开放;这对我来说很好;它在删除用户
foo
后恢复

@SpringBootApplication
public class So49323291Application {

    public static void main(String[] args) {
        SpringApplication.run(So49323291Application.class, args);
    }

    @Bean
    public ApplicationRunner runner(RabbitListenerEndpointRegistry registry, CachingConnectionFactory cf,
            RabbitTemplate template) {
        return args -> {
            cf.setUsername("foo");
            cf.setPassword("bar");
            registry.start();
            doSends(template);
            registry.stop();
            cf.resetConnection();
            cf.setUsername("baz");
            cf.setPassword("qux");
            registry.start();
            doSends(template);
        };
    }

    public void doSends(RabbitTemplate template) {
        while (true) {
            try {
                template.convertAndSend("foo", "Hello");
                Thread.sleep(5_000);
            }
            catch (Exception e) {
                e.printStackTrace();
                break;
            }
        }
    }

    @RabbitListener(queues = "foo", autoStartup = "false")
    public void in(Message in) {
        System.out.println(in);
    }

}
(正文:'Hello'MessageProperties[headers={},contentType=text/plain,contentEncoding=UTF-8,contentLength=0,receivedDeliveryMode=PERSISTENT,priority=0,redelivered=false,receivedExchange=,receivedRoutingKey=foo,deliveryTag=4,consumerTag=amq.ctag-9zt3wUGYSJmoON3zw03wUw,consumerQueue=foo])

2018-03-16 11:24:01.451错误11867---[127.0.0.1:5672]o.s.a.r.c.CachingConnectionFactory:通道关闭:连接错误;协议方法:#方法(回复代码=320,回复文本=CONNECTION_-FORCED-删除用户'foo',类id=0,方法id=0)

原因:com.rabbitmq.client.AuthenticationFailureException:访问被拒绝-使用普通身份验证机制拒绝登录。有关详细信息,请参阅代理日志文件

2018-03-16 11:24:01.745错误11867---[cTaskExecutor-2]o.s.a.r.l.SimpleMessageListenerContainer:从中止的使用者停止容器

2018-03-16 11:24:03.740信息11867---[cTaskExecutor-3]o.s.a.r.c.CachingConnectionFactory:已创建新连接:rabbitConnectionFactory 35; 2c4d1ac:3/SimpleConnection@5e9c036b[代表=amqp://baz@127.0.0.1:5672/,localPort=59346]

(正文:'Hello'MessageProperties[headers={},contentType=text/plain,contentEncoding=UTF-8,contentLength=0,receivedDeliveryMode=PERSISTENT,priority=0,redelivered=false,receivedExchange=,receivedRoutingKey=foo,deliveryTag=1,consumerTag=amq.ctag-LJNY00TBUVY5CCAD3R4A,consumerQueue=foo])


但是,您确实不需要停止/启动注册表,只需使用新凭据重新配置连接工厂,然后调用
resetConnection()
;集装箱会恢复的。

谢谢。我希望我不必执行停止/启动操作,但集装箱无论如何都无法恢复。我想知道这是否是因为消费者在
CachingConnectionFactory
设置其凭据之前重新启动。此外,如果我降低Spring AMQP日志记录以进行调试,它似乎仍在获取旧的细节。似乎没有任何“重置”的情况发生。似乎是比赛条件影响了我而不是你。我用2.0.2进行了测试,但我不记得有任何改变会影响这一点。下周我将尝试使用1.7.x。如果将容器上的
possibleAuthenticationFailureFailtal
设置为
false
,是否会看到不同的行为?感谢您的关注。经过测试,该标志在此无效。看起来容器和
ShutdownSignalException
处理程序之间确实出现了错位:只有在线程之间共享一些状态,我才能在容器重新启动之前尝试重新排序刷新…我刚刚用1.7.6测试过,没有问题;如果你能举出一个小例子来说明这个问题,我会找出问题所在。
16:18:47,208 INFO  u.c.c.c.r.RabbitMQReauthenticator - CachingConnectionFactory reset
// Get ready to release the SMLC.restart() breakpoint...
16:19:02,072 INFO  o.s.a.r.c.CachingConnectionFactory - Attempting to connect to: rabbitmq.service.consul:5672
16:19:02,083 INFO  o.s.a.r.c.CachingConnectionFactory - Created new connection: connectionFactory#7489bca4:1/SimpleConnection@68546c13 [delegate=amqp://cert-configserver-132a07c2-94f3-0099-4de1-f0b1a9875d5a@127.0.0.1:5672/, localPort= 33350]
16:19:02,086 INFO  o.s.amqp.rabbit.core.RabbitAdmin - Auto-declaring a non-durable, auto-delete, or exclusive Queue ...
16:19:02,095 DEBUG u.c.c.c.r.ReauthenticatingChannelListener - Active connection check succeeded for channel AMQChannel(amqp://cert-configserver-132a07c2-94f3-0099-4de1-f0b1a9875d5a@127.0.0.1:5672/,1)
16:19:02,120 INFO  o.s.amqp.rabbit.core.RabbitAdmin - Auto-declaring a non-durable, auto-delete, or exclusive Queue (springCloudBus...
@SpringBootApplication
public class So49323291Application {

    public static void main(String[] args) {
        SpringApplication.run(So49323291Application.class, args);
    }

    @Bean
    public ApplicationRunner runner(RabbitListenerEndpointRegistry registry, CachingConnectionFactory cf,
            RabbitTemplate template) {
        return args -> {
            cf.setUsername("foo");
            cf.setPassword("bar");
            registry.start();
            doSends(template);
            registry.stop();
            cf.resetConnection();
            cf.setUsername("baz");
            cf.setPassword("qux");
            registry.start();
            doSends(template);
        };
    }

    public void doSends(RabbitTemplate template) {
        while (true) {
            try {
                template.convertAndSend("foo", "Hello");
                Thread.sleep(5_000);
            }
            catch (Exception e) {
                e.printStackTrace();
                break;
            }
        }
    }

    @RabbitListener(queues = "foo", autoStartup = "false")
    public void in(Message in) {
        System.out.println(in);
    }

}