I have a Jetty endpoint receiving push-messages of different types from several data-providers - let´s call them type1, type2.
I also provide set of websocket-endpoints - one for each type - where clients can subscribe to push-updates of the different message-types (/ws_type1, /ws_type2).
The dataproviders and the clients are not the same.
Based on the type of incoming message, I am trying to get the camel route to push updates only to the clients subscribing to the specific messagetype.
My code is something like this:
from("jetty:http://0.0.0.0:8888/incoming_1?matchOnUriPrefix=true")
.log("incoming_1")
.to("websocket://ws_type1?sendToAll=true");
from("jetty:http://0.0.0.0:8888/incoming_2?matchOnUriPrefix=true")
.log("incoming_2")
.to("websocket://ws_type2?sendToAll=true");
from("jetty:http://0.0.0.0:8080/incoming?matchOnUriPrefix=true")
.log("incoming")
.to("websocket://woot?sendToAll=true");
from("websocket://ws_type1")
.log("ws_type1")
.to("websocket://ws_type1")
;
from("websocket://ws_type2")
.log("ws_type2")
.to("websocket://ws_type2")
;
The result of this is that ALL messages of ALL types are sent to ALL the connected clients - regardless if they are connected to the /ws_type1 or /ws_type2 endpoints.
Is it possible to filter the updates to different sets of clients? I.e. messages of type1 are pushed to the clients connected to /ws_type1, and messages of type2 are pushed to the clients connected to /ws_type2.
EDIT:
Using the code above, I am able to connect websockets to ws-endpoints "ws_type1", "ws_type2", and "woot". However - when I post data to the "/incoming_1" jetty-endpoint ALL three websockets receive the data, but only "incoming_1" is logged.
Am I missing something?
EDIT 2:
I looked at the camel-websocket source, and it seems like this is by design. There is no filtering on which websockets the message-contents are sent to, and the content is written directly to the socket. This also means that the camel-routes "ws_type1" and "ws_type2" in the example above will not be called when the server pushes data.
....
Collection<DefaultWebsocket> websockets = store.getAll();
Exception exception = null;
for (DefaultWebsocket websocket : websockets) {
try {
sendMessage(websocket, message);
...
Full source
Related
I am currently migrating our existing Spring asynchronous REST architecture to Spring's new WebFlux library and have a question around joining multiple requests so that they can listen for the same published response.
Use Case is as follows:
Client A connects to our web server and requests data
We hit our cache to check if we have the data there
We don't, so we go and retrieve this data (Client A has subscribed and waits for a response)
Client B connects to our web server and requests the same data (hits the same endpoint)
We check the cache, data is still not there
As we are already fetching this data for Client A we don't want to make another request, however, we also do not want to turn Client B away. Client B should be able to listen for the same information
How can Client B subscribe to the same response stream that Client A is waiting for?
"Client A has subscribed and waits for a response"
I suppose the request is coded as a Mono and client A sibscribes to it literally:
Subscriber<Response> clientA = ...
Mono<Response> request = makeRequest(...);
request.subscribe(clientA);
then clientB should subscribe the same way:
Subscriber<Response> clientB = ...
request.subscribe(clientB);
Moreover, the cache should contain not the previously saved response data, but the requests themselves, of type Mono<Response>. Then, if such a request is found in the cache, new clients simply subscribe to it, regardless of was that request already completed or not.
I was going through the tutorial shared by RabbitMQ here
I am assuming that the client code below
while (true)
{
var ea = (BasicDeliverEventArgs)consumer.Queue.Dequeue();
if (ea.BasicProperties.CorrelationId == corrId)
{
return Encoding.UTF8.GetString(ea.Body);
}
}
Would receive all messages on the queue and will unnecessarily iterate through messages not designated for it. Is their anyway we can avoid it i.e we can modify the client to only receive the messages intended for it only.
The basic work that i intend to achieve through RabbitMQ is Request-Response pattern where a request would be received by web-service which will send data in a queue the data object would have a unique reference number . This would be received by an asynchronous tcp-client which will send data on a tcp/ip layer based on message it had received.
On receiving reply from the asynchronous channel of tcp/ip the channel would parse the data and respond back on the queue with the corresponding request reference number.
The RPC approach is well suited for it but the client code shared have this shortcoming would appreciate feedback on it.
Actually I didn’t understand well your aim, but when you create an RPC model, you have to create an “reply queue”, this queue is bound only to the client.
It means that you will receive back only the client messages, and not all messages.
Since the Rabbitmq RPC model is asynchronous you can execute more than one request without wait the responses and replies could not have the same publish order.
The correlation id is necessary to map your client requests with the replies, so there are not "unnecessarily" messages
hope it helps
I have a problem concerning receiving messages (I use #ManagedService). I use the same connection to send and receive messages between browser and my Java program. I can see that all the messages pass through ManagedAtmosphereHandler.message(AtmosphereResource resource, Object o) method.
If it is an incoming message, Atmosphere iterates through all methods marked #Message. Then it tries to find a decoder and eventually invokes correct method.
For outgoing messages, Atmosphere retrieves invoked method. It does so by getting localAttribute named "ManagedAtmosphereHandler" (name of current class). It is present only for outgoing messages. Then the message is encoded and send to browser.
The problem is, sometimes invokedMethod is set for incoming messages. It results in treating my incoming messages as outgoing. Does anybody know why it happens? My outgoing messages are scheduled and I suppose that's the reason why it happens, but I'm not sure. When are these localAttributes set and what are they for?
I updated Atmosphere 2.3.0-RC6 to 2.3.0 and it works like a charm now.
I have the following two routes:
Route 1
from("netty:tcp://localhost:5050?textline=true&encoder=#customStringEncoder&decoder=#customDecoder")
.routeId("inboundSocketRoute")
.doTry()
.unmarshal(beanIO)
.bean(inboundInterfaceProcessor, "processInterfaceData")
.doCatch(ValidationException.class, UnidentifiedRecordException.class, InvalidRecordException.class)
.bean(inboundInterfaceProcessor, "processInterfaceDataError")
.end();
Route 2
String server = "123.45.67.89:5050";
from("jms://queue:evOutboundDataInterface")
.routeId("outboundInterfaceRoute")
.doTry()
.bean(outboundInterfaceProcessor, "processOutboundData")
.to("netty:tcp://" + server + "?textline=true&requestTimeout=10000&encoder=#customStringEncoder&decoder=#customDecoder")
.bean(outboundInterfaceProcessor, "processSequence")
.doCatch(ReadTimeoutException.class)
.bean(outboundInterfaceProcessor, "handleTimeout")
.doCatch(ConnectException.class)
.bean(outboundInterfaceProcessor, "handleConnectionError")
.end();
Route 1 is triggered by incoming data from an external server. The incoming data is parsed by BeanIO and eventually ends up in my InterfaceProcessor, which treats inbound data. Route 2 is triggered by a JMS message (which is sent by my software) and it should send a message back to the external server on the same port.
In my current setup, I start my own server (route 1) and client (route 2). I don't think this will work, as both connections are always active. This way, when I want to send a message to the external server from route 2, it probably won't be able to connect to the external server. However, when I receive a message on route 1, I am able to send a message back to the external server (from within the processor that is bound to that route) by having inboundInterfaceProcessor.processInterfaceData() return the String that will be sent to the external server.
Because I'm able to send a message back to the external server from route 1, I'm thinking about triggering inboundInterfaceProcessor from outboundInterfaceProcessor to send a message to the external server from route 2. How should I do this? Is this even possible with Camel/Netty? Or should I use another approach to this problem?
I solved this by having the external server poll for data that would normally be sent through the second route. Every message is answered with an acknowledge message, so when this acknowledgement is received by the inbound interface, I can check for more outgoing interface data. It isn't ideal, but it works. :)
I am using a multicast in Camel DSL because I need to send a copy of the same message to two different endpoints. However, it seems that the routes are interfering with each other. Have I got the syntax wrong, or some other issue?
from("{{in.endpoint}}")
.routeId(this.getClass().getSimpleName())
.multicast().parallelProcessing()
.to("{{update.in}}", "{{add.ibmmq.topic}});
where
in.endpoint = seda:addOrder?waitForTaskToComplete=Never
update.in = seda:updateData?waitForTaskToComplete=Never
add.ibmmq.topic = an ibmmq topic
I expect the 'update' route to receive the 'in' message, and the 'ibmmq topic' to receive the same message, presumably cloned. However, in the logs I am getting exceptions like:
Exchange[
Id ID-slon12d10628-1228-1386074869307-0-44746
ExchangePattern InOnly
Headers {breadcrumbId=ID-slon12d10628-1228-1386074869307-0-41682, calendar=null, CamelMyBatisResult=[integration.model.EInquiry#19eb77c, integration.model.EInquiry#12059ce, xxxxxxx
BodyType message.BulkAddOrderMsg
Body message.BulkAddBondOrderMsg#77df22
]
but the EInquiry objects are read in by a completely separate route, nothing to do with this route except it, too, sends messages to 'in.endpoint'.
The other thing is because I read from Tibco and send to IBMMQ, I have to clear the JMS header codes because they are not compatible, so I have put:
exchange.getIn().getHeaders().clear();
in my 'update' route. Could this be clearing Camel's exchange tracing headers and causing this issue, basically like some weird concurrency issue?
Its hard to find the error without full source code, but bear in mind that multicast does not do deep copy.
If you have child objects in the Order object they are not duplicated and they are shared between both SEDA routes.
Probably you will have to make a custom deep clone of the object
The body of your Exchange is a custom POJO: message.BulkAddBondOrderMsg#77df22... which means there is no deep cloning available unless you add it. Same thing would happen if the body were DOM XML node...
Serialize the POJO to a String prior to the multicast so it can be shared across Exchanges.