Akka-Java is throwing DeadLetterException on ask-await - java

I have a driver/main class in file like this. (Basically I'm trying to mix STORM & AKKA). In TenderEventSpout2 class, I am trying to send and receive message to/from an actor.
public class TenderEventSpout2 extends BaseRichSpout {
ActorSystemHandle actorSystemHandle;
ActorSystem _system;
ActorRef eventSpoutActor;
Future<Object> future;
Timeout timeout;
String result;
#Override
public void open(Map map, TopologyContext topologyContext, SpoutOutputCollector spoutOutputCollector) {
//String[] message = {"WATCH_DIR"};
timeout = new Timeout(Duration.create(60, "seconds"));
List<Object> messageList = new ArrayList<Object>();
messageList.add("WATCH_DIR");
messageList.add(this.inputDirName);
actorSystemHandle = new ActorSystemHandle();
_system = actorSystemHandle.getActorSystem();
eventSpoutActor = _system.actorOf(Props.create(EventSpoutActor.class));
future = Patterns.ask(eventSpoutActor, messageList, timeout);
}
#Override
public void nextTuple() {
String result = null;
try{
result = (String) Await.result(future, timeout.duration());
}
catch(Exception e){
e.printStackTrace();
}
}
My Actor is:
public class EventSpoutActor extends UntypedActor {
public ConcurrentLinkedQueue<String> eventQueue = new ConcurrentLinkedQueue<>();
Inbox inbox;
#Override
public void onReceive(Object message){// throws IOException {
if (message instanceof List<?>) {
System.out.println(((List<Object>)message).get(0)+"*******************");
if(((List<Object>)message).get(0).equals("WATCH_DIR")){
final List<Object> msg = (List<Object>)message;
Thread fileWatcher = new Thread(new Runnable(){
#Override
public void run() {
System.out.println(msg.get(1)+"*******************");
try {
String result = "Hello";
System.out.println("Before Sending Message *******************");
getSender().tell(result, getSelf());
}
catch (Exception e) {
getSender().tell(new akka.actor.Status.Failure(e), getSelf());
throw e;
}
}
});
fileWatcher.setDaemon(true);
fileWatcher.start();
System.out.println("Started file watcher");
}
}
else{
System.out.println("Unhandled !!");
unhandled(message);
}
}
}
I'm able to send message to my EventSpoutActor. But facing problem with receiving messages. Why is that?? I get the following message printed in console:
[EventProcessorActorSystem-akka.actor.default-dispatcher-3]
[akka://EventProcessorActorSystem/deadLetters] Message [java.lang.String]
from Actor[akka://EventProcessorActorSystem/user/$a#-1284357486] to
Actor[akka://EventProcessorActorSystem/deadLetters] was not delivered. [1]
dead letters encountered.
This logging can be turned off or adjusted with configuration settings
'akka.log-dead-letters' and 'akka.log-dead-letters-during-shutdown'.

So, I found out why the messages were not delivered.
getSender().tell(result, getSelf());
This line which is supposed to send the messages to the sender, lost it's context data, when it is used inside Thread code:
Thread fileWatcher = new Thread(new Runnable(){
#Override
public void run() {
System.out.println(msg.get(1)+"*******************");
try {
String result = "Hello";
System.out.println("Before Sending Message *******************");
getSender().tell(result, getSelf());
When I moved the "tell" code outside the thread, it worked.

Related

How can I get the data from a thread that acts as a UDP server?

I am making an Android application that receives messages from an Arduino, I implemented a UDP server opening a Thread, but I can not get the value of the answer string "lastMessage", because with this value I will make a series of actions.
This is my class served_UDP:
public class Servidor_UDP {
private boolean server_activado = true;
private String lastMessage = "";
DatagramSocket socket;
private byte[] resp;
private DatagramPacket pqtResp;
Servidor_UDP()
{
resp = new byte[1024];
try {
socket = new DatagramSocket(6000);
pqtResp = new DatagramPacket(resp, resp.length);
} catch (SocketException e) {
e.printStackTrace();
}
}
public void start(){
Thread t = new Thread(new server());
t.start();
}
public class server implements Runnable {
server() { run(); }
public void run() {
String message = "";
try {
do
{
socket.receive(pqtResp);
//message = new String(resp).trim();
message = new String(pqtResp.getData(),0,pqtResp.getLength());
lastMessage = message;
} while(server_activado);
} catch (Exception e) {
e.printStackTrace();
}
}
}
public String getString()
{
return lastMessage;
}
public void setServer(boolean b)
{
server_activado = b;
}
}
This class I implemented from the onCreate of my MainActivity:
Servidor_UDP UDP_S;
UDP_S = new Servidor_UDP();
UDP_S.start();
I try to get the results of a method of the main class and show them in a TextView to make sure that the messages are arriving but it does not show me anything, just empty.
public void actualizarUI()
{
respuesta = UDP_S.getString();
txt.setText(respuesta);
}
I await your help, thanks in advance.
Your server() constructor should not call run(). Thread.start() will do that. At present Thread.start() is never executing, let alone completing, so any code that calls your start() method will never return.
EDIT: The other answer is right!
Ok so, I think you have the problem when creating the new server()...
You could try this:
private server server;
public void start(){
server = new server();
Thread t = new Thread(server);
t.start();
}
public class server implements Runnable {
server() { /*NO run();*/ }
public void run() {
String message = "";
try {
do
{
socket.receive(pqtResp);
//message = new String(resp).trim();
message = new String(pqtResp.getData(),0,pqtResp.getLength());
lastMessage = message;
} while(server_activado);
} catch (Exception e) {
e.printStackTrace();
}
}
public String getLastMessage() {
return lastMessage;
}
}
public String getString()
{
return server.getLastMessage();
}
You are doing new server(); so I you are creating a new object, you should save it in a class variable like I did, and then create a get method in the server class...
PD: Intenta no hacer codigo en castellano :)

Getting ClassNotFound Exception in Flink SourceFunction

I'm using protocol buffer to send stream of data to Apache Flink.
I have two classes. one is Producer and one is Consumer.
Producer is a java thread class which reads the data from socket and Protobuf deserializes it and then I store it in my BlockingQueue
Consumer is a class which implements SourceFunction in Flink.
I tested this program with using:
DataStream<Event.MyEvent> stream = env.fromCollection(queue);
instead of custom source and it works fine.
But when I try to use a SourceFunction class it throws this exception:
Caused by: java.lang.RuntimeException: Unable to find proto buffer class
at com.google.protobuf.GeneratedMessageLite$SerializedForm.readResolve(GeneratedMessageLite.java:775)
...
Caused by: java.lang.ClassNotFoundException: event.Event$MyEvent
at java.net.URLClassLoader.findClass(URLClassLoader.java:381)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:331)
...
And in another attempt I mixed both classed into one (the class which implements SourceFunction). I get data from socket and deserialize it with protobuf and store it in BlockingQueue and then I read from BlockingQueue right after that. My code works fine with this approach too.
But I want to use two separate classes (multi-threading) but it throws that exception.
I'm trying to solve it in last 2 days and also did lots of searching but no luck.
Any help would be apperciated.
Producer:
public class Producer implements Runnable {
Boolean running = true;
Socket socket = null, bufferSocket = null;
PrintStream ps = null;
BlockingQueue<Event.MyEvent> queue;
final int port;
public Producer(BlockingQueue<Event.MyEvent> queue, int port){
this.port = port;
this.queue = queue;
}
#Override
public void run() {
try {
socket = new Socket("127.0.0.1", port);
bufferSocket = new Socket(InetAddress.getLocalHost(), 6060);
ps = new PrintStream(bufferSocket.getOutputStream());
while (running) {
queue.put(Event.MyEvent.parseDelimitedFrom(socket.getInputStream()));
ps.println("Items in Queue: " + queue.size());
}
}catch (Exception e){
e.printStackTrace();
}
}
}
Consumer:
public class Consumer implements SourceFunction<Event.MyEvent> {
Boolean running = true;
BlockingQueue<Event.MyEvent> queue;
Event.MyEvent event;
public Consumer(BlockingQueue<Event.MyEvent> queue){
this.queue = queue;
}
#Override
public void run(SourceContext<Event.MyEvent> sourceContext) {
try {
while (running) {
event = queue.take();
sourceContext.collect(event);
}
}catch (Exception e){
e.printStackTrace();
}
}
#Override
public void cancel() {
running = false;
}
}
Event.MyEvent is my protobuf class. I'm using version 2.6.1 and I compiled classes with v2.6.1 . I double checked the versions to be sure it's not the problem.
The Producer class is working fine.
I tested this with both Flink v1.1.3 and v1.1.4.
I'm running it in local mode.
EDIT: Answer was included in question, posted it separately and removed it here.
UPDATE 12/28/2016
...
But I'm still curious. What is causing this error? Is it a bug in Flink or am I doing something wrong?
...
The asker already found a way to make this working. I have extracted the relevant part from the question. Note that the reason why it happened remains unexplained.
I did not use quote syntax as it is a lot of text, but the below was shared by the asker:
So finally I got it to work. I created my BlockingQueue object inside SourceFunction (Consumer), and called Producer class from inside the SourceFunction class (Consumer) instead of making BlockingQueue and calling Producer class in main method of the program. and it now works!
Here's my full working code in Flink:
public class Main {
public static void main(String[] args) throws Exception {
final int port, buffer;
//final String ip;
try {
final ParameterTool params = ParameterTool.fromArgs(args);
port = params.getInt("p");
buffer = params.getInt("b");
} catch (Exception e) {
System.err.println("No port number and/or buffer size specified.");
return;
}
final StreamExecutionEnvironment env = StreamExecutionEnvironment.getExecutionEnvironment();
DataStream<Event.MyEvent> stream = env.addSource(new Consumer(port, buffer));
//DataStream<Event.MyEvent> stream = env.fromCollection(queue);
Pattern<Event.MyEvent, ?> crashedPattern = Pattern.<Event.MyEvent>begin("start")
.where(new FilterFunction<Event.MyEvent>() {
#Override
public boolean filter(Event.MyEvent myEvent) throws Exception {
return (myEvent.getItems().getValue() >= 120);
}
})
.<Event.MyEvent>followedBy("next").where(new FilterFunction<Event.MyEvent>() {
#Override
public boolean filter(Event.MyEvent myEvent) throws Exception {
return (myEvent.getItems().getValue() <= 10);
}
})
.within(Time.seconds(3));
PatternStream<Event.MyEvent> crashed = CEP.pattern(stream.keyBy(new KeySelector<Event.MyEvent, String>() {
#Override
public String getKey(Event.MyEvent myEvent) throws Exception {
return myEvent.getEventType();
}
}), crashedPattern);
DataStream<String> alarm = crashed.select(new PatternSelectFunction<Event.MyEvent, String>() {
#Override
public String select(Map<String, Event.MyEvent> pattern) throws Exception {
Event.MyEvent start = pattern.get("start");
Event.MyEvent next = pattern.get("next");
return start.getEventType() + " | Speed from " + start.getItems().getValue() + " to " + next.getItems().getValue() + " in 3 seconds\n";
}
});
DataStream<String> rate = alarm.windowAll(TumblingProcessingTimeWindows.of(Time.seconds(1)))
.apply(new AllWindowFunction<String, String, TimeWindow>() {
#Override
public void apply(TimeWindow timeWindow, Iterable<String> iterable, Collector<String> collector) throws Exception {
int sum = 0;
for (String s: iterable) {
sum ++;
}
collector.collect ("CEP Output Rate: " + sum + "\n");
}
});
rate.writeToSocket(InetAddress.getLocalHost().getHostName(), 7070, new SimpleStringSchema());
env.execute("Flink Taxi Crash Streaming");
}
private static class Producer implements Runnable {
Boolean running = true;
Socket socket = null, bufferSocket = null;
PrintStream ps = null;
BlockingQueue<Event.MyEvent> queue;
final int port;
Producer(BlockingQueue<Event.MyEvent> queue, int port){
this.port = port;
this.queue = queue;
}
#Override
public void run() {
try {
socket = new Socket("127.0.0.1", port);
bufferSocket = new Socket(InetAddress.getLocalHost(), 6060);
ps = new PrintStream(bufferSocket.getOutputStream());
while (running) {
queue.put(Event.MyEvent.parseDelimitedFrom(socket.getInputStream()));
ps.println("Items in Queue: " + queue.size());
}
}catch (Exception e){
e.printStackTrace();
}
}
}
private static class Consumer implements SourceFunction<Event.MyEvent> {
Boolean running = true;
final int port;
BlockingQueue<Event.MyEvent> queue;
Consumer(int port, int buffer){
queue = new ArrayBlockingQueue<>(buffer);
this.port = port;
}
#Override
public void run(SourceContext<Event.MyEvent> sourceContext) {
try {
new Thread(new Producer(queue, port)).start();
while (running) {
sourceContext.collect(queue.take());
}
}catch (Exception e){
e.printStackTrace();
}
}
#Override
public void cancel() {
running = false;
}
}

How to make an Android class wait until another class completes its task?

I'm writing an Android messaging application, and 1 class is calling another class, and I wish for the calling class to wait for the callee class to complete before carrying on.
Caller Class (MessageManagement) code snippet is as follows:
private static Messenger myMessenger;
try {
Message msg = Message.obtain();
msg.arg1 = constructedMessage.length();
msg.arg2 = -1;
msg.obj = constructedMessage;
Log.d(TAG, "Calling myMessenger.send()");
myMessenger.send(msg);
Log.d(TAG, "Sent");
} catch (Exception e) {
e.printStackTrace();
}
// Wait here until myMessenger completes its task
doOtherStuff();
Right now, doOtherStuff() starts and finishes before myMessenger starts. I need myMessenger to complete before doOtherStuff() starts.
I've read about wait() and notify() but I'm not sure how to implement it here, or whether it's the right choice.
Some background about the flow of the program. It's basically a messaging app that I inherited, so I'm not exactly sure of its framework. From what I can tell tracing the flow of the code:
When an SMS message is received, the SMS receiver BroadcastReceiver(SmsReceiver) handles it, getting the sender address and message body, then calling a SMS handler service(HandleSmsService), which then calls the caller class in a runnable with the following code:
HandleSmsService
public class HandleSmsService extends Service {
private String message;
private MessageManagement messageManager;
private Handler timeoutHandler = new Handler();
#Override
public void onStart(Intent intent, intent startid) {
message = intent.getExtras().getString("message");
messageManager = new MessageManagement(this);
timeoutHandler.postDelayed(runnable, 10);
}
private Runnable runnable = new Runnable() {
#Override
public void run() {
try {
messageManager.handleMessage(message);
stopSelf();
} catch (Exception e) {
e.printStackTrace();
}
}
};
MessageManagement is my caller class, and MessageManagement.handleMessage() is the top most code snippet presented earlier.
The MessageManagement.handleMessage() apparently calls another Handler in the callee class when it calls myMessenger.send(msg). This Handler code is as follows:
private Handler smsHandler = new Handler() {
#Override
public void handleMessage(Message msg) {
// do some stuff
}
};
I'm assuming the posted code is running on the MainThread and the reason why you are using a handler is that something asynchronous is done on another thread when receiving that message.
In that case, you can't use wait on the thread, as it will lock up the UI and probably cause an application not responding error.
Without changing too much of your code, one way to do it is to nest a listener in your constructedMessage for e.g.
public class DoStuffRequest {
private OnFinishListener mOnFinishListener;
private boolean isCanceled;
private String mMessage;
public interface OnFinishListener {
public void onFinish();
}
public DoStuffRequest(String message) {
mMessage = message;
}
public OnFinishListener getOnFinishListener() {
return mOnFinishListener;
}
public void setOnFinishListener(OnFinishListener onFinishListener) {
mOnFinishListener = onFinishListener;
}
public void cancel() {
isCanceled = true;
}
public void notifyFinish() {
if (!isCanceled && mOnFinishListener != null) {
mOnFinishListener.onFinish();
}
}
public String getMessage() {
return mMessage;
}
}
then use some along the line of this to get the ball rolling:
private static Messenger myMessenger;
private DoStuffRequest mRequest;
...
private void send(String message) {
mRequest = new DoStuffRequest(message);
mRequest.setOnFinishListener(new ConstructedMessage.OnFinishListener() {
#Override
public void onFinish() {
doOtherStuff();
}
});
try {
Message msg = Message.obtain();
msg.arg1 = constructedMessage.length();
msg.arg2 = -1;
msg.obj = constructedMessage;
Log.d(TAG, "Calling myMessenger.send()");
myMessenger.send(msg);
Log.d(TAG, "Sent");
} catch (Exception e) {
e.printStackTrace();
}
}
private void doThisIfYouWantToCancel() {
if (mRequest != null) {
mRequest.cancel();
}
}
your Handler/Service code can now call constructedMessage.finish() when the async stuff is done. Depending on what doOtherStuff() does (e.g. when manipulating the UI), you might want to do this on the MainThread (the code i've written above is NOT thread safe and i assume you are calling the listener on the MainThread).
Also remember to call constructedMessage.cancel() in case you do not want to get notified any more (e.g. you are leaving the activity/fragment).
this is just one way to do it, depending on your needs, some other methods might be a better choice.
I guess it should look something like this:
try {
Message msg = Message.obtain(handler, new Runnable() {
#Override
public void run() {
doOtherStuff();
}
});
msg.arg1 = constructedMessage.length();
msg.arg2 = -1;
msg.obj = constructedMessage;
Log.d(TAG, "Calling myMessenger.send()");
msg.sendToTarget();
Log.d(TAG, "Sent");
} catch (Exception e) {
e.printStackTrace();
}
The other way to do this using native means:
private static Messenger myMessenger = new Messenger(new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
// do something what you need
if (msg.getTarget() != null) {
msg.sendToTarget();
}
return false;
}
}));
try {
final Message msg = Message.obtain();
msg.setTarget(new Handler(new Handler.Callback() {
#Override
public boolean handleMessage(Message msg) {
doOtherStuff();
return false;
}
}));
msg.arg1 = constructedMessage.length();
msg.arg2 = -1;
msg.obj = constructedMessage;
Log.d(TAG, "Calling myMessenger.send()");
myMessenger.send(msg);
Log.d(TAG, "Sent");
} catch (final Exception e) {
e.printStackTrace();
}

Why used heap is always increasing in my MINA application?

I have an application which consists of two parts as server and client.
It works like this :
Client connects to the server and sends a string; server receives the string and returns an ArrayList (by converting string) which contains 10000 elements.
I wrote a class (ClientConnector.java) which simulates many clients use one connection to take those 10000 elements from server.
When I run this two programs, server side is ok. However on the client side, used heap is always increasing ! I tried to release the used objects by "null" but the used memory is still getting larger and larger.
http://s10.postimage.org/egf4ugrd5/mem.png
My Server Side Codes :
Client.java
public class Client {
private static final int PORT = 7571;
ClientHandler handler = new ClientHandler("hey");
IoConnector connector;
boolean available = true;
public synchronized void setAvailable(boolean available) {
this.available = available;
}
public synchronized boolean isAvailable() {
return available;
}
public void starter() throws InterruptedException {
Thread t = new Thread(new Runnable() {
#Override
public void run() {
connector = new NioSocketConnector();
connector.getSessionConfig().setReadBufferSize(2048);
TextLineCodecFactory t = new TextLineCodecFactory(Charset.forName("UTF-8"));
t.setEncoderMaxLineLength(20 * 150000);
t.setDecoderMaxLineLength(20 * 150000);
connector.getFilterChain().addLast("logger", new LoggingFilter());
connector.getFilterChain().addLast("codec", new ProtocolCodecFilter(t));
connector.setHandler(handler);
ConnectFuture future = connector.connect(new InetSocketAddress("localhost", PORT));
future.awaitUninterruptibly();
if (!future.isConnected()) {
return;
}
IoSession session = future.getSession();
session.getConfig().setUseReadOperation(true);
session.getCloseFuture().awaitUninterruptibly();
connector.dispose();
}
});
t.start();
Thread.sleep(300);
}
public void conClose() {
connector.dispose();
}
public ClientHandler getHandler() {
return handler;
}
public void reqInf() {
handler.reqInfo();
}
public static void main(String[] args) {
try {
Client c = new Client();
c.starter();
} catch (InterruptedException ex) {
System.out.println("error");
}
}
}
ClientHandler.java
public class ClientHandler extends IoHandlerAdapter {
long time;
private final String values;
IoSession session;
public ClientHandler(String values) {
this.values = values;
}
#Override
public void sessionOpened(IoSession session) throws InterruptedException {
this.session = session;
}
public ArrayList<String> convert(String str) {
Gson gson = new Gson();
return gson.fromJson(str, ArrayList.class);
}
#Override
public void messageReceived(IoSession session, Object message) throws InterruptedException {
try {
ArrayList<String> test = convert(message.toString());
System.out.println("TIME : " + (System.currentTimeMillis() - time) + " strList:" + test.size());
message = null;
test = null;
} catch (Exception ex) {
ex.printStackTrace();
}
}
#Override
public void exceptionCaught(IoSession session, Throwable cause) {
session.close();
System.out.println(cause.toString());
}
#Override
public void sessionClosed(IoSession session) {
System.out.println("Connection Lost");
}
public void reqInfo() {
time = System.currentTimeMillis();
session.write("test");
}
}
My Server Side :
Server.java
public class Server {
private static final int PORT = 7571; //TEST PORT
IoAcceptor acceptor = new NioSocketAcceptor();
public Server() throws IOException {
TextLineCodecFactory t = new TextLineCodecFactory(Charset.forName("UTF-8"));
t.setEncoderMaxLineLength(20*150000);
t.setDecoderMaxLineLength(20*150000);
acceptor.getFilterChain().addLast("logger", new LoggingFilter());
acceptor.getFilterChain().addLast("codec", new ProtocolCodecFilter(t));
// acceptor.getFilterChain().addLast("threadPool", new ExecutorFilter(Executors.newCachedThreadPool()));
Executor executor = new ThreadPoolExecutor(5, 70, 60, TimeUnit.SECONDS, new LinkedBlockingQueue<Runnable>());
acceptor.getFilterChain().addLast("threadPool", new ExecutorFilter(executor));
acceptor.setHandler(new ServerHandler());
acceptor.getSessionConfig().setReadBufferSize(2048);
acceptor.getSessionConfig().setIdleTime(IdleStatus.BOTH_IDLE, 1000);
//timer();
acceptor.bind(new InetSocketAddress(PORT));
System.out.println("***Mina Server is ready !");
System.out.println("");
System.out.println("");
}
public static void main(String[] args) throws IOException {
Server m = new Server();
}
}
ServerHandler.java
public class ServerHandler extends IoHandlerAdapter {
private final Logger logger = (Logger) LoggerFactory.getLogger(getClass());
IoSession sessions;
//Communication communication;
public ServerHandler() throws IOException {
loader();
// communication = new Communication(this);
}
#Override
public void sessionOpened(IoSession session) {
// set idle time to 10 seconds
session.getConfig().setIdleTime(IdleStatus.BOTH_IDLE, 1000);
System.out.println("Client Connected !!!");
//session.setAttribute("Values: ");
this.sessions = session;
}
public String toGSon(ArrayList<String> list) {
Gson gson = new Gson();
String str = gson.toJson(list);
return str;
}
ArrayList<String> str = new ArrayList<String>();
public void loader() {
for (int i = 0; i < 10000; i++) {
str.add("test" + i);
}
}
#Override
public void messageReceived(IoSession session, Object message) throws InterruptedException {
long time = System.currentTimeMillis();
session.write(toGSon(str));
System.out.println("TIME : " + (System.currentTimeMillis() - time));
}
#Override
public void sessionIdle(IoSession session, IdleStatus status) {
System.out.println("Socket #" + session.getId() + " is disconnecting... (IDLE)");
session.close();
}
#Override
public void exceptionCaught(IoSession session, Throwable cause) {
System.out.println("------------>" + cause.toString());
session.close();
}
}
And my Main Class
public class ClientConnector {
public ClientConnector() throws InterruptedException {
Client cl = new Client();
cl.starter();
while (true) {
cl.reqInf();
Thread.sleep(100);
}
}
public static void main(String[] args) throws InterruptedException {
ClientConnector cl = new ClientConnector();
}
}
You must remove below code from client side.
session.getConfig().setUseReadOperation(true);
Above code will cause memory leak.
One of our developers found an issue in Mina with the way clean up was being done and a patch was applied to version 2.0.8. Since as of today this is "snapshot" you have to grab it from git and build it yourself. Here is the command to get it from git:
git checkout 2.0
Repository uri:
git clone http://git-wip-us.apache.org/repos/asf/mina.git
This code is not enough to reach to a pin pointed answer.
Heap size continuous increase and no effect of GC --> Signs of memory leak.
Probably you should Profile your application and use some OQL Tools to find out which class is using char[], which here is the culprit looking at heap dump in your case

Netty client sometimes doesn't receive all expected messages

I have a fairly simple test Netty server/client project . I am testing some aspects of the stability of the communication by flooding the server with messages and counting the messages and bytes that I get back to make sure that everything matches.
When I run the flood from the client, the client keeps track of the number of messages it sends and how many it gets back and then when the number equal to each other it prints out some stats.
On certain occassions when running locally (I'm guessing because of congestion?) the client never ends up printing out the final message. I haven't run into this issue when the 2 components are on remote machines. Any suggestions would be appreciated:
The Encoder is just a simple OneToOneEncoder that encodes an Envelope type to a ChannelBuffer and the Decoder is a simple ReplayDecoder that does the opposite.
I tried adding a ChannelInterestChanged method to my client handler to see if the channel's interest was getting changed to not read, but that did not seem to be the case.
The relevant code is below:
Thanks!
SERVER
public class Server {
// configuration --------------------------------------------------------------------------------------------------
private final int port;
private ServerChannelFactory serverFactory;
// constructors ---------------------------------------------------------------------------------------------------
public Server(int port) {
this.port = port;
}
// public methods -------------------------------------------------------------------------------------------------
public boolean start() {
ExecutorService bossThreadPool = Executors.newCachedThreadPool();
ExecutorService childThreadPool = Executors.newCachedThreadPool();
this.serverFactory = new NioServerSocketChannelFactory(bossThreadPool, childThreadPool);
this.channelGroup = new DeviceIdAwareChannelGroup(this + "-channelGroup");
ChannelPipelineFactory pipelineFactory = new ChannelPipelineFactory() {
#Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("encoder", Encoder.getInstance());
pipeline.addLast("decoder", new Decoder());
pipeline.addLast("handler", new ServerHandler());
return pipeline;
}
};
ServerBootstrap bootstrap = new ServerBootstrap(this.serverFactory);
bootstrap.setOption("reuseAddress", true);
bootstrap.setOption("child.tcpNoDelay", true);
bootstrap.setOption("child.keepAlive", true);
bootstrap.setPipelineFactory(pipelineFactory);
Channel channel = bootstrap.bind(new InetSocketAddress(this.port));
if (!channel.isBound()) {
this.stop();
return false;
}
this.channelGroup.add(channel);
return true;
}
public void stop() {
if (this.channelGroup != null) {
ChannelGroupFuture channelGroupCloseFuture = this.channelGroup.close();
System.out.println("waiting for ChannelGroup shutdown...");
channelGroupCloseFuture.awaitUninterruptibly();
}
if (this.serverFactory != null) {
this.serverFactory.releaseExternalResources();
}
}
// main -----------------------------------------------------------------------------------------------------------
public static void main(String[] args) {
int port;
if (args.length != 3) {
System.out.println("No arguments found using default values");
port = 9999;
} else {
port = Integer.parseInt(args[1]);
}
final Server server = new Server( port);
if (!server.start()) {
System.exit(-1);
}
System.out.println("Server started on port 9999 ... ");
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
server.stop();
}
});
}
}
SERVER HANDLER
public class ServerHandler extends SimpleChannelUpstreamHandler {
// internal vars --------------------------------------------------------------------------------------------------
private AtomicInteger numMessagesReceived=new AtomicInteger(0);
// constructors ---------------------------------------------------------------------------------------------------
public ServerHandler() {
}
// SimpleChannelUpstreamHandler -----------------------------------------------------------------------------------
#Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
Channel c = e.getChannel();
System.out.println("ChannelConnected: channel id: " + c.getId() + ", remote host: " + c.getRemoteAddress() + ", isChannelConnected(): " + c.isConnected());
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
System.out.println("*** EXCEPTION CAUGHT!!! ***");
e.getChannel().close();
}
#Override
public void channelDisconnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
super.channelDisconnected(ctx, e);
System.out.println("*** CHANNEL DISCONNECTED ***");
}
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
if(numMessagesReceived.incrementAndGet()%1000==0 ){
System.out.println("["+numMessagesReceived+"-TH MSG]: Received message: " + e.getMessage());
}
if (e.getMessage() instanceof Envelope) {
// echo it...
if (e.getChannel().isWritable()) {
e.getChannel().write(e.getMessage());
}
} else {
super.messageReceived(ctx, e);
}
}
}
CLIENT
public class Client implements ClientHandlerListener {
// configuration --------------------------------------------------------------------------------------------------
private final String host;
private final int port;
private final int messages;
// internal vars --------------------------------------------------------------------------------------------------
private ChannelFactory clientFactory;
private ChannelGroup channelGroup;
private ClientHandler handler;
private final AtomicInteger received;
private long startTime;
private ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
// constructors ---------------------------------------------------------------------------------------------------
public Client(String host, int port, int messages) {
this.host = host;
this.port = port;
this.messages = messages;
this.received = new AtomicInteger(0);
}
// ClientHandlerListener ------------------------------------------------------------------------------------------
#Override
public void messageReceived(Envelope message) {
if (this.received.incrementAndGet() == this.messages) {
long stopTime = System.currentTimeMillis();
float timeInSeconds = (stopTime - this.startTime) / 1000f;
System.err.println("Sent and received " + this.messages + " in " + timeInSeconds + "s");
System.err.println("That's " + (this.messages / timeInSeconds) + " echoes per second!");
}
}
// public methods -------------------------------------------------------------------------------------------------
public boolean start() {
// For production scenarios, use limited sized thread pools
this.clientFactory = new NioClientSocketChannelFactory(cachedThreadPool, cachedThreadPool);
this.channelGroup = new DefaultChannelGroup(this + "-channelGroup");
this.handler = new ClientHandler(this, this.channelGroup);
ChannelPipelineFactory pipelineFactory = new ChannelPipelineFactory() {
#Override
public ChannelPipeline getPipeline() throws Exception {
ChannelPipeline pipeline = Channels.pipeline();
pipeline.addLast("byteCounter", new ByteCounter("clientByteCounter"));
pipeline.addLast("encoder", Encoder.getInstance());
pipeline.addLast("decoder", new Decoder());
pipeline.addLast("handler", handler);
return pipeline;
}
};
ClientBootstrap bootstrap = new ClientBootstrap(this.clientFactory);
bootstrap.setOption("reuseAddress", true);
bootstrap.setOption("tcpNoDelay", true);
bootstrap.setOption("keepAlive", true);
bootstrap.setPipelineFactory(pipelineFactory);
boolean connected = bootstrap.connect(new InetSocketAddress(host, port)).awaitUninterruptibly().isSuccess();
System.out.println("isConnected: " + connected);
if (!connected) {
this.stop();
}
return connected;
}
public void stop() {
if (this.channelGroup != null) {
this.channelGroup.close();
}
if (this.clientFactory != null) {
this.clientFactory.releaseExternalResources();
}
}
public ChannelFuture sendMessage(Envelope env) {
Channel ch = this.channelGroup.iterator().next();
ChannelFuture cf = ch.write(env);
return cf;
}
private void flood() {
if ((this.channelGroup == null) || (this.clientFactory == null)) {
return;
}
System.out.println("sending " + this.messages + " messages");
this.startTime = System.currentTimeMillis();
for (int i = 0; i < this.messages; i++) {
this.handler.sendMessage(new Envelope(Version.VERSION1, Type.REQUEST, 1, new byte[1]));
}
}
// main -----------------------------------------------------------------------------------------------------------
public static void main(String[] args) throws InterruptedException {
final Client client = new Client("localhost", 9999, 10000);
if (!client.start()) {
System.exit(-1);
return;
}
while (client.channelGroup.size() == 0) {
Thread.sleep(200);
}
System.out.println("Client started...");
client.flood();
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
System.out.println("shutting down client");
client.stop();
}
});
}
}
CLIENT HANDLER
public class ClientHandler extends SimpleChannelUpstreamHandler {
// internal vars --------------------------------------------------------------------------------------------------
private final ClientHandlerListener listener;
private final ChannelGroup channelGroup;
private Channel channel;
// constructors ---------------------------------------------------------------------------------------------------
public ClientHandler(ClientHandlerListener listener, ChannelGroup channelGroup) {
this.listener = listener;
this.channelGroup = channelGroup;
}
// SimpleChannelUpstreamHandler -----------------------------------------------------------------------------------
#Override
public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) throws Exception {
if (e.getMessage() instanceof Envelope) {
Envelope env = (Envelope) e.getMessage();
this.listener.messageReceived(env);
} else {
System.out.println("NOT ENVELOPE!!");
super.messageReceived(ctx, e);
}
}
#Override
public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) throws Exception {
System.out.println("**** CAUGHT EXCEPTION CLOSING CHANNEL ***");
e.getCause().printStackTrace();
e.getChannel().close();
}
#Override
public void channelConnected(ChannelHandlerContext ctx, ChannelStateEvent e) throws Exception {
this.channel = e.getChannel();
System.out.println("Server connected, channel id: " + this.channel.getId());
this.channelGroup.add(e.getChannel());
}
// public methods -------------------------------------------------------------------------------------------------
public void sendMessage(Envelope envelope) {
if (this.channel != null) {
this.channel.write(envelope);
}
}
}
CLIENT HANDLER LISTENER INTERFACE
public interface ClientHandlerListener {
void messageReceived(Envelope message);
}
Without knowing how big the envelope is on the network I'm going to guess that your problem is that your client writes 10,000 messages without checking if the channel is writable.
Netty 3.x processes network events and writes in a particular fashion. It's possible that your client is writing so much data so fast that Netty isn't getting a chance to process receive events. On the server side this would result in the channel becoming non writable and your handler dropping the reply.
There are a few reasons why you see the problem on localhost but it's probably because the write bandwidth is much higher than your network bandwidth. The client doesn't check if the channel is writable, so over a network your messages are buffered by Netty until the network can catch up (if you wrote significantly more than 10,000 messages you might see an OutOfMemoryError). This acts as a natural break because Netty will suspend writing until the network is ready, allowing it to process incoming data and preventing the server from seeing a channel that's not writable.
The DiscardClientHandler in the discard handler shows how to test if the channel is writable, and how to resume when it becomes writable again. Another option is to have sendMessage return the ChannelFuture associated with the write and, if the channel is not writable after the write, block until the future completes.
Also your server handler should write the message and then check if the channel is writable. If it isn't you should set channel readable to false. Netty will notify ChannelInterestChanged when the channel becomes writable again. Then you can set channel readable to true to resume reading messages.

Categories

Resources