I'm reading the akka documentation and now I'm at the section about Inbox. Here's what is said there:
The send method wraps a normal tell and supplies the internal actor’s
reference as the sender.
But what's the difference? When using tell this way:
ActorRef aRef1;
ActorRef aRef2;
//init the references
aRef1.tell(aRef2, "Message");
we can get the sender in the onRecieve method like this:
public void onReceive(Object message) throws Exception {
System.out.println("Sender: " + getSender().path().name());
}
What's the actual benefit of send in comparison to just tell?
The purpose of an Inbox is to have
an actor-like object which is interrogated from the outside.
It's not meant to be used within an actor. It's for external systems that have access to the actor system/context and want to send a message to an actor.
The method send documentation states
Have the internal actor act as the sender of the given message which
will be sent to the given target. This means that should the target
actor reply then those replies will be received by this Inbox.
This allows an external component to act as if it was part of the actor system and receive messages from actors. Unfortunately, the price to pay for this is that receive is blocking.
Related
I'm trying to implement distributed actor model which uses Netty as communication protocol - the NIO version with TCP connections.
Lets say we have 2 nodes (machines), each have Netty's server instances that pass the incoming messages to actors on that node.
I would like to keep message ordering per same pair of remote actors, so my solution was to use asynchronous writeAndFlush method to send messages to remote node and actor - when another message needs to be sent to the same actor before the first one was delivered, I would add it to buffer and with the callback of the writeAndFlush message, process the next one from buffer. It looks like this:
channel.writeAndFlush(message).addListener(new MessageListener(mailboxOfSelector));
the callback method is:
#Override
public void operationComplete(ChannelFuture future) throws Exception {
Queue<RemoteMessage> unsentToMailbox = unsentMessages.get(mailboxOfSelector);
if (!unsentToMailbox.isEmpty()) {
RemoteMessage message = unsentToMailbox.poll();
channel.writeAndFlush(message).addListener(this);
}
}
So if A and B are 2 server instances connected with Channel and we send from A -> B - my question would be: what does isSuccess flag mean in depth? and when does the callback actually return?
Does it return when it finished with last handler on A or actually when it is delivered to the first handler on the B?
In Netty5. Version alpha2. after flush the data to socketchannel,Netty then callback the operationComplete method .In this case, it dose not means the data reach the client. It means the data has been sent to the TCP protocol stack.You can see these in source code:
io.netty.channel.ChannelOutboundBuffer.java
It will calls the promise.trySuccess() from the remove() method or remove(Cause cause), witch can trigger the operationComplete() method.
I'm trying to build a custom mq exit to archive messages that hit a queue. I have the following code.
class MyMqExits implements WMQSendExit, WMQReceiveExit{
#Override
public ByteBuffer channelReceiveExit(MQCXP arg0, MQCD arg1, ByteBuffer arg2) {
// TODO Auto-generated method stub
if ( arg2){
def _bytes = arg2.array()
def results = new String(_bytes)
println results;
}
return arg2;
}
...
The content of the message (header/body) is in the byte buffer, along with some unreadable binary information. How can I parse the message (including the body and the queue name) from arg2? We've gone through IBM's documentation, but haven't found an object or anything that makes this easy.
Assuming the following two points:
1) Your sender application has not hard coded the queue name where it puts messages. So you can change the application configuration to send messages to a different object.
2) MessageId of the archived message is not important, only message body is important.
Then one alternative I can think of is to create an Alias queue that resolves to a Topic and use two subscribers to receive messages.
1) Subscriber 1: An administratively defined durable subscriber with a queue provided to receive messages. Provide the same queue name from which your existing consumer application is receiving messages.
2) Subscriber 2: Another administratively defined durable subscriber with queue provided. You can write a simple java application to get messages from this queue and archive.
3) Both subscribers subscribe to the same topic.
Here are steps:
// Create a topic
define topic(ANY.TOPIC) TOPICSTR('/ANY_TOPIC')
// Create an alias queue that points to above created topic
define qalias(QA.APP) target(ANY.TOPIC) targtype(TOPIC)
// Create a queue for your application that does business logic. If one is available already then no need to create.
define ql(Q.BUSLOGIC)
// Create a durable subscription with destination queue as created in previous step.
define sub(SB.BUSLOGIC) topicstr('/ANY_TOPIC') dest(Q.BUSLOGIC)
// Create a queue for application that archives messages.
define ql(Q.ARCHIVE)
// Create another subscription with destination queue as created in previous step.
define sub(SB.ARCHIVE) topicstr('/ANY_TOPIC') dest(Q.ARCHIVE)
Write a simple MQ Java/JMS application to get messages from Q.ARCHIVE and archive messages.
A receive exit is not going to give you the whole message. Send and receive exits operate on the transmission buffers sent/received by channels. These will contain various protocol flows which are not documented because the protocol is not public, and part of those protocol flows will be chunks of the messages broken down to fit into 32Kb chunks.
You don't give enough information in your question for me to know what type of channel you are using, but I'm guessing it's on the client side since you are writing it in Java and that is the only environment where that is applicable.
Writing the exit at the client side, you'll need to be careful you deal with the cases where the message is not successfully put to the target queue, and you'll need to manage syncpoints etc.
If you were using QMgr-QMgr channels, you should use a message exit to capture the MQXR_MSG invocations where the whole message is given to you. If you put any further messages in a channel message exit, the messages you put are included in the channel's Syncpoint and so committed if the original messages were committed.
Since you are using client-QMgr channels, you could look at an API Exit on the QMgr end (currently client side API Exits are only supported for C clients) and catch all the MQPUT calls. This exit would also give you the MQPUT return codes so you could code your exit to look out for, and deal with failed puts.
Of course, writing an exit is a complicated task, so it may be worth finding out if there are any pre-written tools that could do this for you instead of starting from scratch.
I fully agree with Morag & Shashi, wrong approach. There is an open source project called Message Multiplexer (MMX) that will get a message from a queue and output it to one or more queues. Context information is maintained across the message put(s). For more info on MMX go to: http://www.capitalware.com/mmx_overview.html
If you cannot change the source or target queues to insert MMX into the mix then an API Exit may do the trick. Here is a blog posting about message replication via an API Exit: http://www.capitalware.com/rl_blog/?p=3304
This is quite an old question but it's worth replying with an update that's relevant to MQ 9.2.3 or later. There is a new feature called Streaming Queues (see https://www.ibm.com/docs/en/ibm-mq/9.2?topic=scenarios-streaming-queues) and one of the use-cases it is designed to support is putting a copy of every message sent to a given queue, to an alternative queue. Another application can then consume the duplicate messages and archive them separately to the application that is processing the original messages.
The publish callback in PubNub API returns with a message like below -
[1,"Sent","13729639808030640"]
But this does not give any indication as to for which message this callback is for. In case of publish error, the first value in the return array will be 0. But how do you find out which message to re-publish?
The publisher can be publishing messages at a high rate and not waiting to receive the callback before publishing another message. So when the callback is invoked the publisher might have already published 10 more messages.
PubNub REST API provide JSONP format as well. You can create map of "callback function" identifiers to actual messages and when processing completed, you can obtain reference on original message using "callback function" identifier from response.
For example:
https://pubsub.pubnub.com/publish/demo/demo/0/iosdev/m_2c453/%22Hello%20world2%22
As you can see, there is m_2c453 in URI, it will be used by server in response:
m_2c453([1,"Sent","14034711347326358"])
And here we know, that m_2c453 has been used to send "Hello world" message.
But, I think platform dependent PubNub SDK should handle all this for you.
Transferred here since it's too long for a message reply.
In reply with #Geremy, so if message 1,2,3,4,5 will be sent, i'll get a publish callback in 1,2,3,4,5 order? there won't be a case where a response will fail in say 2 and 4? In that case, if we'll continue in the notion that we get an ordered response, this would mean that a response failed to arrive for messages 4 and 5 instead of 2 and 4. Might I suggest to the pubnub team that they add a fourth data in the JSONArray they return, it would contain the id field in the message that was published ( if there is such a data e.g. { "id":123, message:"hello"} ), if there's is none, obviously the returned id would be null or empty string.
I faced a similar challenge. I wanted to queue messages while the device is offline, and then send them on reconnect. In the callback i needed a way of knowing which message was sent to remove it from the queue. I came up with this solution:
function sendData(channel, data, callback) {
Pubnub.publish({
channel: channel,
message: data,
callback : callback
});
}
//This code is placed within the "reconnect" callback of the subscription
if ($localStorage.chatQueue.length) {
for (var i = 0; i < $localStorage.chatQueue.length; i++) {
sendData(
$localStorage.chatQueue[i].channel,
$localStorage.chatQueue[i].data,
function(){
console.log("arguments");
console.log(arguments);
console.log("this");
console.log(this);
index = $localStorage.chatQueue.indexOf(this);
console.log("Message in offline queue sent, index = "+index);
if (index > -1) {
$localStorage.chatQueue.splice(index, 1);
}
}.bind($localStorage.chatQueue[i])
);
}
}
The trick is binding this in the callback function to the message object. It seems to work. I guess one could also just bind the i variable which would give a direct pointer to the message in the queue.
I was inspired by this answer in another question: https://stackoverflow.com/a/19472945/3319392
I have an webapp that is expected to fetch and display data from an External App which is accessible only via messaging (JMS).
So, if a user submits a request on a browser, the same HTTP request thread will have to interact with the Messaging system (MQ Series) such that the same request thread can display the data received from the Messaging System.
Is there a pattern I can make use of here? I saw some vague references on the net that use "Correlation ID" in this way:
Msg m = new TextMsg("findDataXYZ");
String cr_id = m.setCorrelationID(id);
sendQueue.send(m).
// now start listening to the Queue for a msg that bears that specific cr_id
Response r = receiverQueue.receive(cr_id);
Is there something better out there? The other patterns I found expect the response to be received asynchronously.. which is not an option for me, since I have to send the response back on the same HTTP request.
The request/reply messaging pattern is useful for your requirement. You typically use a CorrelationId to relate request & reply messages.
While sending request message you set JMSReplyTo destination on the message. Typically a temporary queue is used as JMSReplyTo destination. When creating a consumer to receive response use a selector with JMSCorrelationId, something like
cons = session.createConsumer(tempDestination,"JMSCorrelationId="+requestMsg.JMSMessageId);
At the other end, the application that is processing the request message must use the JMSReplyTo destination to send response. It must also use the MessageId of the request message and set it as CorrelationId of the response message.
First, open the response queue. Then pass that object to the set reply-to method on the message. That way the service responding to your request knows where to send the reply. Typically the service will copy the message ID to the correlation ID field so when you send the message, take the message ID you get back and use that to listen on the reply queue. Of course if you use a dynamic reply-to queue even that isn't neessary - just listen for the next message on the queue.
There's sample code that shows all of this. If you installed to the default location, the sample code lives at "C:\Program Files (x86)\IBM\WebSphere MQ\tools\jms\samples\simple\SimpleRequestor.java" on a Windows box or /var/mqm/toolsjms/samples/simple/SimpleRequestor.java on a *nix box.
And on the off chance you are wondering "install what, exactly?" the WMQ client install is downloadable for free as SupportPac MQC71.
say you have multiple agents(each of them is it's own process) which can communicate to each other(agents communicate only in pairs); how do you ensure that once two agents start communicating, no other agent can interrupt them?
Here's the important part of the code:
class Agent {
private void send(int to, byte[] message) {...};
private void receive(int from, byte[] message) {...};
}
The send method sends the message to the specified agent and receive method processes the received message, that comes from other agents. So let's say agents with id=1 and id=2 exchange a few messages: how do I ensure that neither of the agents processes(in it's receive method) messages from any other agent during their exchange? I tried filtering messages based on agent's id(by storing them in int variable) but it doesn't seems to work properly?
With processes and using TCP for the IPC, at any time let every agent have at most one socket open. Then a second agent will never be able to talk with an already talking agent.
You can give receivers a token. When an agent want to send to a receiver, it should get the receiver's token at first. After finishing the whole communication, the sender will release the token, and then other's can send to the receiver.