I have two applications within my server, and use JMS via ActiveMQ to send messages between the two. My two apps are as follows
Web service - accepts HTTP requests, validates, then sends messages to be executed by the other application.
Exec App - accepts object messages, executes order, sends execution report back to the web service to present to the client.
My Exec app receives messages from the Web service within 200ms, no problems there. However when I send an exec report, the message can hang in the queue for over 10 seconds before being received by the web service. I am using the same code for both side's consumers so I am unsure what the cause would be.
Here is my message producer in the Exec App -
public void createAndSendExecReport(OrderExecutionReport theReport){
try {
logger.debug("Posting exec report: " +theReport.getOrderId());
this.excChannelMessageProducer.send(createMessage(theReport));
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
[there is a createMessage method which converts my POJO into an object message]
MessageListener listener = new MessageListener() {
#Override
public void onMessage(Message message) {
logger.debug("Incoming execution report");
try {
OrderExecutionReport report = (OrderExecutionReport)((ObjectMessage)message).getObject();
consumeExecutionReport(report);
} catch (Exception e) {
logger.error("Message handling failed. Caught: " + e);
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
logger.error(sw.toString());
}
}
};
I get the log message "sending execution report"
Then nothing in the web service for up to 15 seconds later until finally I get "incoming ... "
What could be the cause of this?
Make sure you have enough MDBs running on the Exec App so they can handle the load.
Related
I have deployed my Java-MDB based application using ActiveMQ as messaging service . I could see that a few messages have been in pending status for quite some time on some queues. I have read that this happens when ActiveMQ delivers the message and consumer consumes the message but doesn't send the ack back. But I could not see any related loggers on the consumer/application side which proves that the message is consumed.
Could anyone please help me understand the reason of message being stuck in pending state.
Edit - Adding the details:
We are using Auto-acknowledge as acknowledgeMode and below is the onMessage method used on consumer side.
public void onMessage(Message message) {
try {
// Clear all ThreadLocal in SQLQueryHelper.
SQLQueryHelper.clearCache();
String messageOut = processMessage(message);
// if there is a reply, send it out
if (messageOut != null) {
logger.warn(LoggerKeys.LOG_1_ARGS,
new String[] {"Reply from MDB not supported. " + messageOut});
}
} catch (Throwable e) {
logger.error(LoggerKeys.LOG_1_ARGS,
new String[] {"Error encountered: " + e.toString()});
try {
//put message on error queue
handleError(message, e);
} catch (Throwable e2) {
//retry to put message on error queue
handleErrorAndRollBack(message, e2);
}
}
}
I encountered a knotty problem when receiving message from WildFly JMS queue. My code is below:
Session produceSession = connectionFactory.createConnection().createSession(false, Session
.CLIENT_ACKNOWLEDGE);
Session consumerSession = connectionFactory.createConnection().createSession(false, Session
.CLIENT_ACKNOWLEDGE);
ApsSchedule apsSchedule = new ApsSchedule();
boolean success;
MessageProducer messageProducer = produceSession.createProducer(outQueueMaxusOrder);
success = apsSchedule.sendD90Order(produceSession,messageProducer, d90OrderAps);
if (!success) {
logger.error("Can't send APS schedule msg ");
} else {
MessageConsumer consumer = consumerSession.createConsumer(inQueueDeliveryDate);
data = apsSchedule.receiveD90Result(consumerSession,consumer);
}
then getting into the receiveD90Result():
public DeliveryData receiveD90Result(Session session, MessageConsumer consumer) {
DeliveryData data = null;
try {
Message message = consumer.receive(10000);
if (message == null) {
return null;
}
TextMessage msg = (TextMessage) message;
String text = msg.getText();
logger.debug("Receive APS d90 result: {}", text);
ObjectMapper mapper = new ObjectMapper();
data = mapper.readValue(text, DeliveryData.class);
} catch (JMSException je) {
logger.error("Can't receive APS d90 order result: {}", je.getMessage());
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
consumer.close();
} catch (JMSException e) {
e.printStackTrace();
}
}
return data;
}
But when implementing the consumer.receive(10000), the project can't get a message from queue. If I use asynchronous way of MDB to listen the queue, I can get the message from queue. How to resolve it?
There are multiple modes you can choose to get a message from the queue. Message Queues are by default asynchronous in usage. There are however cases when you want to read it synchronously , for example sending a message with account number and using another queue to read the response and match it with a message id or a message correlation id. When you do a receive , the program is waiting for a message to arrive within that polling interval specified in receive.
The code snippet you have , as i see it uses the psuedo synchronous approach. If you have to use it as an MDB , you will have to implement message driven bean (EJB Resource) or message listener.
The way that MDB/Message Listener works is more event based , instead of a poll with a timeout (like the receive) , you implement a callback called onMessage() that is invoked every time there is a message. Instead of a synchronous call , this becomes asynchronous. Your application may require some changes both in terms of design.
I don't see where you're calling javax.jms.Connection.start(). In fact, it doesn't look like you even have a reference to the javax.jms.Connection instance used for your javax.jms.MessageConsumer. If you don't have a reference to the javax.jms.Connection then you can't invoke start() and you can't invoke close() when you're done so you'll be leaking connections.
Furthermore, connections are "heavy" objects and are meant to be re-used. You should create a single connection for both the producer and consumer. Also, if your application is not going to use the javax.jms.Session from multiple threads then you don't need multiple sessions either.
I am currently trying to publish a command to a specific topic in the IBM IoT Foundation MQTT Broker using a Java web application. My application is already able to listen to device events and act on them, however publishing commands to the device is a problem. I know for sure that my device is listening to the proper topic for commands, so what could be the problem? More specifically, here is the command I call to publish to the topic (from my Java app):
publish("iot-2/cmd/" + MQTTUtil.getDefaultCmdId() + "/fmt/json", rawJSONCommand, false, 0);
System.out.println("Finished sending command!");
Where the "publish" method is defined as follows:
public void publish(String topic, String message, boolean retained, int qos) { // check if client is connected
if (isMqttConnected())
{
// create a new MqttMessage from the message string
MqttMessage mqttMsg = new MqttMessage(message.getBytes());
// set retained flag
mqttMsg.setRetained(retained);
// set quality of service
mqttMsg.setQos(qos);
try {
System.out.println("About to send!");
client.publish(topic, mqttMsg);
System.out.println("Finished sending!"); }
catch (MqttPersistenceException e)
{ e.printStackTrace(); }
catch (MqttException e)
{ e.printStackTrace(); } }
else {
System.out.println("Connection lost!"); connectionLost(null);
} }
All that happens is that I enter the method, I get "About to send!" printed on my console as the code specifies, and then the actual 'client.publish(topic, mqttMsg)' call blocks my program indefinitely.. Eventually, after blocking for a while, I get the following error:
org.eclipse.paho.client.mqttv3.internal.ClientState checkForActivity SEVERE: a:2uwqwc:<MY_APP_NAME>: Timed out as no write activity, keepAlive=60,000 lastOutboundActivity=1,452,646,209,624 lastInboundActivity=1,452,646,149,303 time=1,452,646,329,628 lastPing=0
Thanks for the help!
If you are publishing from an application, are you specifying the device type and device id?
myAppClient.publishCommand(deviceType, deviceId, "stop", data);
Refer to section in documentation about publishing commands to connected devices.
https://docs.internetofthings.ibmcloud.com/java/java_cli_app.html
I have a background service that runs in its own separate process using
android:process=":deamon"
In the manifest entry for the service. I want to communicate with the the service (remote process) from my activity and receive data from it.
I'm doing that by sending messages to and from the remote process as described in http://developer.android.com/guide/components/bound-services.html#Messenger and as they suggested I followed
If you want the service to respond, then you need to also create a Messenger in the client. >Then when the client receives the onServiceConnected() callback, it sends a Message to the >service that includes the client's Messenger in the replyTo parameter of the send() method.
The thing is, I need to provide a blocking/synchronous API to get data from my remote service, how can my "get" function block the caller and then return the data received in my incoming Handler ?
What would be the best approach to do that ?
This is code for messaging part of Client
SparseArray<CountDownLatch> lockArray = new SparseArray<>();
SparseArray<Bundle> msgDataArray = new SparseArray<>();
public Bundle sendAndWaitResponse(Message msg) throws
RemoteException, InterruptedException {
int msgId = msg.arg2;
Log.d("PlatformConnector", "Sending message to service, Type: "
+ msg.what + ", msgId: " + msg.arg2);
CountDownLatch latch = new CountDownLatch(1);
lockArray.put(msgId, latch);
platformMessenger.send(msg);
latch.await();
Bundle response = msgDataArray.get(msgId);
lockArray.delete(msgId);
msgDataArray.delete(msgId);
return response;
}
void storeResponseAndNotify(Message msg) {
int msgId = msg.arg2;
// Because the message itself is recycled after Handler returns,
// we should store only the data of message
msgDataArray.put(msgId, msg.getData());
lockArray.get(msgId).countDown();
}
private class ClientMessageHandler extends Handler {
#Override
public void handleMessage(Message msg) {
storeResponseAndNotify(msg);
}
}
This is example of utilizing above code.
RandomInt.getNextInt() is my custom static method, which generates random integer with Random.nextInt().
public JSONObject doSomething(JSONObject object) {
Message msg = Message.obtain(null, Constants.MESSAGE_SOMETHING, 0, RandomInt.getNextInt());
Bundle bundle = new Bundle();
bundle.putString(Constants.MESSAGE_DATA_SOMETHING, object.toString());
msg.setData(bundle);
try {
Bundle responseData = sendAndWaitResponse(msg);
return new JSONObject(responseData.getString(Constants.MESSAGE_DATA_RETURN));
} catch (RemoteException e) {
Log.e(TAG, "Failed to send message to platform");
e.printStackTrace();
} catch (InterruptedException e) {
Log.e(TAG, "Interrupted while waiting message from platform");
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
return null;
}
Sequence is as follows,
The Client prepares Message and set its arg2 as some random integer
(this integer will be the message id for synchronization).
The Client prepares new CountDownLatch and put it to LockArray.
the Client sends message with sendAndWaitResponse(). It sends message to service via Messenger and invokes latch.await().
Service processes receives message and prepare reply message. The arg2 of this reply message should be same as received message.
Service sends reply message to client via Messenger in replyTo.
Client message handler handles the message with storeResponseAndNotify.
When the blocking of Client thread is finished, the response data would be already prepared in msgDataArray.
CountDownLatch is simple switch to block and unblock the thread.
(http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/CountDownLatch.html)
SparseArray is similar to HashMap, but more memory-efficient for smaller sets.
(http://developer.android.com/reference/android/util/SparseArray.html)
Be careful not to block the thread of Messenger. Messenger runs in single thread and if you block from the handleMessage(), it will block all other messages and cause deaklock problem.
I am trying to develop a sms sending and receiving test application in J2ME using the WMA API. I have separate threads for sending and receiving.
The Sending thread's run method -
public void run() {
try {
MessageConnection connection = (MessageConnection) Connector.open("sms://+" + number + ":1234");
BinaryMessage messageBody = (BinaryMessage) connection.newMessage(connection.BINARY_MESSAGE);
messageBody.setPayloadData(message.getBytes());
connection.send(messageBody);
connection.close();
} catch (IOException ex) {
}
}
The receiving thread's run method
public void run() {
try {
while (true) {
MessageConnection connection = (MessageConnection) Connector.open("sms://:1234");
BinaryMessage messageBody = (BinaryMessage) connection.receive();
message = new String(messageBody.getPayloadData());
number = messageBody.getAddress();
number = number.substring(6, 15);
App.setDisplay(number, message);
connection.close();
}
} catch (IOException ex) {
ex.printStackTrace();
}
}
I am initializing the receiving thread in the startApp() and initializing the sending thread when the send command is pressed. The problem I have is that if I use two Emulators, both sides can't send messages. One emulator can continuously send messages to the other but when the other emulator tries to send a message the message isn't received.
When a message is received by the emulator console shows -
[INFO] [sms ] ## javacall: SMS
sending...
when that line appears the emulator doesn't receive any messages. Where is the problem in my code?
PS: I saw that their is a way to use a listener to work around this problem with using a separate thread for receiving but I want to know where is the problem is in the above code?
Any help is really appreciated ^^
If you are running in emulator, use wma console available to send or receive messages. You can't do it from emulator to emulator. wma console is available at
utilities -> wma console
I found the problem... It's because SMS doesn't work in Netbeans above versions. It only works in Netbeans 6.1 ... Something is wrong with the emulator