Kafka with Spring Integration - consumer-timeout vs read timeout? - java

With the configuration
Using the spring-integration-kafka extention and the following configuration:
<int-kafka:zookeeper-connect id="zookeeperConnect"
zk-connect="#{kafkaConfig['zooKeeperUrl']}" zk-connection-timeout="10000"
zk-session-timeout="10000" zk-sync-time="2000" />
<int-kafka:consumer-context id="consumerContext" consumer-timeout="5000" zookeeper-connect="zookeeperConnect">
the timeout is the time of waiting for a message or the time of waiting for a message and reading that message? is this value different from read timeout?

consumer.timeout.ms -1
from Kafka configuration
Throw a timeout exception to the consumer if no message is available
for consumption after the specified interval

from git-hub-spring-integration-kafka-repository
"In the above consumer context, you can also specify a consumer-timeout value which would be used to timeout the consumer in case of no messages to consume. This timeout would be applicable to all the streams (threads) in the consumer. The default value for this in Kafka is -1 which would make it wait indefinitely. However, Sping Integration overrides it to be 5 seconds by default in order to make sure that no threads are blocking indefinitely in the lifecycle of the application and thereby giving them a chance to free up any resources or locks that they hold. It is recommended to override this value so as to meet any specific use case requirements. By providing a reasonable consumer-timeout on the context and a fixed-delay value on the poller, this inbound adapter is capable of simulating a message driven behaviour."

Related

"Fire then Return" route in Apache Camel

We use Apache Camel to trigger some processes within our applications, e.g:
from("quartz2://sometThing/someQueue?cron=0+0+4+?+*+MON-SUN").setBody(constant(""))
.routeId(this.getClass().getSimpleName())
.to("jms:some-trigger-queue");
We then have a bunch of processors off the trigger queue to run each job, e.g:
from("jms:some-trigger-queue")
.processRef("someProcessor");
Some of these processors will in turn write messages to JMS queues. The problem I'm trying to fix is that the processors won't commit the JMS messages to the broker until the entire process is complete. I suspect this is because there is a message in flight on the trigger queue ("jms:some-trigger-queue") and because the processors are using the same context they won't commit until the in flight message is cleared (FYI I have tried forcing new transactions to be created within the processors but had no luck).
So my question is if I only had one processor (or my didn't care about the processors running at the same time) - how could I configure camel to trigger the processor and immediately move on (i.e. to remove the trigger message from being in flight)?
If you want to call the processors and then immediately move on then you can use the Wire Tap EIP (https://camel.apache.org/manual/latest/wireTap-eip.html).
For example:
from("jms:some-trigger-queue")
.wireTap("direct:callProcessor");
from("direct:callProcessor")
.processRef("someProcessor");
This way the direct:callProcessor route will be executed on a separate thread and jms:some-trigger-queue will continue routing without waiting for a response from direct:callProcessor.

Azure eventhub Kafka org.apache.kafka.common.errors.TimeoutException for some of the records

Have a ArrayList containing 80 to 100 records trying to stream and send each individual record(POJO ,not entire list) to Kafka topic (event hub) . Scheduled a cron job like every hour to send these records(POJO) to event hub.
Able to see messages being sent to eventhub ,but after 3 to 4 successful run getting following exception (which includes several messages being sent and several failing with below exception)
Expiring 14 record(s) for eventhubname: 30125 ms has passed since batch creation plus linger time
Following is the config for Producer used,
props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
props.put(ProducerConfig.ACKS_CONFIG, "1");
props.put(ProducerConfig.RETRIES_CONFIG, "3");
Message Retention period - 7
Partition - 6
using spring Kafka(2.2.3) to send the events
method marked as #Async where kafka send is written
#Async
protected void send() {
kafkatemplate.send(record);
}
Expected - No exception to be thrown from kafka
Actual - org.apache.kafka.common.errors.TimeoutException is been thrown
Prakash - we have seen a number of issues where spiky producer patterns see batch timeout.
The problem here is that the producer has two TCP connections that can go idle for > 4 mins - at that point, Azure load balancers close out the idle connections. The Kafka client is unaware that the connections have been closed so it attempts to send a batch on a dead connection, which times out, at which point retry kicks in.
Set connections.max.idle.ms to < 4mins – this allows Kafka client’s network client layer to gracefully handle connection close for the producer’s message-sending TCP connection
Set metadata.max.age.ms to < 4mins – this is effectively a keep-alive for the producer metadata TCP connection
Feel free to reach out to the EH product team on Github, we are fairly good about responding to issues - https://github.com/Azure/azure-event-hubs-for-kafka
This exception indicates you are queueing records at a faster rate than they can be sent. Once a record is added a batch, there is a time limit for sending that batch to ensure it has been sent within a specified duration. This is controlled by the Producer configuration parameter, request.timeout.ms. If the batch has been queued longer than the timeout limit, the exception will be thrown. Records in that batch will be removed from the send queue.
Please check the below for similar issue, this might help better.
Kafka producer TimeoutException: Expiring 1 record(s)
you can also check this link
when-does-the-apache-kafka-client-throw-a-batch-expired-exception/34794261#34794261 for reason more details about batch expired exception.
Also implement proper retry policy.
Note this does not account any network issues scanner side. With network issues you will not be able to send to either hub.
Hope it helps.

ActiveMQ - cannot rollback non transaced session INVIDUAL_ACK

Is it possible to rollback async processed message in ActiveMQ? I'm consuming next message while first one is still processing, so while I'm trying to rollback the first message on another (not activemq pool) thread, I'm getting above error. Eventually should I sednd message to DLQ manually?
Message error handling can work a couple ways:
Broker-side 'redelivery policy'. Where the client invokes a rollback n number (default is usually 6 retries) of times and the broker automatically moves the message to a Dead Letter Queue (DLQ)
Client-side. Application consumes the message and then produces to the DLQ.
Option #1 is good for unplanned/planned outages-- database down, etc. Where you want automatic retry. The re-delivery policy can also be configured when the client connects to the broker.
Option #2 is good for 'bad data' scenarios where you know the message will never be able to be processed. This is ideal, because you can move the message on the 1st consumption and not have to reject the message n number of times.
When you combine infinite retry with #1 and include #2 in your application flow, you can have a robust process flow of automatic retry, and move-bad-data-out-of-the-way-quickly. Best of breed =)
ActiveMQ Redelivery policy

String Cloud Stream - How to force a message to be dead-lettered without requeing if retry is enabled?

We are using Spring Cloud Stream and we have retry enabled using maxAttempts > 1 in our consumer. Is there any way to force a message to send immediately to a DLQ, i.e. to bypass the requeuing e.g. throwing a special exception in the consumer listener when the message is processed?
The retry policy in the binder supports that but it's not currently exposed to be configurable.
This is one of a number of exception handling improvement stories we are starting to work on.

Critical RabbitMQ method arguments

I'm trying to read up and understand 3 fundamental methods in the RabbitMQ Java client:
Channel#basicConsume
Channel#basicPublish; and
DefaultConsumer#handleDelivery
These methods have several arguments that are cryptic and mysterious, and although the Javadocs do provide some explanation of what they are, don't really make it clear/obvious as to what these arguments do:
Channel#basicConsume
consumerTag - a client-generated consumer tag to establish context
noLocal - true if the server should not deliver to this consumer messages published on this channel's connection
exclusive - true if this is an exclusive consumer
arguments - a set of arguments for the consumer
Channel#basicPublish
exchangeName - the exchange to publish the message to
routingKey - the routing key
DefaultConsumer#handleDelivery
envelope - packaging data for the message
These methods, and using them correctly, are crucial to using RabbitMQ in its simplest form (basic publishing & consuming of messages to and from a queue). Until I understand what these arguments are - and what they imply/do on the server-side - I'm stuck and unsure of how to proceed with the library.
Can some battle-weary RabbitMQ veteran help a newbie like myself understand these 7 method arguments, and what they are used for? The Javadoc explanations just aren't clear enough. For example: "arguments - a set of arguments for the consumer". What?!?! Or: "exclusive - true if this is an exclusive consumer"...well what's an exclusive consumer?!?! Etc. Thanks in advance!
Follow below two link :-
https://www.rabbitmq.com/ttl.html
http://www.rabbitmq.com/amqp-0-9-1-quickref.html
Java creates a queue in which messages may reside for at most 60 seconds:
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-message-ttl", 60000);
channel.queueDeclare("myqueue", false, false, false, args);
To throughly understand the implementation of RabbitMQ you might have to go through the AMQP protocol specification and reference. In general irrespective of the language the specification should explain all the parameters
Below link explains about consumer-tag
Exclusive:
Exclusive queues may only be accessed by the current connection, and are deleted when that connection closes. Passive declaration of an exclusive queue by other connections are not allowed.
The server MUST support both exclusive (private) and non-exclusive (shared) queues.
The client MAY NOT attempt to use a queue that was declared as exclusive by another still-open connection. Error code: resource-locked
Customer tag:
Specifies the identifier for the consumer. The consumer tag is local to a channel, so two clients can use the same consumer tags. If this field is empty the server will generate a unique tag.
The client MUST NOT specify a tag that refers to an existing consumer. Error code: not-allowed
The consumer tag is valid only within the channel from which the consumer was created. I.e. a client MUST NOT create a consumer in one channel and then use it in another. Error code: not-allowed
AMQP extensions to understand additional Args (Map)
http://www.rabbitmq.com/extensions.html
Example - TTL:
Per-Queue Message TTL
The x-message-ttl argument to queue.declare controls for how long a message published to a queue can live before it is discarded. A message that has been in the queue for longer than the configured TTL is said to be dead. Note that a message routed to multiple queues can die at different times, or not at all, in each queue in which it resides. The death of a message in one queue has no impact on the life of the same message in other queues.
The server guarantees that dead messages will not be included in any basic.get-ok or basic.deliver methods. Further, the server will try to reap messages at or shortly after their TTL-based expiry.
The value of the x-message-ttl argument must be a non-negative 32 bit integer (0 <= n <= 2^32-1), describing the TTL period in milliseconds. Thus a value of 1000 means that a message added to the queue will live in the queue for 1 second or until it is delivered to a consumer. The argument can be of AMQP type short-short-int, short-int, long-int, or long-long-int.
This example in Java creates a queue in which messages may reside for at most 60 seconds:
Map<String, Object> args = new HashMap<String, Object>();
args.put("x-message-ttl", 60000);
channel.queueDeclare("myqueue", false, false, false, args);
The original expiry time of a message is preserved if it is requeued (for example due to the use of an AMQP method that features a requeue parameter, or due to a channel closure).
Setting x-message-ttl to 0 causes messages to be expired upon reaching a queue unless they can be delivered to a consumer immediately. Thus this provides an alternative to basic.publish's immediate flag, which the RabbitMQ server does not support. Unlike that flag, no basic.returns are issued, and if a dead letter exchange is set then messages will be dead-lettered.
Per-Message TTL
A TTL can be specified on a per-message basis, by setting the expiration field in the basic AMQP class when sending a basic.publish.
The value of the expiration field describes the TTL period in milliseconds. The same constraints as for x-message-ttl apply. Since the expiration field must be a string, the broker will (only) accept the string representation of the number.
When both a per-queue and a per-message TTL are specified, the lower value between the two will be chosen.
This example in Java publishes a message which can reside in the queue for at most 60 seconds:
byte[] messageBodyBytes = "Hello, world!".getBytes();
AMQP.BasicProperties properties = new AMQP.BasicProperties();
properties.setExpiration("60000");
channel.basicPublish("my-exchange", "routing-key", properties, messageBodyBytes);

Categories