Sleuth Brave headers are not compatible with JMS spec - spring

I am using Sleuth in Spring Integration project to pass along tracing headers across JMS messages. IBM MQ is used for Queue Manager. This configuration is working all fine functionally. However, all the Brave header X-B3-* are not compatible with JMS spec? As IBM MQ client lib throws a warning about this -
Warning Message:
JMSCC0049: The property name 'X-B3-Sampled' is not a valid Java(tm) identifier.
JMS Payload:
2018-03-13 11:54:42.919 INFO [domain-batch,d5a9e59728d0846a,954264c0e98a448b,false] 141252 --- [ask-scheduler-2] c.l.p.module.biz.BackendServiceClient : Message: GenericMessage [payload=2018-03-13T11:54:42.856, headers={JMS_IBM_Character_Set=UTF-8, jms_destination=queue:///DEV.QUEUE.1, JMS_IBM_Encoding=273, jms_timestamp=1520956482869, JMS_IBM_PutApplType=28, spanId=9a20699cdc50f7e9, JMS_IBM_Format=MQSTR , JMSXDeliveryCount=1, X-B3-Sampled=0, JMS_IBM_PutTime=15544287, X-B3-TraceId=d5a9e59728d0846a, id=d40cfbec-5dce-a8cd-0d96-da0e3d761459, jms_messageId=ID:414d5120514d3120202020202020202035a3a35aae92fa20, JMS_IBM_MsgType=8, JMSXUserID=app , X-B3-ParentSpanId=385f47b14a627448, priority=4, JMSXAppID=BackendServiceApplication , spanTraceId=d5a9e59728d0846a, spanParentSpanId=385f47b14a627448, nativeHeaders={spanTraceId=[d5a9e59728d0846a], spanId=[9a20699cdc50f7e9], spanParentSpanId=[385f47b14a627448], spanSampled=[0]}, jms_redelivered=false, JMS_IBM_PutDate=20180313, X-B3-SpanId=9a20699cdc50f7e9, spanSampled=0}]
Is there an option in sleuth to change the header naming convention for JMS? Similar to the baggage naming convention ? Hopefully I am not missing something from the documentation.
EDIT:
Add the following log level config to suppress the warning exception
logging:
level:
org.springframework.integration.jms.DefaultJmsHeaderMapper: ERROR

I think those warnings can be ignored. We're setting both the X-B3-Sampled and the spanSampled headers (check this out https://github.com/spring-cloud/spring-cloud-sleuth/blob/master/spring-cloud-sleuth-core/src/main/java/org/springframework/cloud/sleuth/instrument/messaging/MessageHeaderPropagation.java). The first ones are not compatible the second ones are JMS compatible

https://github.com/openzipkin/brave/issues/584 is the longer topic in brave. JMS is unfortunate.
Luckily, we've recently changed the format of the successor to B3 "Trace Context" which no longer uses hyphens so won't make JMS sad. https://github.com/w3c/distributed-tracing/tree/master/trace_context Note: this is not an implementation version of the spec yet, but anyway you can follow it.

Related

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

Spring kafka transaction id is wrong at start?

I'm using spring kafka 2.2.2.RELEASE
Our broker has strict authorization verification.
Here is our client configuration :
spring.kafka.producer.transaction-id-prefix=test.
topic : topic
groupId: group
It should generate a transactional id : "test.group.topic0"
Problem:
When I start the application, KafkaMessageListenerContainer#onPartitionsAssigned is called and the transactional id used is "test0".
It seems like in this case, the kafkaTemplate is not considered to be in a listenerContainer.
This is leading to an Unauthorized exception because this transactional id is refused by the broker
Question
Is it normal ?
Thanks; it's a bug; I opened an issue.

Spring JMS Message Redelivery not working as expected for CLIENT_ACKNOWLEDGE mode

My environment: spring 4.1, JBoss EAP 6.4, IBM MQ 8.0:
Messages are not redelivered in the case where Listener throws RuntimeException.
I have the following in JmsConfig:
#Bean
DefaultMessageListenerContainer defaultMessageListenerContainer(QueueConnectionFactory connectionFactory, JndiDestinationResolver dr, MessageListener ml) {
DefaultMessageListenerContainer mlc = new DefaultMessageListenerContainer();
mlc.setConnectionFactory(connectionFactory);
mlc.setMessageListener(ml);
mlc.setDestinationName(jndiInQueue);
mlc.setDestinationResolver(dr);
mlc.setSessionTransacted(true);
mlc.setSessionAcknowledgeMode(Session.CLIENT_ACKNOWLEDGE);
return mlc;
}
If I use a JmsTransactionManager and pass it to the above method and use like so:
mlc.setTransactionManager(tm)
Following warnings are written to the log:
It is not valid to commit a non-transacted session, and the behavior is the same, no redelivery.
ConnectionFactory is obtained via JNDI, I wonder if sourcing the ConnectionFactory through jndi has something to do with this?
From the AbstractMessageListenerContainer Javadocs:
In order to consistently arrange for redelivery with any container variant, consider "CLIENT_ACKNOWLEDGE" mode or - preferably - setting "sessionTransacted" to "true" instead
There is a similar question on SO.
Flip your ack mode to Session.SESSION_TRANSACTED instead of CLIENT_ACKNOWLEDGE.
Client Ack mode doesn't work as most folks want it.. and is a common "gotcha" in JMS. It acknowledges current message AND all previous messages in the session. It is not per-message acknowledgement.
Edit:
Also check related post-- IBM MQ may require you to use the "XA" versions of the connection factory class.
ref: Websphere Liberty profile - transacted Websphere MQ connection factory

Can I get JMSXDeliveryCount and JMSDestination using org.springframework.messaging.Message

I am using Spring JMS 4.1.2, and I am using org.springframework.messaging.Message as the input payload in the JMS Listener. I am listening to an Active MQ Queue, and I would like to know if it is possible to obtain the JMSXDeliveryCount and JMSDestination using the org.springframework.messaging.Message, or if I have to use the javax.jms.Message class to accomplish this.
Thanks,
Juan
The delivery count property is mapped by default; I just ran a test...
message: GenericMessage [payload=jms test, headers={jms_redelivered=true, JMSXDeliveryCount=2, ...
Standard headers are mapped with a jms_ prefix all; message properties are mapped as-is.
The destination from which the message is received is not currently mapped to the message.
You would need to add a custom JmsHeaderMapper - perhaps a subclass of DefaultJmsHeaderMapper.
I opened a JIRA issue to make this standard.

How to test WSO2 Message Broker with JMeter

I'm having some issues getting JMeter to work against the WSO2 Message Broker using the JMS Publisher. I had JMeter working against ActiveMQ but I'm still new with the tool.
I copied the client libraries over to jmeter wso2mb-2.0.1\client-lib to apache-jmeter-2.9\lib
andes-client-0.13.wso2v4.jar
geronimo-jms_1.1_spec-1.1.0.wso2v1.jar
Settings:
Context Factory : org.wso2.andes.jndi.PropertiesFileInitialContextFactory
Provider Url : amqp://admin:admin#clientID/carbon?brokerlist='tcp://localhost:5672'
Connection Factory : qpidConnectionfactory
...also tried several other values
Destination: dynamicQueues/test
The error I'm getting is on the Connection Factory field.
I've tried several different values all of which generate a naming error like there is a setting missing.
When I leave it blank I get:
javax.naming.NamingException: Expected javax.jms.ConnectionFactory, found org.wso2.andes.jndi.ReadOnlyContext
Does anyone know what I'm missing here?
Suspect it's something simple.
I found the problem.
In short the qpid context factory org.wso2.andes.jndi.PropertiesFileInitialContextFactory does not use fields the same way as the activeMQ context factory org.apache.activemq.jndi.ActiveMQInitialContextFactory.
While ActiveMQ allows you to not use a separate properties file with Jmeter, Qpid does not.
Jmeter JMS Publisher:
Context Factory : org.wso2.andes.jndi.PropertiesFileInitialContextFactory
Provider Url : nameOfYouFile.properties
Connection Factory : qpidConnectionfactory
Destination : <QueuePropertyName>
nameOfYouFile.properties:
connectionfactory.qpidConnectionfactory = amqp://admin:admin#clientID/carbon?brokerlist='tcp://localhost:5672'
queue.JMeterQueue = JMeterQueue
Reference:
Qpid Wiki

Resources