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()
内的代理,但该通道随后会永久阻塞以获得回复,因此,容器关闭被完全阻止
我已尝试将任务执行器
(aExecutors.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);
}
}