I'm working on a websocket implementation that collects data from several (around 10) android clients.
So I have created a classic ServerEndpoint running currently on localhost and on client side an app that opens up a connection to the ServerEndpoint and sends sensor data every 500ms.
The whole thing works fine and on time if I use just one client.
However if I use multiple clients, they send their messages all on time, but the ServerEndpoints onMessage is called at random times. It looks like it "queues" messages from a clients for several seconds, and then fires the onMessage method 5 times in a row. I would need it always on the exact time however. Can I force this?
No errors or exceptions showing up.
This is the very basic server side:
#ServerEndpoint("/ServerEndpoint")
public class ServerEndpoint {
static Set<Session> connections = Collections.synchronizedSet(new HashSet<Session>());
#OnOpen
public void handleOpen(Session userSession){
log("opened session: "+ userSession);
connections.add(userSession);
}
#OnMessage
public void handleMessage(String message, Session userSession) throws IOException{
String userName = (String) userSession.getUserProperties().get("username");
log("received message from: "+ userName+": "+Calendar.getInstance().get(Calendar.SECOND)+":"+Calendar.getInstance().get(Calendar.MILLISECOND)+ " "+ message );
....
}
#OnClose
public void handleClose(Session userSession){
log("closed session: "+userSession);
connections.remove(userSession);
}
I guess I miss some configuration option of the ServerEndpoint or something. Does someone know what causes this behavior and how to solve it?
Alright got it. The issue was Tomcat 7 which has obviously some issues with websockets. Using Tomcat 8, it works now without any queues or big delay. Also other minor errors and connection problems were solved by the update and it seems to be much more stable.
Maybe this helps someone facing similar problems.
Related
We use akka to stress test one of our systems by sending JMS messages in parallel to our system entry points.
At a very high level, there is a Boss actor and a number of Worker actors that do the job.
When Boss actor is created in its constructor it also creates the Worker actors and puts them in a map:
workers = endPoints.stream().collect(Collectors.toMap(e -> e, e -> newWorker(e, ...)));
Then when the Boss receives the StartTesting message it just iterates to the list of its workers and send a PerformWork message to each one. Upon receiving the PerformWork message each worker goes to the database get the messages to send out, and start sending them to its associated end point. Nothing out of the ordinary here:
logger.info("Number of worker actors: " + workers.values().size());
PerformWork performWork = new PerformWork();
workers.values().forEach(w -> {
logger.info("Sending PerformWork message to " + w);
w.tell(performWork, getSelf());
});
When running we can see in the logs the following:
... Number of worker actors: 43
... Sending a PerformWork message to Actor[akka://.../WORKER-1
... Sending a PerformWork message to Actor[akka://.../WORKER-2
.
... WORKER-1: received message of type PerformWork
... Sending a PerformWork message to Actor[akka://.../WORKER-30
.
The number of Sending a PerformWork log entries are never equals with the number of workers (43 in this case). Usually between 20 and 30 but not necessarily always the same. The number of WORKER-x received message of PerformWork entries are usually smaller than the messages sent. The worker actors that actually received the PerformWork message perform what they are supposed to do without any problem.
However we never seen the rest of the Sending ... or Received ... messages in the logs for the rest of the workers, and obviously those end points associated with them never receive any message.
So my questions would be:
What I am doing wrong? Maybe my approach is too naive. I am not very experienced with akka, never used it beyond building testing tools.
What will cause the sending PerformMessage loop above to never complete.
What will cause the delivery of PerformMessage above to fail.
All this processing is happening inside the same JVM. I am open to any other suggestion that will help me understand what is going on and address the issue.
The testing tool is written in Java. I added the Scala tag thinking that Scala developers would be more familiar with akka, given Actor framework is part of the language.
Thank you in advance.
UPDATE
I worked out what was causing the issue, and I was able to fix it, however I still don't have an explanation about why was happening and it would be good to have an understanding.
So before the fix the Worker code looked like below:
#Override
public void onReceive(final Object message) throws InterruptedException {
if (message instanceof PerformWork) {
// here is the code using jdbcTemplate to get messages
// from database and send them to the system end point
getSender().tell(new WorkDone(), getSelf());
} else {
logger.info("Not prepared to handle message of type " + message.getClass());
unhandled(message);
}
}
And I changed it to start sending messages with a delay of two seconds:
#Override
public void onReceive(final Object message) throws InterruptedException {
if (message instanceof PerformWork) {
new Timer().schedule(
new TimerTask() {
#Override
public void run() {
proceedWithSendingMessages();
}
},
2000
);
} else {
logger.info("Not prepared to handle message of type " + message.getClass());
unhandled(message);
}
}
private void proceedWithSendingMessages() {
// here is the code using jdbcTemplate to get messages
// from database and send them to the system end point
getSender().tell(new WorkDone(), getSelf());
}
After the above change everything started working but the question I have is why the issue existed in the first place. It seems to me that what I experienced is against the asynchronous processing concept.
Again thank you in advance for your inputs.
UPDATE 2
In a normal run each worker runs for 24 hours. Remember it is a stress/load test so no WorkDone message is sent back to the Boss in less than this time. My akka application got hung after less than one second after starting. As I said all the workers that received the PerformWork were running normally and kept sending messages for 24 hours.
When receiving a WorkDone message the Boss verify if all Workers are done and if so it shuts down akka. I am attaching the code here as it was requested but I don't think it has anything to do with my problem.
} else if (message instanceof WorkDone) {
// completed below is a set
completed.add(((WorkDone) message).getSystem())
if (completed.size() == workers.size()) {
shutDownAkka();
}
}
I realized that was the Worker starting the work immediately after receiving a PerformWork message causing my issue by changing the database in such a way that it will be nothing to send so by querying an empty database made everything to work OK but finished straight away.
I suspected something funny would be caused by the spring JdbcTemplate bean which was singleton and being thread safe will lock things when multiple workers will try to use it immediately. I changed it to be prototype but the problem staid the same. I even made it new JdbcTemplate(singletonDatasource) with no luck. On the other hand I thought it must not be JdbcTemplate as 99% of the Java world it is using it.
At this point I added the delay in the worker code as posted in my first UPDATE thinking it was important all workers receive the PerformWork notification. Once I did this all started working and no problems. However I would be interested to know what would have caused this.
ive got the following code as kind of a hello world test for restlet
public static void main(String[] args) throws Exception {
//Find a way to get these from the ARGS...
Settings.setCurrent(new Settings());
// Create a new Restlet component and add a HTTP server connector to it
component.getServers().add(Protocol.HTTP, 8182);
component.getContext().getParameters().add("maxThreads", "512");
component.getContext().getParameters().add("minThreads", "100");
component.getDefaultHost().attach("/findMissingPackages", Jeblet.class);
// Now, let's start the component!
// Note that the HTTP server connector is also automatically started.
component.start();
}
#Get
public String toString() {
try {
Thread.sleep(10000);
}
catch(Exception ex) { }
String settingString = "stuff";
return settingString;
}
The problem I'm having is if I open two tabs in chrome and access the server twice in a row it takes 20 seconds to get a response on the second tab. This should take 10 seconds for both tabs.
when I debug I only have one dispatcher. how do I tell restlet that I would like more than one thread?
Opening a new browser tab (or window) is not the same as opening a new connection. Browsers are really good at re-using already open connections and the 20 seconds delay is evidence of that. You can verify this by printing out the remote IP + port in your server, it will be the same for both requests.
In Firefox you can force a new connection by pressing ctrl+F5, Chrome probably has a similar feature. But you could also write a little (multi-threaded) client program that does the get-request: it is not that difficult to write and will come in handy when you need to test/debug other features of your server.
I'm trying to run a Jetty Server that can have a number of people connect to the server and see a list of print outs. I want everybody who connects to see the same values printed out.
For instance, if I have a single list keeping track of the time and I want 5 or so people to be able to go to my website (e.g. localhost:8080/time) and have them all see what time it is every 30 seconds, how would i set that up?
What I have:
I am using Jetty.
I created a single server bound to port 8080.
I created my own handler that extends AbstractHandler
this writes to the screen saying when an event has transpired (i.e. 30 seconds have passed)
If two people connect to this page, they each see a print out every minute (that is it switches back and forth letting each person know when every other event has transpired)
If 3 people connect, only two can stay connected and the third just spins getting no output to the screen
I have not set up an Connectors of my own since my attempts to do so have been unsuccessful and i'm not sure how I understand if that is the solution to my problem.
Any help would be much appreciated and if anybody has some idea but needs some clarification on what I am doing I would be glad to give more details.
Thanks!
Handler code:
#Override
public void handle(String target, Request request, HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse) throws IOException, ServletException
{
httpServletResponse.setContentType("text/html;charset=utf-8");
httpServletResponse.setStatus(HttpServletResponse.SC_OK);
request.setContextPath("/time");
request.setHandled(true);
while (true) {
synchronized(Main.list) {
while (!Main.list.isEmpty()) {
Double time = Main.list.get(0);
httpServletResponse.getWriter().println("<h1>The time now is " + time + "</h1>");
httpServletResponse.flushBuffer();
Main.list.remove(0);
}
try {
Main.list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
So the list object is a static ArrayList defined in the Main class that I wake up (i.e. notify) every 30 seconds. Hopefully this helps someone understand more what I am talking about as i'm not sure what I could change in the handler...
How are you feeding clients into your handler? Browsers have limits to the number of connections are made to to a particular host, perhaps your seeing that.
there is nothing intrinsically wrong that handler code aside from it being a generally odd thing to see in a handler
I'm sending JMS requests to a Weblogic 10.3 server through a named JMS queue, and receive a reply back through a temporary queue.
Client (barebone):
//init
Destination replyQueue = session.createTemporaryQueue();
replyConsumer = session.createConsumer(replyQueue);
...
//loop
TextMessage requestMessage = session.createTextMessage();
requestMessage.setText("Some request")
requestMessage.setJMSReplyTo(replyQueue);
requestProducer.send(requestMessage);
Message msg = replyConsumer.receive(5000);
if (msg instanceof TextMessage) {
...
} else { ... }
//loop end
Server MDB (message driven bean):
public void onMessage(Message msg) {
if (msg instanceof TextMessage) {
...
TextMessage replyMessage = jmsSession.createTextMessage();
replyMessage.setText("Some response");
replyMessage.setJMSCorrelationID(msg.getJMSCorrelationID());
replyProducer.send(replyMessage);
}
}
The problem is that the very first server reply is often lost! That is, the replyConsumer.receive(5000) ends with timeout for every 4th-5th replyConsumer. When the consumer receives the first answer, then it continues to receive all the rest, so the problem is only with the first message send through the temporary queue after the temp queue has been created.
My question: Do I have to set something special for the temporary queue in order it works from the very start after being created? Or any other hint?
Further info:
When testing against my local development machine, the temp queues work without problem. The messages are getting lost only when testing against our clustered Weblogic server. However, I have switched off all cluster members but one instance.
I have verified that the server successfully replies all the requests that the client sends (by counting the sent requests and sent replies). The server replies in the order of milliseconds, even for the lost replies.
When I replace the temporary queue with a regular named queue, the problem disappears! So the problem doesn't seem (to me) to be in my code.
I've also tried to modify expiration, persistency, delay etc. of the reply message, but without success. This way I excluded the scenario that the response arrives earlier than the client begins to read the queue, and then the message immediately expires not giving the client a chance to process it.
Edit: Instead of the synchronous replyConsumer.receive(5000) I've also tried to use the asynchronous replyConsumer.setMessageListener(this). The behaviour hasn't changed, first messages are still getting lost for temp queues.
Edit: It seems that there's something wrong with the Weblogic server (or cluster) I am using. Because when I deployed the server application to another Weblogic cluster we have, everything began to work correctly! Both clusters should be configured identically - so where's a difference? It scares me that the Weblogic signals no error.
Your problem seems to be that sometimes the server is receiving the publish and discarding it before your consumer has started receiving.
The way around it is to use the asynchronous receive (replyConsumer.setMessageListener) calls instead of the blocking call you currently have (replyConsumer.receive(5000)) and to add the call to the code with the rest of your consumer code.
That way, you are already listening for replies before you send out the request.
Hope that helps.
Edit: Just read that you are using a temporary queue, so my first sentence is not correct. However as an experiment try the rest of my response to see if it changes the behaviour you are seeing
I am using Tapestry 5, Smack api 3.1.0.
I have established a connection and am able to communicate with a user through the xmpp server but the replies i get are sent to the standard output as they come in:
Chat chat = connection.getChatManager().createChat("blah#jabber.org", new MessageListener() {
public void processMessage(Chat chat, Message message) {
// Print out any messages we get back to standard out.
System.out.println("Received message: " + message.getBody()); // this works
showonbrowser = message.getBody();
System.out.println(showonbrowser) // this prints nothing
}
};
I am looking to get the replies to my html file so i can read them on the web instead of the console. However, when i try to set message.getBody() to showonbrowser (a property on the page) i see no result. Does anyone know how I get around this?
Regards,
Kace
Smack is multi-threading and it has a nasty habit of eating up exceptions that are thrown (silently.) Most likely you are not using a thread-safe GUI and its throwing an exception that you never get.
I think the processMessage method is being called after the page is rendered.
You are creating a MessageListener instance (through an anonymous class), so you don't know when the processMessage method will be called. I think you would have to do something with AJAX to do partial updates on the page, polling the server and getting any new messages to show them on the page.