For a project we are sending some events to kafka. We use spring-kafka 2.6.2.
Due to usage of spring-vault we have to restart/kill the application before the end of credentials lease (application is automatically restarted by kubernetes).
Our problem is that when using applicationContext.close() to proceed with our gracefull shutdown, KafkaProducer gets an InterruptedException Interrupted while joining ioThread inside it's close() method.
It means that in our case some pending events are not sent to kafka before shutdown as it's forced to close due to an error during destroy.
Here under a stacktrace
2020-12-18 13:57:29.007 INFO [titan-producer,222efdd2a07966ce,222efdd2a07966ce,true] 1 --- [ scheduling-1] o.s.b.w.e.tomcat.GracefulShutdown : Commencing graceful shutdown. Waiting for active requests to complete
2020-12-18 13:57:29.009 INFO [titan-producer,222efdd2a07966ce,222efdd2a07966ce,true] 1 --- [ scheduling-1] o.apache.catalina.core.StandardService : Stopping service [Tomcat]
2020-12-18 13:57:29.013 INFO [titan-producer,222efdd2a07966ce,222efdd2a07966ce,true] 1 --- [ scheduling-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Destroying Spring FrameworkServlet 'dispatcherServlet'
2020-12-18 13:57:29.014 INFO [titan-producer,,,] 1 --- [tomcat-shutdown] o.s.b.w.e.tomcat.GracefulShutdown : Graceful shutdown complete
2020-12-18 13:57:29.020 WARN [titan-producer,222efdd2a07966ce,222efdd2a07966ce,true] 1 --- [ scheduling-1] o.a.c.loader.WebappClassLoaderBase : The web application [ROOT] appears to have started a thread named [kafka-producer-network-thread | titan-producer-1] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
java.base#11.0.9.1/sun.nio.ch.EPoll.wait(Native Method)
java.base#11.0.9.1/sun.nio.ch.EPollSelectorImpl.doSelect(Unknown Source)
java.base#11.0.9.1/sun.nio.ch.SelectorImpl.lockAndDoSelect(Unknown Source)
java.base#11.0.9.1/sun.nio.ch.SelectorImpl.select(Unknown Source)
org.apache.kafka.common.network.Selector.select(Selector.java:873)
org.apache.kafka.common.network.Selector.poll(Selector.java:469)
org.apache.kafka.clients.NetworkClient.poll(NetworkClient.java:544)
org.apache.kafka.clients.producer.internals.Sender.runOnce(Sender.java:325)
org.apache.kafka.clients.producer.internals.Sender.run(Sender.java:240)
java.base#11.0.9.1/java.lang.Thread.run(Unknown Source)
2020-12-18 13:57:29.021 WARN [titan-producer,222efdd2a07966ce,222efdd2a07966ce,true] 1 --- [ scheduling-1] o.a.c.loader.WebappClassLoaderBase : The web application [ROOT] appears to have started a thread named [micrometer-kafka-metrics] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
java.base#11.0.9.1/jdk.internal.misc.Unsafe.park(Native Method)
java.base#11.0.9.1/java.util.concurrent.locks.LockSupport.parkNanos(Unknown Source)
java.base#11.0.9.1/java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.awaitNanos(Unknown Source)
java.base#11.0.9.1/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
java.base#11.0.9.1/java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
java.base#11.0.9.1/java.util.concurrent.ThreadPoolExecutor.getTask(Unknown Source)
java.base#11.0.9.1/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
java.base#11.0.9.1/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
java.base#11.0.9.1/java.lang.Thread.run(Unknown Source)
2020-12-18 13:57:29.046 INFO [titan-producer,222efdd2a07966ce,222efdd2a07966ce,true] 1 --- [ scheduling-1] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService 'applicationTaskExecutor'
2020-12-18 13:57:29.048 INFO [titan-producer,222efdd2a07966ce,222efdd2a07966ce,true] 1 --- [ scheduling-1] o.s.s.c.ThreadPoolTaskScheduler : Shutting down ExecutorService 'taskScheduler'
2020-12-18 13:57:29.051 INFO [titan-producer,222efdd2a07966ce,222efdd2a07966ce,true] 1 --- [ scheduling-1] o.a.k.clients.producer.KafkaProducer : [Producer clientId=titan-producer-1] Closing the Kafka producer with timeoutMillis = 30000 ms.
2020-12-18 13:57:29.055 ERROR [titan-producer,222efdd2a07966ce,222efdd2a07966ce,true] 1 --- [ scheduling-1] o.a.k.clients.producer.KafkaProducer : [Producer clientId=titan-producer-1] Interrupted while joining ioThreadjava.lang.InterruptedException: null
at java.base/java.lang.Object.wait(Native Method)
at java.base/java.lang.Thread.join(Unknown Source)
at org.apache.kafka.clients.producer.KafkaProducer.close(KafkaProducer.java:1205)
at org.apache.kafka.clients.producer.KafkaProducer.close(KafkaProducer.java:1182)
at org.springframework.kafka.core.DefaultKafkaProducerFactory$CloseSafeProducer.closeDelegate(DefaultKafkaProducerFactory.java:901)
at org.springframework.kafka.core.DefaultKafkaProducerFactory.destroy(DefaultKafkaProducerFactory.java:428)
at org.springframework.beans.factory.support.DisposableBeanAdapter.destroy(DisposableBeanAdapter.java:258)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroyBean(DefaultSingletonBeanRegistry.java:587)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingleton(DefaultSingletonBeanRegistry.java:559)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingleton(DefaultListableBeanFactory.java:1092)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.destroySingletons(DefaultSingletonBeanRegistry.java:520)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.destroySingletons(DefaultListableBeanFactory.java:1085)
at org.springframework.context.support.AbstractApplicationContext.destroyBeans(AbstractApplicationContext.java:1061)
at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:1030)
at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.doClose(ServletWebServerApplicationContext.java:170)
at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:979)
at org.springframework.cloud.sleuth.instrument.async.TraceRunnable.run(TraceRunnable.java:68)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.base/java.lang.Thread.run(Unknown Source)2020-12-18 13:57:29.055 INFO [titan-producer,222efdd2a07966ce,222efdd2a07966ce,true] 1 --- [ scheduling-1] o.a.k.clients.producer.KafkaProducer : [Producer clientId=titan-producer-1] Proceeding to force close the producer since pending requests could not be completed within timeout 30000 ms.
2020-12-18 13:57:29.056 WARN [titan-producer,222efdd2a07966ce,222efdd2a07966ce,true] 1 --- [ scheduling-1] o.s.b.f.support.DisposableBeanAdapter : Invocation of destroy method failed on bean with name 'kafkaProducerFactory': org.apache.kafka.common.errors.InterruptException: java.lang.InterruptedException
2020-12-18 13:57:29.064 INFO [titan-producer,222efdd2a07966ce,222efdd2a07966ce,true] 1 --- [ scheduling-1] o.s.s.concurrent.ThreadPoolTaskExecutor : Shutting down ExecutorService
2020-12-18 13:57:29.065 INFO [titan-producer,222efdd2a07966ce,222efdd2a07966ce,true] 1 --- [ scheduling-1] c.l.t.p.zookeeper.ZookeeperManagerImpl : Closing zookeeperConnection
2020-12-18 13:57:29.197 INFO [titan-producer,222efdd2a07966ce,222efdd2a07966ce,true] 1 --- [ scheduling-1] org.apache.zookeeper.ZooKeeper : Session: 0x30022348ba6000b closed
2020-12-18 13:57:29.197 INFO [titan-producer,,,] 1 --- [d-1-EventThread] org.apache.zookeeper.ClientCnxn : EventThread shut down for session: 0x30022348ba6000b
2020-12-18 13:57:29.206 INFO [titan-producer,222efdd2a07966ce,222efdd2a07966ce,true] 1 --- [ scheduling-1] com.zaxxer.hikari.HikariDataSource : loadtest_fallback_titan_pendingEvents - Shutdown initiated...
2020-12-18 13:57:29.221 INFO [titan-producer,222efdd2a07966ce,222efdd2a07966ce,true] 1 --- [ scheduling-1] com.zaxxer.hikari.HikariDataSource : loadtest_fallback_titan_pendingEvents - Shutdown completed.
Here is my configuration class
#Flogger
#EnableKafka
#Configuration
#RequiredArgsConstructor
#ConditionalOnProperty(
name = "titan.producer.kafka.enabled",
havingValue = "true",
matchIfMissing = true)
public class KafkaConfiguration {
#Bean
DefaultKafkaProducerFactoryCustomizer kafkaProducerFactoryCustomizer(ObjectMapper mapper) {
return producerFactory -> producerFactory.setValueSerializer(new JsonSerializer<>(mapper));
}
#Bean
public NewTopic createTopic(TitanProperties titanProperties, KafkaProperties kafkaProperties) {
TitanProperties.Kafka kafka = titanProperties.getKafka();
String defaultTopic = kafkaProperties.getTemplate().getDefaultTopic();
int numPartitions = kafka.getNumPartitions();
short replicationFactor = kafka.getReplicationFactor();
log.atInfo()
.log("Creating Kafka Topic %s with %s partitions and %s replicationFactor", defaultTopic, numPartitions, replicationFactor);
return TopicBuilder.name(defaultTopic)
.partitions(numPartitions)
.replicas(replicationFactor)
.config(MESSAGE_TIMESTAMP_TYPE_CONFIG, LOG_APPEND_TIME.name)
.build();
}
}
and my application.yaml
spring:
application:
name: titan-producer
kafka:
client-id: ${spring.application.name}
producer:
key-serializer: org.apache.kafka.common.serialization.UUIDSerializer
value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
properties:
max.block.ms: 2000
request.timeout.ms: 2000
delivery.timeout.ms: 2000 #must be greater or equal to request.timeout.ms + linger.ms
template:
default-topic: titan-dev
Our vault configuration which executes the applicationContext.close() using a scheduledTask. We do it kind randomly as we have multiple replicas of the app running in parallel and avoid all the replicas to be killed at the same time.
#Flogger
#Configuration
#ConditionalOnBean(SecretLeaseContainer.class)
#ConditionalOnProperty(
name = "titan.producer.scheduling.enabled",
havingValue = "true",
matchIfMissing = true)
public class VaultConfiguration {
#Bean
public Lifecycle scheduledAppRestart(Clock clock, TitanProperties properties, TaskScheduler scheduler, ConfigurableApplicationContext applicationContext) {
Instant now = clock.instant();
Duration maxTTL = properties.getVaultConfig().getCredsMaxLease();
Instant start = now.plusSeconds(maxTTL.dividedBy(2).toSeconds());
Instant end = now.plusSeconds(maxTTL.minus(properties.getVaultConfig().getCredsMaxLeaseExpirationThreshold()).toSeconds());
Instant randomInstant = randBetween(start, end);
return new ScheduledLifecycle(scheduler, applicationContext::close, "application restart before lease expiration", randomInstant);
}
private Instant randBetween(Instant startInclusive, Instant endExclusive) {
long startSeconds = startInclusive.getEpochSecond();
long endSeconds = endExclusive.getEpochSecond();
long random = RandomUtils.nextLong(startSeconds, endSeconds);
return Instant.ofEpochSecond(random);
}
}
The ScheduledLifecycle class we use to run the scheduledtasks
import lombok.extern.flogger.Flogger;
import org.springframework.context.SmartLifecycle;
import org.springframework.scheduling.TaskScheduler;
import java.time.Duration;
import java.time.Instant;
import java.util.concurrent.ScheduledFuture;
#Flogger
public class ScheduledLifecycle implements SmartLifecycle {
private ScheduledFuture<?> future = null;
private Duration delay = null;
private final TaskScheduler scheduler;
private final Runnable command;
private final String commandDesc;
private final Instant startTime;
public ScheduledLifecycle(TaskScheduler scheduler, Runnable command, String commandDesc, Instant startTime) {
this.scheduler = scheduler;
this.command = command;
this.commandDesc = commandDesc;
this.startTime = startTime;
}
public ScheduledLifecycle(TaskScheduler scheduler, Runnable command, String commandDesc, Instant startTime, Duration delay) {
this(scheduler, command, commandDesc, startTime);
this.delay = delay;
}
#Override
public void start() {
if (delay != null) {
log.atInfo().log("Scheduling %s: starting at %s, running every %s", commandDesc, startTime, delay);
future = scheduler.scheduleWithFixedDelay(command, startTime, delay);
} else {
log.atInfo().log("Scheduling %s: execution at %s", commandDesc, startTime);
future = scheduler.schedule(command, startTime);
}
}
#Override
public void stop() {
if (future != null) {
log.atInfo().log("Stop %s", commandDesc);
future.cancel(true);
}
}
#Override
public boolean isRunning() {
boolean running = future != null && (!future.isDone() && !future.isCancelled());
log.atFine().log("is %s running? %s", running);
return running;
}
}
Is there a bug with spring-kafka? Any idea?
Thanks
future.cancel(true);
This is interrupting the producer thread and is likely the root cause of the problem.
You should use future.cancel(false); to allow the task to terminate in an orderly fashion, without interruption.
/**
* Attempts to cancel execution of this task. This attempt will
* fail if the task has already completed, has already been cancelled,
* or could not be cancelled for some other reason. If successful,
* and this task has not started when {#code cancel} is called,
* this task should never run. If the task has already started,
* then the {#code mayInterruptIfRunning} parameter determines
* whether the thread executing this task should be interrupted in
* an attempt to stop the task.
*
* <p>After this method returns, subsequent calls to {#link #isDone} will
* always return {#code true}. Subsequent calls to {#link #isCancelled}
* will always return {#code true} if this method returned {#code true}.
*
* #param mayInterruptIfRunning {#code true} if the thread executing this
* task should be interrupted; otherwise, in-progress tasks are allowed
* to complete
* #return {#code false} if the task could not be cancelled,
* typically because it has already completed normally;
* {#code true} otherwise
*/
boolean cancel(boolean mayInterruptIfRunning);
EDIT
In addition, the ThreadPoolTaskScheduler.waitForTasksToCompleteOnShutdown is false by default.
/**
* Set whether to wait for scheduled tasks to complete on shutdown,
* not interrupting running tasks and executing all tasks in the queue.
* <p>Default is "false", shutting down immediately through interrupting
* ongoing tasks and clearing the queue. Switch this flag to "true" if you
* prefer fully completed tasks at the expense of a longer shutdown phase.
* <p>Note that Spring's container shutdown continues while ongoing tasks
* are being completed. If you want this executor to block and wait for the
* termination of tasks before the rest of the container continues to shut
* down - e.g. in order to keep up other resources that your tasks may need -,
* set the {#link #setAwaitTerminationSeconds "awaitTerminationSeconds"}
* property instead of or in addition to this property.
* #see java.util.concurrent.ExecutorService#shutdown()
* #see java.util.concurrent.ExecutorService#shutdownNow()
*/
public void setWaitForTasksToCompleteOnShutdown(boolean waitForJobsToCompleteOnShutdown) {
this.waitForTasksToCompleteOnShutdown = waitForJobsToCompleteOnShutdown;
}
You might also have to set awaitTerminationSeconds.
Related
I have simple Spring Boot (2.5) application to get multiple data from multiple sources at once. I have created 3 job classes, each of them have several tasks to do. First one have two tasks (defined in separate methods) to do, second have 3 and thirds have 2 - there's 7 in all count.
Each job have this construction:
#Component
public class FirstJob {
[...]
#Scheduled(cron = "0 * * * * *")
public void getLastTaskStatistics() {
[...]
}
#Scheduled(cron = "0 * * * * *")
public void getMetersStatusCount() {
[...]
}
}
#Component
public class SecondJob {
[...]
#Scheduled(cron = "0 * * * * *")
public void getIndexStats() {
[...]
}
#Scheduled(cron = "0 * * * * *")
public void getCollectionStats() {
[...]
}
#Scheduled(cron = "0 * * * * *")
public void getActiveMetersStats() {
[...]
}
}
Third one is the same. As you can see, all methods have fixed and the same firing time. Everything is working almost properly, but I want to execute them in parallel, in available execution thread pool: actually observation is different, all tasks are executed in single execution task (always named scheduling-1), and also in sequential. A part of log:
2021-05-04 14:39:00.020 INFO 9004 --- [ scheduling-1] FirstJob : getMetersStatusCount: start
2021-05-04 14:39:00.166 INFO 9004 --- [ scheduling-1] FirstJob : getMetersStatusCount: end
2021-05-04 14:39:00.166 INFO 9004 --- [ scheduling-1] FirstJob : getLastTaskStatistics: start
2021-05-04 14:39:00.235 INFO 9004 --- [ scheduling-1] FirstJob : getLastTaskStatistics: end
2021-05-04 14:39:00.235 INFO 9004 --- [ scheduling-1] SecondJob : getActiveMetersStats: start
2021-05-04 14:39:05.786 INFO 9004 --- [ scheduling-1] SecondJob : getActiveMetersStats: end
2021-05-04 14:39:05.786 INFO 9004 --- [ scheduling-1] SecondJob : getCollectionStats: start
2021-05-04 14:39:05.833 INFO 9004 --- [ scheduling-1] SecondJob : getCollectionStats: end
2021-05-04 14:39:05.833 INFO 9004 --- [ scheduling-1] SecondJob : getIndexStats: start
2021-05-04 14:39:05.902 INFO 9004 --- [ scheduling-1] SecondJob : getIndexStats: end
2021-05-04 14:39:05.902 INFO 9004 --- [ scheduling-1] ThirdJob : getExchangesDetails: start
2021-05-04 14:39:06.187 INFO 9004 --- [ scheduling-1] ThirdJob : getExchangesDetails: end
2021-05-04 14:39:06.187 INFO 9004 --- [ scheduling-1] ThirdJob : getQueueDetails: start
2021-05-04 14:39:06.303 INFO 9004 --- [ scheduling-1] ThirdJob : getQueueDetails: end
Please help me: how to avoid single instance of Quartz executor and run in parallel all tasks in all jobs? Quartz auto configuration in application.properties is based on default values, except:
spring.quartz.properties.org.quartz.scheduler.batchTriggerAcquisitionMaxCount=5
(change made for experiment purposes, value differ from default '1', but nothing interesting happened).
You can configure the pool size. Default is 1.
Sample:
spring.task.scheduling.pool.size=10
Why don't you try the async approach i.e. from a single #scheduled method call other method in async manners.
you can follow the approach over here How to asynchronously call a method in Java
eg:
CompletableFuture.runAsync(() -> {
// method calls
});
or
CompletableFuture.allOf(
CompletableFuture.runAsync(() -> ...),
CompletableFuture.runAsync(() -> ...)
);
Thanks to Ezequiel, it's enough to set:
spring.task.scheduling.pool.size=10
in application.properties, now all tasks starts at the same time.
I want to create a cron job which is retry-able and only 1 instance should execute it when we deploy multiple instances of the application.
I have also referred #Recover annotated method is not discovered for a #Retryable method that also is #Scheduled, but I am unable to resolve the issue of ArrayIndexOutOfBoundsException.
I am using 2.1.8.RELEASE version spring-boot
#Configuration
#EnableScheduling
#EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
#EnableRetry
public class MyScheduler {
#Scheduled(cron = "0 16 16 * * *")
#SchedulerLock(name = "MyScheduler_lock", lockAtLeastForString = ""PT5M", lockAtMostForString ="PT14M")
#Retryable(value = Exception.class, maxAttempts = 2)
public void retryAndRecover() {
retry++;
log.info("Scheduling Service Failed " + retry);
throw new Exception();
}
#Recover
public void recover(Exception e, String str) {
log.info("Service recovering");
}
}
Detailed exception:
2019-12-07 19:42:00.109 INFO [my-service,false] 16767 --- [ scheduling-1] r.t.p.scheduler.MyScheduler : Scheduling Service Failed 1
2019-12-07 19:42:01.114 INFO [my-service,false] 16767 --- [ scheduling-1] r.t.p.scheduler.MyScheduler : Scheduling Service Failed 2
2019-12-07 19:42:01.123 ERROR [my-service,,,] 16767 --- [ scheduling-1] o.s.s.s.TaskUtils$LoggingErrorHandler : Unexpected error occurred in scheduled task.
java.lang.ArrayIndexOutOfBoundsException: arraycopy: last source index 1 out of bounds for object array[0]
at java.base/java.lang.System.arraycopy(Native Method) ~[na:na]
at org.springframework.retry.annotation.RecoverAnnotationRecoveryHandler$SimpleMetadata.getArgs(RecoverAnnotationRecoveryHandler.java:166) ~[spring-retry-1.2.1.RELEASE.jar:na]
at org.springframework.retry.annotation.RecoverAnnotationRecoveryHandler.recover(RecoverAnnotationRecoveryHandler.java:62) ~[spring-retry-1.2.1.RELEASE.jar:na]
Your recover method can't have more parameters than the main method (aside from the exception.
String str
In playing around with Spring Boot, ActiveMQ, and JmsTemplate, I noticed that it appears that message order is not always preserved. In reading on ActiveMQ, "Message Groups" are offered as a potential solution to preserving message order when sending to a topic. Is there a way to do this with JmsTemplate?
Add Note: I'm starting to think that JmsTemplate is nice for "getting launched", but has too many issues.
Sample code and console output posted below...
#RestController
public class EmptyControllerSB {
#Autowired
MsgSender msgSender;
#RequestMapping(method = RequestMethod.GET, value = { "/v1/msgqueue" })
public String getAccount() {
msgSender.sendJmsMessageA();
msgSender.sendJmsMessageB();
return "Do nothing...successfully!";
}
}
#Component
public class MsgSender {
#Autowired
JmsTemplate jmsTemplate;
void sendJmsMessageA() {
jmsTemplate.convertAndSend(new ActiveMQTopic("VirtualTopic.TEST-TOPIC"), "message A");
}
void sendJmsMessageB() {
jmsTemplate.convertAndSend(new ActiveMQTopic("VirtualTopic.TEST-TOPIC"), "message B");
}
}
#Component
public class MsgReceiver {
private final String consumerOne = "Consumer.myConsumer1.VirtualTopic.TEST-TOPIC";
private final String consumerTwo = "Consumer.myConsumer2.VirtualTopic.TEST-TOPIC";
#JmsListener(destination = consumerOne )
public void receiveMessage1(String strMessage) {
System.out.println("Received on #1a -> " + strMessage);
}
#JmsListener(destination = consumerOne )
public void receiveMessage2(String strMessage) {
System.out.println("Received on #1b -> " + strMessage);
}
#JmsListener(destination = consumerTwo )
public void receiveMessage3(String strMessage) {
System.out.println("Received on #2 -> " + strMessage);
}
}
Here's the console output (note the order of output in first sequence)...
\Intel\Intel(R) Management Engine Components\DAL;C:\WINDOWS\System32\OpenSSH\;C:\Program Files (x86)\NVIDIA Corporation\PhysX\Common;C:\Program Files (x86)\gnupg\bin;C:\Users\LesR\AppData\Local\Microsoft\WindowsApps;c:\Gradle\gradle-5.0\bin;;C:\Program Files\JetBrains\IntelliJ IDEA 2018.3\bin;;.]
2019-04-03 09:23:08.408 INFO 13936 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2019-04-03 09:23:08.408 INFO 13936 --- [ main] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 672 ms
2019-04-03 09:23:08.705 INFO 13936 --- [ main] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2019-04-03 09:23:08.845 INFO 13936 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2019-04-03 09:23:08.877 INFO 13936 --- [ main] mil.navy.msgqueue.MsgqueueApplication : Started MsgqueueApplication in 1.391 seconds (JVM running for 1.857)
2019-04-03 09:23:14.949 INFO 13936 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2019-04-03 09:23:14.949 INFO 13936 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2019-04-03 09:23:14.952 INFO 13936 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 3 ms
Received on #2 -> message A
Received on #1a -> message B
Received on #1b -> message A
Received on #2 -> message B
<HIT DO-NOTHING ENDPOINT AGAIN>
Received on #1b -> message A
Received on #2 -> message A
Received on #1a -> message B
Received on #2 -> message B
BLUF - Add "?consumer.exclusive=true" to the declaration of the destination for the JmsListener annotation.
It seems that the solution is not that complex, especially if one abandons ActiveMQ's "message groups" in favor or "exclusive consumers". The drawback to the "message groups" is that the sender has to have prior knowledge of the potential partitioning of message consumers. If the producer has this knowledge, then "message groups" are a nice solution, as the solution is somewhat independent of the consumer.
But, a similar solution can be implemented from the consumer side, by having the consumer declare "exclusive consumer" on the queue. While I did not see anything in the JmsTemplate implementation that directly supports this, it seems that Spring's JmsTemplate implementation passes the queue name to ActiveMQ, and then ActiveMQ "does the right thing" and enforces the exclusive consumer behavior.
So...
Change the following...
private final String consumerOne = "Consumer.myConsumer1.VirtualTopic.TEST-TOPIC";
to...
private final String consumerOne = "Consumer.myConsumer1.VirtualTopic.TEST-TOPIC";?consumer.exclusive=true
Once I did this, only one of the two declared receive methods were invoked, and message order was maintained in all my test runs.
I am developing a spring boot application which will listen to ibm mq with
#JmsListener(id="abc", destination="${queueName}", containerFactory="defaultJmsListenerContainerFactory")
I have a JmsListenerEndpointRegistry which starts the listenerContainer.
On message will try to push the same message with some business logic to kafka. The poster code is
kafkaTemplate.send(kafkaProp.getTopic(), uniqueId, message)
Now in case a kafka producer fails, I want my boot application to get terminated. So I have added a custom
setErrorHandler.
So I have tried
`System.exit(1)`, `configurableApplicationContextObject.close()`, `Runtime.getRuntime.exit(1)`.
But none of them work. Below is the log that gets generated after
System.exit(0) or above others.
2018-05-24 12:12:47.981 INFO 18904 --- [ Thread-4] s.c.a.AnnotationConfigApplicationContext : Closing org.springframework.context.annotation.AnnotationConfigApplicationContext#1d08376: startup date [Thu May 24 12:10:35 IST 2018]; root of context hierarchy
2018-05-24 12:12:48.027 INFO 18904 --- [ Thread-4] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase 2147483647
2018-05-24 12:12:48.028 INFO 18904 --- [ Thread-4] o.s.c.support.DefaultLifecycleProcessor : Stopping beans in phase 0
2018-05-24 12:12:48.028 INFO 18904 --- [ Thread-4] o.s.j.e.a.AnnotationMBeanExporter : Unregistering JMX-exposed beans on shutdown
2018-05-24 12:12:48.028 INFO 18904 --- [ Thread-4] o.a.k.clients.producer.KafkaProducer : Closing the Kafka producer with timeoutMillis = 9223372036854775807 ms.
2018-05-24 12:12:48.044 INFO 18904 --- [ Thread-4] o.a.k.clients.producer.KafkaProducer : Closing the Kafka producer with timeoutMillis = 30000 ms.
But the application is still running and below are the running threads
Daemon Thread [Tomcat JDBC Pool Cleaner[14341596:1527144039908]] (Running)
Thread [DefaultMessageListenerContainer-1] (Running)
Thread [DestroyJavaVM] (Running)
Daemon Thread [JMSCCThreadPoolMaster] (Running)
Daemon Thread [RcvThread: com.ibm.mq.jmqi.remote.impl.RemoteTCPConnection#12474910[qmid=*******,fap=**,channel=****,ccsid=***,sharecnv=***,hbint=*****,peer=*******,localport=****,ssl=****]] (Running)
Thread [Thread-4] (Running)
The help is much appreciated. Thanks in advance. I simply want the application should exit.
Below is the thread dump before I call System.exit(1)
"DefaultMessageListenerContainer-1"
java.lang.Thread.State: RUNNABLE
at sun.management.ThreadImpl.getThreadInfo1(Native Method)
at sun.management.ThreadImpl.getThreadInfo(ThreadImpl.java:174)
at com.QueueErrorHandler.handleError(QueueErrorHandler.java:42)
at org.springframework.jms.listener.AbstractMessageListenerContainer.invokeErrorHandler(AbstractMessageListenerContainer.java:931)
at org.springframework.jms.listener.AbstractMessageListenerContainer.handleListenerException(AbstractMessageListenerContainer.java:902)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.doReceiveAndExecute(AbstractPollingMessageListenerContainer.java:326)
at org.springframework.jms.listener.AbstractPollingMessageListenerContainer.receiveAndExecute(AbstractPollingMessageListenerContainer.java:235)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.invokeListener(DefaultMessageListenerContainer.java:1166)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.executeOngoingLoop(DefaultMessageListenerContainer.java:1158)
at org.springframework.jms.listener.DefaultMessageListenerContainer$AsyncMessageListenerInvoker.run(DefaultMessageListenerContainer.java:1055)
at java.lang.Thread.run(Thread.java:745)
You should take a thread dump to see what Thread [DefaultMessageListenerContainer-1] (Running) is doing.
Now in case a kafka producer fails
What kind of failure? If the broker is down, the thread will block in the producer library for up to 60 seconds by default.
You can reduce that time by setting the max.block.ms producer property.
Couple of solutions which worked for me to solve above.
Solutions 1.
Get all threads in error handler and interrupt them all and then exist the system.
ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
ThreadInfo[] threadInfos = threadMXBean.getThreadInfo(threadMXBean.getAllThreadIds(), 100);
for (ThreadInfo threadInfo : threadInfos) {
Thread.currentThread().interrupt();
}
System.exit(1);
Solution 2. Define a application context manager. Like
public class AppContextManager implements ApplicationContextAware {
private static ApplicationContext _appCtx;
#Override
public void setApplicationContext(ApplicationContext ctx){
_appCtx = ctx;
}
public static ApplicationContext getAppContext(){
return _appCtx;
}
public static void exit(Integer exitCode) {
System.exit(SpringApplication.exit(_appCtx,() -> exitCode));
}
}
Then use same manager to exit in error handler
Executors.newSingleThreadExecutor().execute(new Runnable() {
public void run() {
jmsListenerEndpointRegistry.stop();
AppContextManager.exit(-1);
}
});
I have spring boot rabbitmq application where i have to send an Employee object to queue. Then i have set up a listener application. Do some processing on employee object and put this object in call back queue.
For this, i have created below objects in my appication.
Created ConnectionFactory.
Created RabbitAdmin object using ConnectionFactory..
Request Queue.
Callback Queue.
Direct Exchange.
Request Queue Binding.
Callback Queue Binding.
MessageConverter.
RabbitTemplate object.
And finally object of SimpleMessageListenerContainer.
My Application files looks like below.
application.properties
spring.rabbitmq.host=localhost
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
spring.rabbitmq.virtual-host=foo
emp.rabbitmq.directexchange=EMP_EXCHANGE1
emp.rabbitmq.requestqueue=EMP_QUEUE1
emp.rabbitmq.routingkey=EMP_ROUTING_KEY1
MainClass.java
package com.employee;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class MainClass {
public static void main(String[] args) {
SpringApplication.run(
MainClass.class, args);
}
}
ApplicationContextProvider.java
package com.employee.config;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ConfigurableApplicationContext;
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public ApplicationContext getApplicationContext(){
return context;
}
#Override
public void setApplicationContext(ApplicationContext arg0) throws BeansException {
context = arg0;
}
public Object getBean(String name){
return context.getBean(name, Object.class);
}
public void addBean(String beanName, Object beanObject){
ConfigurableListableBeanFactory beanFactory = ((ConfigurableApplicationContext)context).getBeanFactory();
beanFactory.registerSingleton(beanName, beanObject);
}
public void removeBean(String beanName){
BeanDefinitionRegistry reg = (BeanDefinitionRegistry) context.getAutowireCapableBeanFactory();
reg.removeBeanDefinition(beanName);
}
}
Constants.java
package com.employee.constant;
public class Constants {
public static final String CALLBACKQUEUE = "_CBQ";
}
Employee.java
package com.employee.model;
import com.fasterxml.jackson.annotation.JsonIdentityInfo;
import com.fasterxml.jackson.annotation.ObjectIdGenerators;
#JsonIdentityInfo(generator = ObjectIdGenerators.IntSequenceGenerator.class, property = "#id", scope = Employee.class)
public class Employee {
private String empName;
private String empId;
private String changedValue;
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public String getEmpId() {
return empId;
}
public void setEmpId(String empId) {
this.empId = empId;
}
public String getChangedValue() {
return changedValue;
}
public void setChangedValue(String changedValue) {
this.changedValue = changedValue;
}
}
EmployeeProducerInitializer.java
package com.employee.config;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.support.converter.Jackson2JsonMessageConverter;
import org.springframework.amqp.support.converter.MessageConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import com.employee.constant.Constants;
import com.employee.service.EmployeeResponseReceiver;
#Configuration
#EnableAutoConfiguration
#ComponentScan(value="com.en.*")
public class EmployeeProducerInitializer {
#Value("${emp.rabbitmq.requestqueue}")
String requestQueueName;
#Value("${emp.rabbitmq.directexchange}")
String directExchange;
#Value("${emp.rabbitmq.routingkey}")
private String requestRoutingKey;
#Autowired
private ConnectionFactory rabbitConnectionFactory;
#Bean
ApplicationContextProvider applicationContextProvider(){
System.out.println("inside app ctx provider");
return new ApplicationContextProvider();
};
#Bean
RabbitAdmin rabbitAdmin(){
System.out.println("inside rabbit admin");
return new RabbitAdmin(rabbitConnectionFactory);
};
#Bean
Queue empRequestQueue() {
System.out.println("inside request queue");
return new Queue(requestQueueName, true);
}
#Bean
Queue empCallBackQueue() {
System.out.println("inside call back queue");
return new Queue(requestQueueName + Constants.CALLBACKQUEUE, true);
}
#Bean
DirectExchange empDirectExchange() {
System.out.println("inside exchange");
return new DirectExchange(directExchange);
}
#Bean
Binding empRequestBinding() {
System.out.println("inside request binding");
return BindingBuilder.bind(empRequestQueue()).to(empDirectExchange()).with(requestRoutingKey);
}
#Bean
Binding empCallBackBinding() {
return BindingBuilder.bind(empCallBackQueue()).to(empDirectExchange()).with(requestRoutingKey + Constants.CALLBACKQUEUE);
}
#Bean
public MessageConverter jsonMessageConverter(){
System.out.println("inside json msg converter");
return new Jackson2JsonMessageConverter();
}
#Bean
public RabbitTemplate empFixedReplyQRabbitTemplate() {
System.out.println("inside rabbit template");
RabbitTemplate template = new RabbitTemplate(this.rabbitConnectionFactory);
template.setExchange(empDirectExchange().getName());
template.setRoutingKey(requestRoutingKey);
template.setMessageConverter(jsonMessageConverter());
template.setReceiveTimeout(100000);
template.setReplyTimeout(100000);
return template;
}
#Bean
public SimpleMessageListenerContainer empReplyListenerContainer() {
System.out.println("inside listener");
SimpleMessageListenerContainer container = new SimpleMessageListenerContainer();
try{
container.setConnectionFactory(this.rabbitConnectionFactory);
container.setQueues(empCallBackQueue());
container.setMessageListener(new EmployeeResponseReceiver());
container.setMessageConverter(jsonMessageConverter());
container.setConcurrentConsumers(10);
container.setMaxConcurrentConsumers(20);
container.start();
}catch(Exception e){
e.printStackTrace();
}finally{
System.out.println("inside listener finally");
}
return container;
}
#Autowired
#Qualifier("empReplyListenerContainer")
private SimpleMessageListenerContainer empReplyListenerContainer;
}
EmployeeResponseReceiver.java
package com.employee.service;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.core.ChannelAwareMessageListener;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.stereotype.Component;
import com.employee.config.ApplicationContextProvider;
import com.employee.model.Employee;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.client.Channel;
#Component
#EnableAutoConfiguration
public class EmployeeResponseReceiver implements ChannelAwareMessageListener {
ApplicationContextProvider applicationContextProvider = new ApplicationContextProvider();
String msg = null;
ObjectMapper mapper = new ObjectMapper();
Employee employee = null;
#Override
public void onMessage(Message message, Channel arg1) throws Exception {
try {
msg = new String(message.getBody());
System.out.println("Received Message : " + msg);
employee = mapper.readValue(msg, Employee.class);
} catch (Exception e) {
e.printStackTrace();
}
}
}
The problem is whenever i start my application, i get below exceptions.
2018-03-17 14:18:36.695 INFO 12472 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2018-03-17 14:18:36.696 INFO 12472 --- [ost-startStop-1] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 5060 ms
2018-03-17 14:18:37.004 INFO 12472 --- [ost-startStop-1] o.s.b.w.servlet.ServletRegistrationBean : Mapping servlet: 'dispatcherServlet' to [/]
2018-03-17 14:18:37.010 INFO 12472 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'characterEncodingFilter' to: [/*]
2018-03-17 14:18:37.010 INFO 12472 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'hiddenHttpMethodFilter' to: [/*]
2018-03-17 14:18:37.011 INFO 12472 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'httpPutFormContentFilter' to: [/*]
2018-03-17 14:18:37.011 INFO 12472 --- [ost-startStop-1] o.s.b.w.servlet.FilterRegistrationBean : Mapping filter: 'requestContextFilter' to: [/*]
inside listener
inside call back queue
inside json msg converter
2018-03-17 14:18:37.576 INFO 12472 --- [cTaskExecutor-8] o.s.a.r.c.CachingConnectionFactory : Created new connection: SimpleConnection#3d31af39 [delegate=amqp://guest#127.0.0.1:5672/foo, localPort= 50624]
2018-03-17 14:18:37.654 WARN 12472 --- [cTaskExecutor-7] o.s.a.r.listener.BlockingQueueConsumer : Failed to declare queue:EMP_QUEUE1_CBQ
2018-03-17 14:18:37.655 WARN 12472 --- [cTaskExecutor-6] o.s.a.r.listener.BlockingQueueConsumer : Failed to declare queue:EMP_QUEUE1_CBQ
2018-03-17 14:18:37.655 WARN 12472 --- [cTaskExecutor-5] o.s.a.r.listener.BlockingQueueConsumer : Failed to declare queue:EMP_QUEUE1_CBQ
2018-03-17 14:18:37.655 WARN 12472 --- [cTaskExecutor-3] o.s.a.r.listener.BlockingQueueConsumer : Failed to declare queue:EMP_QUEUE1_CBQ
2018-03-17 14:18:37.657 WARN 12472 --- [cTaskExecutor-1] o.s.a.r.listener.BlockingQueueConsumer : Failed to declare queue:EMP_QUEUE1_CBQ
2018-03-17 14:18:37.658 WARN 12472 --- [cTaskExecutor-8] o.s.a.r.listener.BlockingQueueConsumer : Failed to declare queue:EMP_QUEUE1_CBQ
2018-03-17 14:18:37.661 WARN 12472 --- [cTaskExecutor-2] o.s.a.r.listener.BlockingQueueConsumer : Failed to declare queue:EMP_QUEUE1_CBQ
2018-03-17 14:18:37.660 WARN 12472 --- [cTaskExecutor-4] o.s.a.r.listener.BlockingQueueConsumer : Failed to declare queue:EMP_QUEUE1_CBQ
2018-03-17 14:18:37.661 WARN 12472 --- [cTaskExecutor-9] o.s.a.r.listener.BlockingQueueConsumer : Failed to declare queue:EMP_QUEUE1_CBQ
2018-03-17 14:18:37.666 WARN 12472 --- [TaskExecutor-10] o.s.a.r.listener.BlockingQueueConsumer : Failed to declare queue:EMP_QUEUE1_CBQ
2018-03-17 14:18:37.667 WARN 12472 --- [cTaskExecutor-2] o.s.a.r.listener.BlockingQueueConsumer : Queue declaration failed; retries left=3
org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$DeclarationException: Failed to declare queue(s):[EMP_QUEUE1_CBQ]
at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.attemptPassiveDeclarations(BlockingQueueConsumer.java:636) ~[spring-rabbit-1.7.2.RELEASE.jar:na]
at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.start(BlockingQueueConsumer.java:535) ~[spring-rabbit-1.7.2.RELEASE.jar:na]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1389) [spring-rabbit-1.7.2.RELEASE.jar:na]
at java.lang.Thread.run(Unknown Source) [na:1.8.0_151]
Caused by: java.io.IOException: null
at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:105) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:101) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:123) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.ChannelN.queueDeclarePassive(ChannelN.java:992) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.ChannelN.queueDeclarePassive(ChannelN.java:50) ~[amqp-client-4.0.2.jar:4.0.2]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_151]
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_151]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_151]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_151]
at org.springframework.amqp.rabbit.connection.CachingConnectionFactory$CachedChannelInvocationHandler.invoke(CachingConnectionFactory.java:955) ~[spring-rabbit-1.7.2.RELEASE.jar:na]
at com.sun.proxy.$Proxy58.queueDeclarePassive(Unknown Source) ~[na:na]
at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.attemptPassiveDeclarations(BlockingQueueConsumer.java:615) ~[spring-rabbit-1.7.2.RELEASE.jar:na]
... 3 common frames omitted
Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no queue 'EMP_QUEUE1_CBQ' in vhost 'foo', class-id=50, method-id=10)
at com.rabbitmq.utility.ValueOrException.getValue(ValueOrException.java:66) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.utility.BlockingValueOrException.uninterruptibleGetValue(BlockingValueOrException.java:32) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.AMQChannel$BlockingRpcContinuation.getReply(AMQChannel.java:366) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.AMQChannel.privateRpc(AMQChannel.java:229) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:117) ~[amqp-client-4.0.2.jar:4.0.2]
... 12 common frames omitted
Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no queue 'EMP_QUEUE1_CBQ' in vhost 'foo', class-id=50, method-id=10)
at com.rabbitmq.client.impl.ChannelN.asyncShutdown(ChannelN.java:505) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.ChannelN.processAsync(ChannelN.java:336) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.AMQChannel.handleCompleteInboundCommand(AMQChannel.java:143) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.AMQChannel.handleFrame(AMQChannel.java:90) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.AMQConnection.readFrame(AMQConnection.java:634) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.AMQConnection.access$300(AMQConnection.java:47) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.AMQConnection$MainLoop.run(AMQConnection.java:572) ~[amqp-client-4.0.2.jar:4.0.2]
... 1 common frames omitted
2018-03-17 14:08:36.689 WARN 11076 --- [cTaskExecutor-4] o.s.a.r.listener.BlockingQueueConsumer : Failed to declare queue:EMP_QUEUE1_CBQ
2018-03-17 14:08:36.695 ERROR 11076 --- [cTaskExecutor-4] o.s.a.r.l.SimpleMessageListenerContainer : Consumer received fatal exception on startup
org.springframework.amqp.rabbit.listener.QueuesNotAvailableException: Cannot prepare queue for listener. Either the queue doesn't exist or the broker will not allow us to use it.
at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.start(BlockingQueueConsumer.java:563) ~[spring-rabbit-1.7.2.RELEASE.jar:na]
at org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer$AsyncMessageProcessingConsumer.run(SimpleMessageListenerContainer.java:1389) ~[spring-rabbit-1.7.2.RELEASE.jar:na]
at java.lang.Thread.run(Unknown Source) [na:1.8.0_151]
Caused by: org.springframework.amqp.rabbit.listener.BlockingQueueConsumer$DeclarationException: Failed to declare queue(s):[EMP_QUEUE1_CBQ]
at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.attemptPassiveDeclarations(BlockingQueueConsumer.java:636) ~[spring-rabbit-1.7.2.RELEASE.jar:na]
at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.start(BlockingQueueConsumer.java:535) ~[spring-rabbit-1.7.2.RELEASE.jar:na]
... 2 common frames omitted
Caused by: java.io.IOException: null
at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:105) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.AMQChannel.wrap(AMQChannel.java:101) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:123) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.ChannelN.queueDeclarePassive(ChannelN.java:992) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.ChannelN.queueDeclarePassive(ChannelN.java:50) ~[amqp-client-4.0.2.jar:4.0.2]
at sun.reflect.GeneratedMethodAccessor27.invoke(Unknown Source) ~[na:na]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_151]
at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_151]
at org.springframework.amqp.rabbit.connection.CachingConnectionFactory$CachedChannelInvocationHandler.invoke(CachingConnectionFactory.java:955) ~[spring-rabbit-1.7.2.RELEASE.jar:na]
at com.sun.proxy.$Proxy58.queueDeclarePassive(Unknown Source) ~[na:na]
at org.springframework.amqp.rabbit.listener.BlockingQueueConsumer.attemptPassiveDeclarations(BlockingQueueConsumer.java:615) ~[spring-rabbit-1.7.2.RELEASE.jar:na]
... 3 common frames omitted
Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no queue 'EMP_QUEUE1_CBQ' in vhost 'foo', class-id=50, method-id=10)
at com.rabbitmq.utility.ValueOrException.getValue(ValueOrException.java:66) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.utility.BlockingValueOrException.uninterruptibleGetValue(BlockingValueOrException.java:32) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.AMQChannel$BlockingRpcContinuation.getReply(AMQChannel.java:366) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.AMQChannel.privateRpc(AMQChannel.java:229) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.AMQChannel.exnWrappingRpc(AMQChannel.java:117) ~[amqp-client-4.0.2.jar:4.0.2]
... 11 common frames omitted
Caused by: com.rabbitmq.client.ShutdownSignalException: channel error; protocol method: #method<channel.close>(reply-code=404, reply-text=NOT_FOUND - no queue 'EMP_QUEUE1_CBQ' in vhost 'foo', class-id=50, method-id=10)
at com.rabbitmq.client.impl.ChannelN.asyncShutdown(ChannelN.java:505) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.ChannelN.processAsync(ChannelN.java:336) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.AMQChannel.handleCompleteInboundCommand(AMQChannel.java:143) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.AMQChannel.handleFrame(AMQChannel.java:90) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.AMQConnection.readFrame(AMQConnection.java:634) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.AMQConnection.access$300(AMQConnection.java:47) ~[amqp-client-4.0.2.jar:4.0.2]
at com.rabbitmq.client.impl.AMQConnection$MainLoop.run(AMQConnection.java:572) ~[amqp-client-4.0.2.jar:4.0.2]
... 1 common frames omitted
2018-03-17 14:08:36.697 INFO 11076 --- [TaskExecutor-10] o.s.a.r.l.SimpleMessageListenerContainer : Successfully waited for workers to finish.
2018-03-17 14:08:36.699 INFO 11076 --- [cTaskExecutor-5] o.s.a.r.l.SimpleMessageListenerContainer : Successfully waited for workers to finish.
2018-03-17 14:08:36.700 INFO 11076 --- [cTaskExecutor-1] o.s.a.r.l.SimpleMessageListenerContainer : Successfully waited for workers to finish.
2018-03-17 14:08:36.701 INFO 11076 --- [cTaskExecutor-3] o.s.a.r.l.SimpleMessageListenerContainer : Successfully waited for workers to finish.
2018-03-17 14:08:36.700 INFO 11076 --- [cTaskExecutor-2] o.s.a.r.l.SimpleMessageListenerContainer : Successfully waited for workers to finish.
2018-03-17 14:08:36.702 INFO 11076 --- [cTaskExecutor-7] o.s.a.r.l.SimpleMessageListenerContainer : Successfully waited for workers to finish.
2018-03-17 14:08:36.765 ERROR 11076 --- [cTaskExecutor-8] o.s.a.r.l.SimpleMessageListenerContainer : Stopping container from aborted consumer
2018-03-17 14:08:36.766 ERROR 11076 --- [cTaskExecutor-6] o.s.a.r.l.SimpleMessageListenerContainer : Stopping container from aborted consumer
2018-03-17 14:08:36.779 ERROR 11076 --- [cTaskExecutor-9] o.s.a.r.l.SimpleMessageListenerContainer : Stopping container from aborted consumer
2018-03-17 14:08:36.791 ERROR 11076 --- [cTaskExecutor-4] o.s.a.r.l.SimpleMessageListenerContainer : Stopping container from aborted consumer
inside app ctx provider
inside rabbit admin
inside exchange
inside request queue
inside request binding
inside rabbit template
2018-03-17 14:08:38.978 INFO 11076 --- [ main] s.w.s.m.m.a.RequestMappingHandlerAdapter : Looking for #ControllerAdvice: org.springframework.boot.context.embedded.AnnotationConfigEmbeddedWebApplicationContext#33b37288: startup date [Sat Mar 17 14:08:16 IST 2018]; root of context hierarchy
2018-03-17 14:08:39.395 INFO 11076 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error]}" onto public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> org.springframework.boot.autoconfigure.web.BasicErrorController.error(javax.servlet.http.HttpServletRequest)
2018-03-17 14:08:39.398 INFO 11076 --- [ main] s.w.s.m.m.a.RequestMappingHandlerMapping : Mapped "{[/error],produces=[text/html]}" onto public org.springframework.web.servlet.ModelAndView org.springframework.boot.autoconfigure.web.BasicErrorController.errorHtml(javax.servlet.http.HttpServletRequest,javax.servlet.http.HttpServletResponse)
2018-03-17 14:08:39.663 INFO 11076 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/webjars/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-03-17 14:08:39.663 INFO 11076 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-03-17 14:08:39.826 INFO 11076 --- [ main] o.s.w.s.handler.SimpleUrlHandlerMapping : Mapped URL path [/**/favicon.ico] onto handler of type [class org.springframework.web.servlet.resource.ResourceHttpRequestHandler]
2018-03-17 14:08:40.648 INFO 11076 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2018-03-17 14:08:40.677 INFO 11076 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Bean with name 'rabbitConnectionFactory' has been autodetected for JMX exposure
2018-03-17 14:08:40.685 INFO 11076 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Located managed bean 'rabbitConnectionFactory': registering with JMX server as MBean [org.springframework.amqp.rabbit.connection:name=rabbitConnectionFactory,type=CachingConnectionFactory]
2018-03-17 14:08:40.746 INFO 11076 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase -2147482648
2018-03-17 14:08:40.747 INFO 11076 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 2147483647
2018-03-17 14:08:41.258 INFO 11076 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
2018-03-17 14:08:41.270 INFO 11076 --- [ main] com.employee.MainClass : Started MainClass in 26.141 seconds (JVM running for 28.02)
Can anybody help me resolving my issue? As per my understanding, when object of SimpleMessageListenerContainer is being created, callback queue is not created on rabbitmq server. I tried declaring queue using RabbitAdmin object, but then execution stops and nothing goes ahead. This problem was not there when i was declaring queue in default virtual host. But when i added virtual host foo all of it sudden stopped working. You can replicate this issue using above code. I have pasted all my code. Kindly let me know if anything else is to be posted.
Interesting point is even if i am getting this exceptions, my application is up and running. That means somehow my callback queue is created and object of SimpleMessageListenerContainer gets the queue. I read somewhere that, when queue is created, my SimpleMessageListenerContainer object will listen to it.
Please help me resolving this issue.
This problem was not there when i was declaring queue in default virtual host. But when i added virtual host foo all of it sudden stopped working.
Does the user that accesses the new virtual host have configure permissions? Configure permissions are required to declare queues.
A RabbitAdmin is required to declare the queues/bindings; the container only does a passive declaration to check the queue is present.
EDIT
container.start();
You must not start() the container within a bean definition. The application context will do that after the application context is completely built, if the container's autoStartUp is true (default).
It is clear from your logs that the container is starting too early - before the other beans (admin, queue etc) have been declared.