Broadcast messages using JMSComponent - queue

I have a problem where I have to broadcast messages to different output locations. I am using JMSComponent for configuring my output queues. My output queues configuration have something like this:
ConnectionFactory factory = createOrGetConnectionFactory(brokerUrl);
JmsConfiguration jmsConfiguration = new JmsConfiguration();
jmsConfiguration.setPreserveMessageQos(true);
jmsConfiguration.setConnectionFactory(factory);
counter++;
outputLocations = new StringBuilder("hubOutput"+counter+":queue://queueName");
JmsEndpoint endpoint = new JmsEndpoint();
JmsComponent component = new JmsComponent();
component.setConcurrentConsumers(5);
component.setConfiguration(jmsConfiguration);
component.setConnectionFactory(factory);
//Add new JMS component in the context. This is done so that the output locations having same queue can be differentiated using the component name in camel registry. getContext().addComponent("hubOutput"+counter, component);
endpoint = (JmsEndpoint) component.createEndpoint(outputLocations.toString());
endpoint.setConfiguration(jmsConfiguration);
I have a camel route for broadcasting the messages to the output queues.
from(fromLocation)
.setHeader("hubRoutesList",constant(hubUrl))
.log(urlToLog)
.setExchangePattern(ExchangePattern.InOnly)
.multicast()
.parallelProcessing()
.to(hubUrl.split(","));
All the output queues have different broker URL but same queue name.
The code works normally but if one of the queues is down, then the message is not broadcasted to other queues also.
Kindly help me with this.
Thanks,
Richa

You can use the recipientList instead of .to(hubUrl.split(","));
With the option stopOnException=false, which is the defaultValue, the forwarding of the messages to the other endpoints will not stop even if one of your queues is down.
See http://camel.apache.org/recipient-list.html for more information.

Related

Sharing objects with all verticles instances

My application, an API server, is thought to be organized as follows:
MainVerticle is called on startup and should create all necessary objects for the application to work. Mainly a mongoDB pool of connections (MongoClient.createShared(...)) and a global configuration object available instance-wide. It also starts the HTTP Listener, several instances of a HttpVerticle.
HttpVerticle is in charge of receiving requests and, based the command xxx in the payload, execute the XxxHandler.handle(...) method.
Most of the XxxHandler.handle(...) methods will need to access the database. In addition, some others will also deploy additional verticles with parameters from the global conf. For example LoginHandler.handle(...) will deploy a verticle to keep user state while he's connected and this verticle will be undeployed when the user logs out.
I can't figure out how to get the global configuration object while being in XxxHandler.handle(...) or in a "sub"-verticle. Same for the mongo client.
Q1: For configuration data, I tried to use SharedData. In `MainVerticle.start() I have:
LocalMap<String, String> lm = vertx.sharedData().getLocalMap("conf");
lm.put("var", "val");
and in `HttpVerticle.start() I have:
LocalMap<String, String> lm = vertx.sharedData().getLocalMap("conf");
log.debug("var={}", lm.get("var"));
but the log output is var=null.... What am I doing wrong ?
Q2: Besides this basic example with a <String, String> map type, what if the value is a mutable Object like JsonObject which actually is what I would need ?
Q3: Finally how to make the instance of the mongo client available to all verticles?
Instead of getLocalMap() you should be using getClusterWideMap(). Then you should be able to operate on shared data accross the whole cluster and not just in one verticle.
Be aware that the shared operations are async and the code might look like (code in Groovy):
vertx.sharedData().getClusterWideMap( 'your-name' ){ AsyncResult<AsyncMap<String,String>> res ->
if( res.succeeded() )
res.result().put( 'var', 'val', { log.info "put succeeded: ${it.succeeded()}" } )
}
You should be able to use any Serializable objects in your map.

How to limit the number of actors of a particular type?

I've created an actor to send messages to a chat server. However, the chat server only permits 5 connections per user. If I hammer my scala server I get error messages because my chat clients get disconnected.
So how can I configure akka so that my XmppSenderActors only use a maximum of 5 threads? I don't want to restrict the rest of the actor system, only this object (at the path /XmppSenderActor/).
I'm trying this config since I think it's the dispatcher I need to configure, but I'm not sure:
akka.actor.deployment {
/XmppSenderActor {
dispatcher = xmpp-dispatcher
}
xmpp-dispatcher {
fork-join-executor.parallelism-min = 2
fork-join-executor.parallelism-max = 3
}
}
This gives me an error though: akka.ConfigurationException: Dispatcher [xmpp-dispatcher] not configured for path akka://sangria-server/user/XmppSenderActor
I would probably try to configure a Router instead.
http://doc.akka.io/docs/akka/2.0/scala/routing.html
A dispatcher seems to deal with sending messages to the inbox rather than the actual number or Actor targets.
That configuration in particular could work for you:
akka.actor.deployment {
/router {
router = round-robin
nr-of-instances = 5
}
}
The nr-of-instances will create 5 childrens from the get going and therefore fill your needs.
You might need to find the right Router implementation though.

vertX eventBus consumer listens to all addresses

I'd like to write a catch all eventBus consumer. Is this possible?
eB = vertx.eventBus();
MessageConsumer<JsonObject> consumer = eB.consumer("*"); // What is catch all address ???
consumer.handler(message -> {
Log.info("Received: " + message.body().toString());
});
A solution to your problem might be an interceptor.
vertx.eventBus().addInterceptor( message -> {
System.out.println("LOG: " + message.message().body().toString());
});
This handler will write every message that comes to the event-bus in vertx.
Reference is here:
http://vertx.io/docs/apidocs/io/vertx/rxjava/core/eventbus/EventBus.html#addInterceptor-io.vertx.core.Handler-
Also, version of vertx-core that I'm using is 3.3.2, I think interceptor functionality is not available in older versions (e.g. 3.0.0).
Having looked through the Java code, I don't think this is possible.
Vert.x stores event bus consumers in a MultiMap looking like:
AsyncMultiMap<String, ServerID>
where the String key is the consumer address.
And as you'd guess, Vert.x just does a map.get(address) to find out the relevant consumers.
Update after OP comment
While I think your use case is valid, I think you're going to have to roll something yourself.
As far as I can see, Vert.x doesn't store consumers of send and publish separately. It's all in one MultiMap. So it would be inadvisable to try to register consumers for all events.
If someone does an eventBus.send(), and Vert.x selects your auditing consumer, it will be the only consumer receiving the event, and I'm going to guess that's not what you want.
I dont know if that´s possible but referring to the documentation, you can put a listener to the events to know when a publish, send, open_socket, close_socket is invoked
sockJSHandler.bridge(options, be -> {
if (be.type() == BridgeEvent.Type.PUBLISH || be.type() == BridgeEvent.Type.RECEIVE) {
Log.info("Received: " + message.body().toString());
}
be.complete(true);
});

MassTransit Send only

I am implementing a Service Bus and having a look at MassTransit. My pattern is not Publish/Subscribe but Sender/Receiver where the Receiver can be offline and came back online later.
Right now I am starting to write my tests to verify that MassTransit succesfully deliver the message using the following code:
bus = ServiceBusFactory.New(sbc =>
{
sbc.UseMsmq(
cfg =>
{
cfg.Configurator.UseJsonSerializer();
cfg.Configurator.ReceiveFrom("msmq://localhost/my_queue");
cfg.VerifyMsmqConfiguration();
});
});
Then I grab the bus and publish a message like this:
bus.Publish<TMessage>(message);
As I can notice from MSMQ, two queues are created and the message is sent cause Mass Transit does not raise any error but I cannot find any message in the queue container.
What am I doing wrong?
Update
Reading the Mass Transit newsgroup I found out that in a scenario of Sender/Receiver where the receiver can come online at any time later, the message can be Send using this code:
bus.GetEndpoint(new Uri("msmq://localhost/my_queue")).Send<TMessage>(message);
Again in my scenario I am not writing a Publisher/Subscriber but a Sender/Receiver.
First, to send, you can use a simple EndpointCacheFactory instead of a ServiceBusFactory...
var cache = EndpointCacheFactory.New(x => x.UseMsmq());
From the cache, you can retrieve an endpoint by address:
var endpoint = cache.GetEndpoint("msmq://localhost/queue_name");
Then, you can use the endpoint to send a message:
endpoint.Send(new MyMessage());
To receive, you would create a bus instance as you specified above:
var bus = ServiceBusFactory.New(x =>
{
x.UseMsmq();
x.ReceiveFrom("msmq://localhost/queue_name");
x.Subscribe(s => s.Handler<MyMessage>(x => {});
});
Once your receiver process is complete, call Dispose on the IServiceBus instance. Once your publisher is shutting down, call Dispose on the IEndpointCache instance.
Do not dispose of the individual endpoints (IEndpoint) instances, the cache keeps them available for later use until it is disposed.

MassTransit Subscriptions and Receiving Own Messages

I am trying to implement a proof of concept service bus using MassTransit. I have three applications which need to communicate changes of a common entity type between each other. So when the user updates the entity in one application, the other two are notified.
Each application is configured as follows with their own queue:
bus = ServiceBusFactory.New(sbc =>
{
sbc.UseMsmq();
sbc.VerifyMsmqConfiguration();
sbc.ReceiveFrom("msmq://localhost/app1_queue");
sbc.UseSubscriptionService("msmq://localhost/subscription");
sbc.UseControlBus();
sbc.Subscribe(subs =>
{
subs.Handler<IMessage1>(IMessage1_Received);
});
});
There is also a subscription service application configured as follows:
subscriptionBus = ServiceBusFactory.New(sbc =>
{
sbc.UseMsmq();
sbc.VerifyMsmqConfiguration();
sbc.ReceiveFrom("msmq://localhost/subscription");
});
var subscriptionSagas = new InMemorySagaRepository<SubscriptionSaga>();
var subscriptionClientSagas = new InMemorySagaRepository<SubscriptionClientSaga>();
subscriptionService = new SubscriptionService(subscriptionBus, subscriptionSagas, subscriptionClientSagas);
subscriptionService.Start();
The problem is that when one of the applications publishes a message, all three applications receive it (including the original sender).
Is there any way to avoid this (without resorting to adding the application name to the message)?
Thanks,
G
So MassTransit is a pub/sub system. If you publish a message, everyone registered to receive it will. If you need only some endpoints to receive it, then you really need to directly send. It's just how this works.
You could include the source in your message and discard messages that aren't of interest to you. If you implement the Consumes.Accept interface, I think the Accept method would allow you to do so easily without mixing that into the normal consumption code.