Starting Spring Boot application without check for Kafka Server - spring

I have got an application that uses SpringBoot 2.10.0.Release and kafka in the version 2.10.0. The application has got a simple producer and consumer: The sender works with KafkaTemplate and the consumer with KafkaListener.
What I try to achieve is to be able to start the SpringBoot application even if the KafkaServer is not running.
Currently without a running KafkaBroker the application cannot be started with this error message:
org.springframework.context.ApplicationContextException:
Failed to start bean 'org.springframework.kafka.config.internalKafkaListenerEndpointRegistry';
nested exception is org.apache.kafka.common.errors.TimeoutException
Is there a way to achieve this and if yes could anybody give me hint or a keyword how to manage this?

When running the Spring-Boot application with a KafkaListener, the listener will per default try to listen to Kafka. If the KafkaBroker is invalid or missing, then you will get a org.apache.kafka.common.KafkaException.
You can change the default behaviour of the container factory by setting the autoStartup property to false. One way to do this is by adding autoStartup = "false" element to your KafkaListener annotation:
#KafkaListener(topics = "some_topic", autoStartup = "false")
public void fooEventListener(){
Now your spring boot application will start. You will still get an error when trying to use the KafkaListener if the broker is still down or invalid, but you will now be able to handle the error within your Java code instead of a Spring Boot server crash.
Documentation about KafkaListner autoStartup element.
It have to be mentioned that the error you are receiving (TimeoutException) is not because the broker is down, it is what Kafka will throw if the buffer is full.
The batch records will then be removed from the queue and will not be delivered to the broker. This error will not be the reason for you application using Kafka not to start.

Related

NoSuchMethodError when trying to map Kafka binder to input method

The following is prompted in console when trying to launch a spring cloud streams project with the Kafka binder active:
org.springframework.context.ApplicationContextException: Failed to start bean 'inputBindingLifecycle';
Caused by: java.lang.NoSuchMethodError: java.util.List.of(Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;Ljava/lang/Object;)Ljava/util/List;
My input method goes as follows using Spring Cloud functions:
#Bean
public Function<Message<String>, byte[]> exec() {
return input -> ...
Now, having Kafka in place, my .properties file looks as follows:
spring.cloud.stream.function.bindings.exec-in-0=in
spring.cloud.stream.bindings.in.destination=topic-0
spring.cloud.stream.function.bindings.exec-out-0=out
spring.cloud.stream.bindings.out.destination=topic-1
spring.cloud.stream.bindings.in.binder=kafka
spring.cloud.stream.kafka.bindings.in.consumer.configuration.value.deserializer=org.apache.kafka.common.serialization.StringDeserializer
spring.cloud.stream.bindings.out.binder=kafka
spring.cloud.stream.kafka.bindings.out.producer.configuration.value.serializer=org.apache.kafka.common.serialization.ByteArraySerializer
Am I missing any configs for the input method? Should that method be different for Kafka (already tested this with PubSub and it works)?
The error in your stack trace gives us a clue that you are facing this problem: https://github.com/spring-projects/spring-integration/issues/3761.
So, or upgrade to the latest Spring Cloud Stream: https://spring.io/projects/spring-cloud-stream#learn
Or to the latest Spring Integration: https://spring.io/projects/spring-integration#learn
Or just use Java > 8 !

Spring Boot JMS listener won't deploy on EAP 7.3 (JBoss/Wildfly)

I'm trying to deploy on EAP 7.3 (ex JBoss, commercial release of Wildfly) an JMS listener like below:
...
#JmsListener(destination = "${jms.destination.name}")
public void onMessage(final Message msg) throws JMSException {
logger.info("*** MessageReceiver.onMessage(): got message {}", ((TextMessage) msg).getText());
}
...
Deploying it on the app server I get the following warning:
2021-06-03 15:57:45,836 WARN [org.springframework.jms.listener.DefaultMessageListenerContainer] (DefaultMessageListenerContainer-7) Setup of JMS message listener invoker failed for destination 'jms.queue.BanQ' - trying to recover. Cause: There is no queue with name jms.queue.BanQ
The deployment gets stuck and the warning above is displayed continuously, every couple of seconds.
So what seems to happen is that the mention queue doesn't exist. However, looking in the console I can see that:
So, as shown in the figure above, the queue named jms.queue.Bank exists. What might be the problem here ?
Many thanks in advance for any help.
Kind regards,
Seymour

Error Handling with Apache Camel and ActiveMQ - so breaking out of pipeline for exchange

I've been back and forth with an issue on our system that even with some research around the forums and several tests, we can't seem to be able to fix.
I'll try to be as clear as I can with what we are dealing with
We have a main service with a route that reads from an activemq queue ( spring boot with embedded broker ) sends it to a Route(B) and then ships everything to a final Route(C) . Route(B) is on a dependency of the service.
Camel Version: 3.3.0
Spring-boot version: 2.3.3.RELEASE
Route A:
onException(Exception::class.java)
.handled(true)
.bean("foo.ErrorProcessor", "processError")
from("activemq:queue:myqueue")
.routeId("myroute")
.to("direct:my_external_route")
.to(ExchangePattern.InOnly,"direct:myroute_result")
Route B:
onException(Exception::class.java)
.handled(true)
.bean("foo.ErrorProcessor", "processError")
from("direct:my_external_route")
.routeId("my_external_route")
.process {something()} //This processor can throw exceptions that are treated in our processor
Route C:
from("direct:myroute_result")
.process(someProcess())
.to(ExchangePattern.InOnly,"activemq:queue:results_queue")
Spring Boot activemq configs
spring:
jmx:
enabled: true
activemq:
broker-url: vm://localhost?broker.persistent=false,useShutdownHook=false
in-memory: true
non-blocking-redelivery: true
packages:
trust-all: false
trusted: com.mypackage
pool:
block-if-full: true
block-if-full-timeout: -1
enabled: false
idle-timeout: 30000
max-connections: 10
time-between-expiration-check: -1
use-anonymous-producers: true
Everything runs very well and smoothly when B's processors do not throw exceptions. When it does, even though they are being treated and a normal object is being returned in the message body, all we have on the logs is
2021-04-10 15:33:32.354 DEBUG [#1 - JmsConsumer[consumerName]] o.a.c.p.Pipeline
: Message exchange has failed: so breaking out of pipeline for exchange: Exchange[ID-1234] Handled by the error handler. {}
We even added a default error handler to our activemq connection factory but nothing happens there as well. We have a DLQ consumer who also does not seems to get anything. The error processor on routeA also does not catches anything which is expected since the exception was handled previously.
Has anyone ever had this issue or similar ? I know that some issues between Camel and the JMS component regarding error handling were raised in the past but we are struggling to understand what is the root of this issue.
Thanks in advance,
Pedro
Probably what you are looking for is the continued option on your Route B exception clause. This option allows you to continue routing to the original route as if the exception did not occur. Do not use the handled option as it will not allow routing to the original route but break out.
So your Route B should be defined as something like this:
onException(Exception::class.java) .continued(true)
.bean("foo.ErrorProcessor", "processError")
from("direct:my_external_route")
.routeId("my_external_route")
.process {something()}
Refer the camel documentation for more details: CAMEL EXCEPTION CLAUSE

What's the correct exception type to NACK a message using annotation based listener in spring-boot with amqp?

I'm using spring boot with spring-amqp and annotation based listener to consume message from a rabbitmq broker.
I've a spring component which contains a method like this:
#RabbitListener(queues = "tasks")
public void receiveMessage(#Payload Task task) {...}
I'm using the AUTO mode to acknowledge messages after successful execution of receiveMessage(...). If i detect a special error, i'm throwing AmqpRejectAndDontRequeueException to get this message into a configured dead letter queue. Now i need to nack a message only, so that the message gets requeued into the main queue of rabbitmq and another consumer has the possibility to work on that message again.
Which exception should i throw for that? I wouldn't like to use channel.basicNack(...) like described here (http://docs.spring.io/spring-integration/reference/html/amqp.html) if possible.
As long as defaultRequeueRejected is true (the default) in the container factory, throwing any exception other than AmqpRejectAndDontRequeueException will cause the message to be rejected and requeued.
The exception must not have a AmqpRejectAndDontRequeueException in its cause chain (the container traverses the causes to ensure there is no such exception).

org.apache.activemq.ActiveMQConnectionFactory cannot be cast to javax.jms.QueueConnectionFactory

I have integrated JMS in my project and getting the Exception as ActiveMQConnectionFactory cannot be cast to javax.jms.QueueConnectionFactory while calling the JMS receiver from servletcontext listener but it works fine from public static void main method and able to receive message from queue asynchronously.I am able to send the message to queue using queueconnection and queuesession from my web app and using the same qconnection approach in JMS receiver function which implements MessageListener interface.
Can any one suggest me what is the best way to start the JMS receiver or consumer automatically when web app starts because i use servletcontextlistener to start listening the message queue automatically.
(both JMS queuesender and queuereceiver works fine from public static void main method and problem starts only after calling the queuereceiver from contextinitialize method)
Maybe this post can help you.
The cause there were two version of the ActiveMQ-jars in the classpath, said the poster.
In my case, the cause was 2 versions of javax.jms in the classpath: the one that came with ActiveMQ, and the one I was using to compile my sources (ActiveMQ is supposed to be just a test dependency for my application). I changed the scope of my maven dependency javax.jms:jms:1.1 from compile to provided, which removed the javax.jms-jar from my WAR file, and the exception disappeared.
Yes there's a version problem, I was able to fix this problem by using these version of activemq, jms and j2ee dependencies.
ActiveMQ 5.8.0 and above
activemq-broker-5.8.0
activemq-client-5.8.0
geronimo-jms_1.1_spec-1.1.1
geronimo-j2ee-management_1.1_spec-1.0.1
Earlier version of ActiveMQ
activemq-core-5.5.1
geronimo-j2ee-management_1.0_spec-1.0
geronimo-jms_1.1_spec-1.1.1
Check the versions it'll help

Resources