1

[PROBLEM] : I have a Netty Server that will listen to a client over TCP , and process the request and send back the response. The problem is that processing part takes time because it needs a validation from a application user . The client is sending more than one request one after another and server doesn't seem to accept the client's request until the previous one is completed.

I have replicated the scenario where client will send couple of request one after another and a server which will take request and process by taking some time . I can work fine with a single request blocking request by passing the blocking operation to another thread and complete the remaining operation. But that still does not accepts second request from client.It will still wait for blocking operation to complete before accepting another request from client.

CLIENT CODE

int count =0;
long currentTime = System.currentTimeMillis();
long trigger = currentTime + 5000;
long stop_loop = currentTime + 130000;
while(count<2){
  boolean loop = true;
  while(loop){
    if(System.currentTimeMillis()>trigger){
      trigger += 5000;
      count++;
      loop = false;
    }
  }
  System.out.println("SENDING FOR COUNTER - "+count);
  content = Unpooled.copiedBuffer(b);
  System.out.println("Channel Active Method Called: "+ctx);
  ctx.write(content);
  ctx.flush();
}

SERVER CODE:

public void channelRead(ChannelHandlerContext ctx, Object msg) { 
final ExecutorService blockingThreadPool = Executors.newFixedThreadPool(10);
  try {
  System.out.println("server receive orde:"+body+"the counter is:" + ++counter);
  ctx.executor().execute(new Runnable(){
     public void run(){
        try{
            new MyBusinessLogicHandler(blockingThreadPool).channelRead(ctx , b_buf);
        }
        catch(Exception e ){
           logger.error(e.getMessage());
        }
     }
  }
  //ByteBuf resp = Unpooled.copiedBuffer(currentTime,CharsetUtil.UTF_8);
  //ByteBuf resp = Unpooled.wrappedBuffer(response.getBytes());
  //ctx.writeAndFlush(resp);
 // ctx.write(resp);
  //ctx.flush();
}

MyBusinessLogic

 @Override
    public void channelRead(ChannelHandlerContext ctx, Object arg1)
                throws Exception{
         System.out.println(" INSIDE BUSINESS HANDLER - OBJ");
         System.out.println(arg1);

         String x = ctx.channel().attr(DiscardServerHandler.CHECKSUMKEY).get();
         System.out.println("X -"+x);

         ChannelHandlerContext temp = ctx;

         resp = Unpooled.wrappedBuffer(x.getBytes());
         ctx.write(resp);
         ctx.flush();
         ByteBuf buf = (ByteBuf) arg1;
            byte[] req = new byte[buf.readableBytes()];
            buf.readBytes(req);
            String body = new String(req,CharsetUtil.UTF_8);
            System.out.println(new Date());
            System.out.println("Business logic receive order : " + body);

            System.out.println("SERVER LISTENER READ");
            boolean loop = true;
            long currentTime = System.currentTimeMillis();
            long trigger = currentTime + 3000;
            long stop_loop = currentTime + 20000;
            int count = 0;
                System.out.println("Server READ");
//              String response = "Server Complete Response ";

                while(loop){
                    long now = System.currentTimeMillis();

                    if(now<stop_loop){

                        if(now>trigger){
                            count++;
                            System.out.println("Now is triggered @" + count + "-- "+(count*5)+"secs passed");
                            trigger += 5000;
                        }

                    }
                    else if(now>stop_loop){
                        loop = false;
                        System.out.println("Loop Completes");
                    }
                }
            String re = "BUSINESS LOGIC RESPONSE";  
            resp = Unpooled.wrappedBuffer(re.getBytes());

            temp.write(resp);
            temp.flush();

     }

All I want is to accept all the client request as they come irrespective of a request completed/incomplete that came before it.

prashantk87
  • 81
  • 1
  • 1
  • 7

1 Answers1

0

This is classic pattern where you need to switch from synchronous service to asynchronous ("async") service. The idea of async service is that you receive request from the client, and just validate it an store it in the some storage on the server (usually queue) in your "TO DO" list. And then you return the response (in this case called acknowledgement ("ack")). In your response you return to client the id of his request and the medium by which the answer will be returned. (Usually a queue). So the client will know where to listen for the result. Meanwhile you can now on the server process your received requests without holding client up. You can also have several instances of "workers" that take incoming requests from your storage and process it. Once the request is processed your worker process publishes it under the same id that you returned to a client in your "ack" to the the medium (queue) that you returned to your client in your "ack". For more info look here: Asynchronous vs synchronous execution, what does it really mean?

Michael Gantman
  • 7,315
  • 2
  • 19
  • 36
  • I could have tried few things myself if I had the client's control or access to source code . the client's behavior is not in our control as it's managed by manufacturer's of product. we just know the format of the requests and we have to respond. Also, we are not allowed to request change the client. – prashantk87 Sep 09 '19 at 09:52
  • Then you have a problem. Partial solution would be that you create a "worker" class and make a pool of instances of that class. Each time request comes the available worker should be taking care of it. So you can treat simultaneously several requests. But the time of response will still be at best not shorter then full time of processing a single request. You may just eliminate a waiting idle time – Michael Gantman Sep 09 '19 at 10:29