I have a spring boot app consuming messages from multiple Solace queues using Camel's jmsComponent. I have defined a Camel route for each queue connection and a Camel Processor for converting messages into json. There is a high volume of messages coming from the queues and my program is not able to keep up with the speed.
Route:
#Component
public class SomeRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
from("jms:{{queue.name}}").process("xmlToJsonProcessor")
.to("kafka:{{topic}}?brokers={{spring.kafka.bootstrap-servers}}&securityProtocol={{spring.kafka.properties.security.protocol}}&saslMechanism={{spring.kafka.properties.sasl.mechanism}}&saslJaasConfig={{spring.kafka.properties.sasl.jaas.config}}");
}
}
I've been looking up how to split each route into its own thread but no luck so far. Any ideas?
Why don't you increase the number of consumers for each queue?
#Override
public void configure() throws Exception {
from("jms:{{queue.name}}?concurrentConsumers=10")
.process("xmlToJsonProcessor")
.to(".....");
}
Related
I have one microservice in which I have one rest controller and one rabbitMQ receiver, sometimes when I start the server receiver and API both are working fine but after some time receiver is not working it stops receiving new messages from the queue.
This is my rabbit configuration bean class:
#Configuration
public class RabbitMQConfiguration {
#Bean
public Queue claimQueue() {
return new Queue("queue");
}
}
other credentials-related configurations are in the application.properties file. And this is my receiver part
#RabbitListener(queues = "queue")
public class ClaimValidatorReciever {
#RabbitHandler
public void reciever(RabbitMQValidatorModel validatorModel)
throws InterruptedException, ExecutionException { }
Is it possible to have both in one microservice, and if possible any idea about this issue?
I tried to restart my server when this thing happen but after restarting this is working but after some time again facing this same issue of not fetching data from queue
I am trying to build a chat using xmpp as producer and as consumer.
I have the following code:
rest("/xmppchat")
.get()
.to("direct:jennychat");
from("direct:jennychat")
.process(new Processor() {
public void process(Exchange exchange) throws Exception {
exchange.getIn().setBody("hi maro");
}
})
.to("xmpp://JID:port?participant=JID&password=OneTeam2020");
//this route is not working
from("xmpp://JID:port?participant=JID&password=OneTeam2020")
.setBody(constant("I will win!\n Your Superman."))
.log("${body}");
however, the second route is not starting because in the rest part I did not route to it, but I don t know how to do that since I cannot use the direct component in from
So any idea how to do that?
Thank you
I am building an application using Spring Websockets on a clustered tomcat environment with a RabbitMQ broker. I have an API module which needs to register the endpoint to listen to. I followed the normal examples and came up with this config:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer
{
#Override
public void configureMessageBroker(final MessageBrokerRegistry config)
{
config.enableStompBrokerRelay("/topic/")
.setRelayHost("localhost")
.setRelayPort(61613)
.setClientLogin("guest")
.setClientPasscode("guest");
}
#Override
public void registerStompEndpoints(final StompEndpointRegistry registry)
{
registry.addEndpoint("/updates")
.setAllowedOrigins("*")
.withSockJS();
}
}
While this works, it doesn't solve my issue as it appears the WebSocket and relay config are all bundled into the API module therefore leaving other layers unable to reuse the broker. I need the stomp message broker relay configuration to happen at the service layer so that other modules of our app can push messages to topics in RabbitMQ which then turn around and notify the API module to update all open websockets.
Below is a sample diagram of the relevant layers in our application and what I am trying to accomplish. I need to allow the module "Cron Message Sender" to push messages to everyone who is subscribed to a message topic through our other API modules.
So the second approach did in fact work. I configured the websockets to be run independently (no relay) and then I made a separate AMQP message broker connection at the service layer to allow communication between services. In the API module, I simply listened to the AMQP message broker and then manually forwarded those messages to the SimpMessagingTemplate which notified the websocket subscribers. I am not sure if this is technically the "right" way to do it but it seems to be working great and I do not yet see any issues with the implementation. In fact, I actually think I may prefer this approach as I now just gave all my services the ability to talk to each other with more types of messages than what I originally needed for the websockets.
Here is the new configuration:
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer
{
#Override
public void configureMessageBroker(final MessageBrokerRegistry config)
{
config.enableSimpleBroker("/topic");
}
#Override
public void registerStompEndpoints(final StompEndpointRegistry registry)
{
registry.addEndpoint("/updates")
.setAllowedOrigins("*")
.withSockJS();
}
}
And here is where I listen to the message broker and forward the messages to the websocket subscribers:
#Component
public class SendWebSocketUpdates
{
private static final Logger logger = LoggerFactory.getLogger(SendWebSocketUpdates.class);
private final Gson gson;
#Autowired
private SimpMessagingTemplate messagingTemplate;
#Autowired
private MessageBrokerConsumer<String> messageBrokerConsumer;
public SendWebSocketUpdates()
{
this.gson = new Gson();
}
#PostConstruct
public void init()
{
//listen for incoming AMQP messages from the rabbitmq server and forward them to the websocket subscribers
messageBrokerConsumer.addListener((message, topicName) -> {
final String destination = "/topic/" + topicName;
final String messageJson = gson.toJson(message.getBody());
//check to see if trace logging is enabled
if (logger.isTraceEnabled())
{
logger.trace("Sending Message to \"{}\": {}", destination, messageJson);
}
//broadcast the via a STOMP message to subscribers of this topic
messagingTemplate.convertAndSend(destination, messageJson);
});
}
}
It's easy to solve this problem. I waste a whole day to find the solution.
Here 's my answer for the same problem.
The key is setUserDestinationBroadcast and setUserRegistryBroadcast:
registry.enableStompBrokerRelay("/topic/", "/queue/", "/exchange/")
.setUserDestinationBroadcast("/topic/log-unresolved-user")
.setUserRegistryBroadcast("/topic/log-user-registry")
I'm trying to understand how to publish/broadcast messages using websockets with Spring Boot to a Javascript application. All examples I can find are making use of a StompJs client - I however am unable to use StompJs in my client code, and I'm not sure my backend is correct which doesn't help.
#Configuration
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/subscribe")
.setAllowedOrigins("*")
.withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.setApplicationDestinationPrefixes("/app");
registry.enableSimpleBroker("/topic");
}
}
Just using a simple #Scheduled to produce the time every 5 seconds, and send it to the time topic (Well, I believe that's what it's doing...)
#Component
#Slf4j
public class TimeSender {
private static final DateTimeFormatter TIME_FORMAT = DateTimeFormatter.ofPattern("HH:mm:ss");
private SimpMessagingTemplate broker;
#Autowired
public TimeSender(final SimpMessagingTemplate broker) {
this.broker = broker;
}
#Scheduled(fixedRate = 5000)
public void run() {
String time = LocalTime.now().format(TIME_FORMAT);
log.info("Time broadcast: {}", time);
broker.convertAndSend("/topic/time", "Current time is " + time);
}
}
There are a few points I'm a little confused about when trying to test this. Using the Simple websocket client plugin for Chrome, I have to add websocket to the end of my request in order to connect. A connection would like ws://localhost:8080/subscribe/websocket Without the websocket I can't connect, but I can't find this mentioned in any examples or Spring documentation?
The second question is how do I subscribe to the time topic? All StompJs clients call something like client.subscribe("time") etc.
I've tried ws://localhost:8080/subscribe/topic/time/websocket but no luck in receiving any timestamps.
I'm not sure if my backend code is just wrong, my URL is wrong, or I'm just missing something else.
Note: My #Controller is missing from above as I'm just focused on pushing messages from Spring to clients at this stage, not receiving messages and It's my understanding controllers just deal with incoming?
Well, I suppose if one searches obsessively enough the answer eventually turns up. Almost immediately after finding your post I found the answer I needed at http://www.marcelustrojahn.com/2016/08/spring-boot-websocket-example/. There is a really good example that essentially does what you are describing. The difference is they are using a Spring SimpMessagingTemplate to send messages to the queue. Once I followed his pattern, it all worked like a charm. Here is the relevant code snippet:
#Autowired
SimpMessagingTemplate template
#Scheduled(fixedDelay = 20000L)
#SendTo("/topic/pingpong")
public void sendPong() {
template.convertAndSend("/topic/pingpong", "pong (periodic)")
}
The method is void so the convertAndSend() method handles publishing to the topic, not the return statement as just about every other tutorial I've seen on the web indicates. This helped solve my problem.
I'm trying to use RabbitMq with spring WebSocketMessageBroker, across distributed microservices.
The setup I'm working with is
Within the WebSocketMessageBroker, I'm using the following config, taken from the docs:
#Configuration
#EnableWebSocketMessageBroker
public class WebsocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/push").setAllowedOrigins("*").withSockJS();
}
#Override
public void configureMessageBroker(MessageBrokerRegistry registry) {
registry.enableStompBrokerRelay("/queue/", "/topic/", "/app");
registry.setApplicationDestinationPrefixes("/app");
registry.setPathMatcher(new AntPathMatcher("."));
}
}
Given this config, what exchange / queue should MyMicroservice publish to in order for the message to be proxied through to the Stomp service?
I've tried the following (on the publishing side -- within MyMicroservice)
#Configuration
#SpringBootApplication
#EnableRabbit
public class Config {
public static final String WEB_QUEUE = "/topic/myNotificationTopic";
public static final String WEB_EXCHANGE = "web.exchange";
#Bean
Queue webQueue() {
return new Queue(WEB_QUEUE, false);
}
#Bean
TopicExchange webExchange() {
return new TopicExchange(WEB_EXCHANGE);
}
#Bean
Binding binding(Queue webQueue, TopicExchange webExchange) {
return BindingBuilder.bind(webQueue).to(webExchange).with(WEB_QUEUE);
}
}
#Component
public class ExamplePublisher {
#Autowired
private AmqpTemplate amqpTemplate;
public void sendMessage() {
amqpTemplate.convertAndSend(Config.WEB_QUEUE, "Hello, world");
}
}
However, the message doesn't appear to be proxied over the WebSocket connection.
To be clear, my questions are:
Is this type of distributed configuration supported out-of-the-box?
Given the example config, what is the relationship between RabbitMq topics that the services can publish to, and the Stomp messagebroker proxying?
It isn't clear by your explanation why you are going to use Spring AMQP for the STOMP interaction, although it is possible anyway.
I'd suggest to take a look to the StompClient support in the Spring Messaging, if you are going to send STOMP messages to the target destination directly from Java.
With the Spring AMQP (or just AMQP protocol) you should follow some RabbitMQ STOMP Adapter rules:
Topic Destinations
For simple topic destinations which deliver a copy of each message to all active subscribers, destinations of the form /topic/<name> can be used. Topic destinations support all the routing patterns of AMQP topic exchanges.
Messages sent to a topic destination that has no active subscribers are simply discarded.
AMQP 0-9-1 Semantics
For SEND frames, the message is sent to the amq.topic exchange with the routing key <name>.
For SUBSCRIBE frames, an autodeleted, non-durable queue is created and bound to the amq.topic exchange with routing key <name>. A subscription is created against the queue.
Pay attention that you should have subscription first anyway, otherwise your messages will be lost without subscribers.