Maxi Wu Maxi Wu - 17 days ago 7
Java Question

How Netty ChannelFuture works?

I've read Netty Guide, it does not explain much on ChannelFuture. I find ChannelFuture is a complex idea when applying it.

What I am trying to do is to write message to a context after it's initial response. Different from typical request/response flow. I need a flow like this:


  1. Client send request -> Server (netty)

  2. Server send a response with ctx.writeAndFlush(msg);

  3. Server send some more message to that ctx after step 2 is complete.



The problem is that if I do something like this, the second write will not send out:

ctx.writeAndFlush(response);
Message newMsg = createMessage();
ctx.writeAndFlush(newMsg); //will not send to client


Then I try to use ChannelFuture, it works, but I am not sure if I am logically correct:

ChannelFuture msgIsSent = ctx.writeAndFlush(response);
if(msgIsSent.isDone())
{
Message newMsg = createMessage();
ctx.writeAndFlush(newMsg); //this works
}


or should I use a ChannelFutureListener() instead?

ChannelFuture msgIsSent = ctx.writeAndFlush(response);
msgIsSent.addListener(new ChannelFutureListener(){
@Override
public void operationComplete(ChannelFuture future)
{
Message newMsg = createMessage();
ctx.writeAndFlush(newMsg);
}
});


Will this also works?

Which one is the best practice approach? Is there any potential problem using method 2?

Answer

Of course, this depends too on your "protocol" (meaning for instance if you use HTTP, sending 2 answears for the same request is not supported by HTTP protocol). But let say your protocol allows you to send multiple response parts:

Netty add messages to send to the pipeline, respecting the order.

So in your first example, I'm a bit surprised it does not work:

ctx.writeAndFlush(response);
Message newMsg = createMessage();
ctx.writeAndFlush(newMsg); // should send the message

However it could be lead by your protocol. For instance, this could happen:

response in message queue to send
flush not yet done
newMsg in message queue to send
flush now come but protocol does not support 2 messages so only send first one

So if your protocol must admit that first message is sent already, then you have to wait for the first, so doing something like:

ctx.writeAndFlush(response).addListener(new ChannelFutureListener() {
  @Override
  public void operationComplete(ChannelFuture future) {
    if (future.isDone()) {
      Message newMsg = createMessage();
      ctx.writeAndFlush(newMsg);
    } else { // an error occurs, do perhaps something else
    }
  }
});

So your last proposal (I've just don't create a ChannelFuture but directly used the result of writeAndFlush, but both are equals). Just take care of the case where operationComplete does not mean it is in success.