I added a mqtt interceptor into my artemis broker in order to intercept mqtt client connection:
public class SimpleMQTTInterceptor implements MQTTInterceptor
{
#Override
public boolean intercept(final MqttMessage mqttMessage, RemotingConnection connection) throws ActiveMQException
{
System.out.println("MQTT Interceptor gets called ");
if (mqttMessage instanceof MqttConnectMessage)
{
System.out.println("MQTT connection intercepted ");
}
return true;
}
My client apache paho connect to the broker via this port "ws://0.0.0.0:61614".
My problem is that only message published to topics are intercepted.
Why this doesn't intercept CONNECT message ?
The current version of ActiveMQ Artemis, 2.2.0, at the time I write this response, only supports intercepting MQTT Publish control packets. I opened a pull request adding that feature, therefore, it should be present on future versions.
Related
I have this components that publishes messages to a broker I want to export the same message to prometheus
public class ModuleAMessagePublisher {
#Inject
#InternalBroker
private MessagePublisher messagePublisher;
public void publish(String topic, final String message) {
log.info("<><><><><><><><><> (MQ) PUBLISH MODULEA MESSAGE: <><><><><><<>\n", message);
messagePublisher.publish(topic, message);
// code for prometheus to be added here
}
}
I'm so new to using prometheus and I'm not sure if it's possible to be done or how can it be done
You can use the hivemq extention provided to host all the metrics on your hivemq server as described here -
https://www.hivemq.com/extension/prometheus-extension/
This will enable a /metrics endpoint on hivemq server which can be consumed by your prometheus server.
we have a microservice which consumes a message using #RabbitListener and persist data into database, generate a response on successful processing of message and send it using #sendTO to different queue for auditing.
When running Rabbit in HA failover, while sending response if connection is lost the message currently being processed is correctly returned to the queue but database transaction (jpa transaction in our case) is not rolled back , response is never sent.
I read from this issue(https://github.com/spring-projects/spring-amqp/issues/696) that this is "best effort 1PC" transaction synchronization; RabbitMQ does not support XA transactions. The Rabbit tx is committed after the DB tx and there is a possibility the DB tx might commit and the rabbit rolled back; you have to deal with the small possibility of duplicate messages.
But in our case when we retry request, we are treating it as duplicate message and response is never created for this request. is there a way where we can only retry sending response message in case of connection lost exceptions rather than reprocessing request again? I looked at ConditionalRejectingErrorHandler.DefaultExceptionStrategy, it has access only to original request,no way to access response lost during connection failure. Please suggest what's the best way to handle this?
our code looks like:
SpringBootApplication
#EnableJpaRepositories("com.***")
#EnableJpaAuditing
#EnableTransactionManagement
#EnableEncryptableProperties
public class PcaClinicalValidationApplication {
#RabbitListener(queues = "myqueue"
#SendTo("exchange/routingKey")
#Timed) description = "Time taken to process a request")
public Message receivemessage(HashMap<String, Object> myMap, Message requestMessage)
throws Exception {
//business logic goes here
Message message = MessageBuilder.fromMessage(requestMessage)
//add some headers
return message;
}
public SimpleRabbitListenerContainerFactory rabbitListenerContainerFactory(ConnectionFactory connectionFactory,
SimpleRabbitListenerContainerFactoryConfigurer configurer) {
SimpleRabbitListenerContainerFactory factory = new SimpleRabbitListenerContainerFactory();
configurer.configure(factory, connectionFactory);
factory.setRetryTemplate(new RetryTemplate());
factory.setReplyRecoveryCallback(ctx -> {
Message failed = SendRetryContextAccessor.getMessage(ctx);
Address replyTo = SendRetryContextAccessor.getAddress(ctx);
Throwable t = ctx.getLastThrowable();
//wrote to a file
serializer.serialize(failed);
return null;
});
return factory;
}
The listener container factory uses a RabbitTemplate in its replyTemplate property - this is used to send the reply.
You can configure a RetryTemplate into that RabbitTemplate to retry sending the reply.
When retries are exhausted, you can add a RecoveryCallback which will get the failed reply and you can save it off someplace and use it when the redelivery occurs.
Trying to connect InfluxDB using
https://github.com/influxdata/influxdb-java
I didn't see any option for setting ssl as true and verifySSL as false. Its available in php client. Can someone help on it?
There is no proper documentation available for java client to connect influxDB hosted in AWS, where the connection will be a https connection.
Here is the code and exception thrown.
InfluxDB influxDB = InfluxDBFactory.connect(databaseURL , userName, password);
Pong response = influxDB.ping();
Exception Stacktrace:
org.influxdb.InfluxDBIOException: java.net.ProtocolException: Unexpected status line:
at org.influxdb.impl.InfluxDBImpl.execute(InfluxDBImpl.java:800)
at org.influxdb.impl.InfluxDBImpl.executeQuery(InfluxDBImpl.java:783)
at org.influxdb.impl.InfluxDBImpl.describeDatabases(InfluxDBImpl.java:709)
Here is a workaround.. some positive result. But, its unsecured way of communication.
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.hostnameVerifier(new HostnameVerifier() {
#Override
public boolean verify(String hostname, SSLSession session) {
return true;
}
});
InfluxDB influxDB = InfluxDBFactory.connect(databaseURL , userName, password, builder);
I have modified to implement channel interceptor in spring-websocket-portfolio sample application (https://github.com/rstoyanchev/spring-websocket-portfolio). whenever the client disconnects, channel interceptor is processed twice. I have similar implementation in my production application. As it is being invoked twice so it has unwanted result for the 2nd invocation. I had put work around for the time being. But wondering why my channel interceptor is invoked twice? Any help would be highly appreciated.
modified items: WebSocketConfig.java:
#Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.setInterceptors(channelInterceptor());
}
#Bean
public ChannelInterceptor channelInterceptor() {
return new ChannelInterceptor();
}
ChannelInterceptor :
package org.springframework.samples.portfolio.config;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.simp.stomp.StompHeaderAccessor;
import org.springframework.messaging.support.ChannelInterceptorAdapter;
public class ChannelInterceptor extends ChannelInterceptorAdapter {
#Override
public void postSend(Message<?> message, MessageChannel channel, boolean sent) {
StompHeaderAccessor sha = StompHeaderAccessor.wrap(message);
System.out.println(sha.getCommand() + " " + sha);
switch (sha.getCommand()) {
case CONNECT: {
System.out.println("connected:"+sha.getSessionId());
break;
}
case DISCONNECT: {
System.out.println("disconnected:"+sha.getSessionId());
break;
}
default:
System.out.println("default:"+sha.getCommand());
break;
}
}
}
logs:
**disconnected**:9k1hvln6
**disconnected**:9k1hvln6
Disconnect events may happen more than once for the same session, your interceptor should be idempotent and ignore duplicate events.
You may also consider using application events (SessionConnectEvent, SessionDisconnectEvent...) instead of a channel interceptor. Here's an example of an idempotent event listener: https://github.com/salmar/spring-websocket-chat/blob/master/src/main/java/com/sergialmar/wschat/event/PresenceEventListener.java
Generally a DISCONNECT frame comes the client side, is processed in the StompSubProtocolHandler, and is then propagated to the broker. However, a connection can also be closed or lost without a DISCONNECT frame. Regardless of how a connection is closed, the StompSubProtocolMessageHandler generates a DISCONNECT frame. So there is some redundancy on the server side to ensure the broker is aware the client connection is gone.
As Sergi mentioned you can either subscribe to listen for SessionDisconnectEvent (of which there should be only one) and other AbstractSubProtocol events or ensure your code is idempotent.
I am using spring amqp publishing my messages to RabbitMQ using an outbound gateway. I have set publisher confirms on the connection factory and added my custom callback listener.
The problem is that my CorrelationData is always null and i can't add any correlation data on an outbound gateway. This is only applicable for an outbound channel adapter.
For an outbound gateway will publisher confirms even work?
EDIT
My configuration is below. I looked through the SI code and yes, publisher confirms, are enabled. The problem is what I do when I receive a NACK?
Because of the outbound gateway I don't need a correlation id to handle the response, there is already a thread listening on a temporary reply queue for the response.
What exactly is the point of using publisher confirms with an outbound gateway? If no response is coming or my Rabbit nodes go down I will encounter exceptions. Is there a scenario when I will lose messages?
<rabbit:connection-factory id="rabbitConnectionFactory"
host="someip" port="5672"
username="username"
password="password"
virtual-host="vhost"
publisher-confirms="true"/>
<rabbit:admin connection-factory="rabbitConnectionFactory"/>
<rabbit:template id="amqpTemplate" connection-factory="rabbitConnectionFactory"
confirm-callback="messagesConfirmCallback"/>
<int-amqp:outbound-gateway
request-channel="channel"
amqp-template="amqpTemplate"
exchange-name="exchange"
routing-key-expression="headers['queueSpecific']+'.queue'">
<amqp:request-handler-advice-chain>
<ref bean="retryAdvice"/>
</amqp:request-handler-advice-chain>
</int-amqp:outbound-gateway>
And my callback is also simple
#Component
public class MessagesConfirmCallback implements RabbitTemplate.ConfirmCallback {
private final static Logger LOGGER = LoggerFactory.getLogger(MessagesConfirmCallback.class);
#Override
public void confirm(CorrelationData correlationData, boolean ack) {
if(ack){
LOGGER.info("ACK received");
}
else{
LOGGER.info("NACK received");
}
}
}
This
Unfortunately, I don't see an easy work around with the gateway; the underlying RabbitTemplate only supports adding correlation data on send() methods, not the sendAndReceive methods.
The two options I can think of is to (1) use a pair of outbound and inbound adapters (instead of the gateway), but you'll have to do your own request/reply correlation in that case.
Alternatively (2), use the RabbitTemplate.execute() and in the doInRabbit callback, add code similar to that in the RabbitTempalate.doSendAndReceive, while setting the correlation data as is done in doSend().
I opened a JIRA Issue.