Re: netty 4.0.25 error: Duplicate handler name

727 views
Skip to first unread message

Leonardo Gomes

unread,
Feb 27, 2015, 5:08:22 PM2/27/15
to ne...@googlegroups.com
You can get several requests on the same connection and I would say only the first request should modify the pipeline. The same pipeline is being used for several requests, if they are sent on the same connection. You have one instance of a pipeline for each Channel instance (i.e. connection), that's why the pipeline is initialized within a ChannelInitializer.

You can check if the handler has already been added with ctx.pipeline().get("handlerName").

HTH,
Leo

On Fri, Feb 27, 2015 at 1:46 PM, Tanima Saini <tanim...@gmail.com> wrote:
Hi,

I am using netty 4.0.25Final to write a netty HTTP server. Apart from http codecs, I have three "sharable" handlers say handler1, handler2 and handler 3. I am modifying netty pipeline when the server gets a http request based on a condition. My pipeline looks like:

pipeline.addLast(new HttpRequestDecoder(4096, 8192, 8192, false),
                     new HttpResponseEncoder(),
                     new HttpObjectAggregator(1048576),
                     handler1
                     ); 
pipeline
        .addLast("handler2", ExceptionHandler.getInstance());


In channelRead0 of handler1, based on a condition I add handler3 like:
ctx.pipeline().addBefore("handler2", "handler3", Handler3.getInstance());

I am trying to make 10 calls to my server with keep-alive= true using the following command
weighttp -c 1 -n 10 -k "http://localhost:8080/abc"

Some of the request gives the below exception:
[ERROR] 27 Feb 2015 12:33:52,370 (com.server.netty.Pipeline.ExceptionHandler:exceptionCaught:49)

java.lang.IllegalArgumentException: Duplicate handler name: CheckTrafficHandler
        at io.netty.channel.DefaultChannelPipeline.checkDuplicateName(DefaultChannelPipeline.java:959)
        at io.netty.channel.DefaultChannelPipeline.addBefore(DefaultChannelPipeline.java:159)
        at io.netty.channel.DefaultChannelPipeline.addBefore(DefaultChannelPipeline.java:151)
        at com.vdopia.rtb.netty.Pipeline.Handler1.channelRead0(RequestDecoder.java:156)
        at com.vdopia.rtb.netty.Pipeline. Handler1.channelRead0(RequestDecoder.java:98)
        at io.netty.channel.SimpleChannelInboundHandler.channelRead(SimpleChannelInboundHandler.java:105)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:294)
        at io.netty.handler.codec.MessageToMessageDecoder.channelRead(MessageToMessageDecoder.java:103)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:294)
        at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:182)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:308)
        at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:294)
        at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:846)
        at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:130)
        at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:511)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:468)
        at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:382)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:354)
        at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:116)
        at io.netty.util.concurrent.DefaultThreadFactory$DefaultRunnableDecorator.run(DefaultThreadFactory.java:137)
        at java.lang.Thread.run(Thread.java:745)

The exception goes off if I do any of the following:
1. I remove keep-alive while making a call to the server
2. Dont use dynamic pipeline.

Has anybody encountered this error? It seems as if same pipeline is being used across some http requests. Please help me to resolve this issue.

Thanks & Regards,
Tanima

--
You received this message because you are subscribed to the Google Groups "Netty discussions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to netty+un...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/netty/b0160563-60c8-430d-8d94-8cf1361097a6%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Tanima Saini

unread,
Mar 1, 2015, 2:16:24 AM3/1/15
to ne...@googlegroups.com, leonardo...@gmail.com
I now understand that same pipeline is used if several requests are sent on the same connection. I have some more doubts regarding this. Below is how my netty pipeline looks like

Based on various parameters in the HTTP GET requests , various handlers are added in the pipeline. Asynchronous handler performs the asynchronous operation and frees up the NIO EventLoop thread. As the result is received in callback thread, it calls fireChannelRead on ChannelHandlerContext.

@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
    
if (msg instanceof FullHttpRequest) {
        
FullHttpRequest req = (FullHttpRequest)msg;
        
        
// Fully asynchronous does not block
        doAsyncOperation
().onSuccess(new Function() {
            
public void String call(String response) {
                ctx
.fireChannelRead(response);
            
}
        
});
    
}
}

1. Is the approach to handle asynchronous operation in this way correct? Is it ok to hold on the ctx object? I assume that the implementation of ChannelHandlerContext dispatch the write to an executor service so it is not run on the same thread as the callback.

2. Assuming the above implementation is correct - Suppose first http call goes through business logic handler1 - >AsyncHandler1 (it fires the db call and frees up NIOEventLoop thread). Before the the async operation completes, the second request comes on the same connection(channel), and now the parameters are such that it has to modify the pipeline and goes to business logic handler2. Now when the async operation completes  and it fires channel read, the pipeline would have already been modified and it will go to the wrong handler. How can I solve this problem? 

3. I looked at the PortUnification example. It also adds the channel handlers dynamically based on some conditions. The difference between the example and my scenario is my all handlers are shareable. Does this make any difference or the example will also have the same problem? Also, this example does 

pipeline.remove(this); 
// this is PortUnificationServerHandler which is the decisionHandler 

Can somebody tell me why this is done? Is this required?

4. Is there a way in which pipeline is not reused even if multiple requests come on the same connection(channel) ?

Thanks & Regards,
Tanima

이희승 (Trustin Lee)

unread,
Mar 6, 2015, 12:53:50 AM3/6/15
to ne...@googlegroups.com
Comments inline

On Sun, Mar 1, 2015, at 04:16 PM, Tanima Saini wrote:
I now understand that same pipeline is used if several requests are sent on the same connection. I have some more doubts regarding this. Below is how my netty pipeline looks like


Based on various parameters in the HTTP GET requests , various handlers are added in the pipeline. Asynchronous handler performs the asynchronous operation and frees up the NIO EventLoop thread. As the result is received in callback thread, it calls fireChannelRead on ChannelHandlerContext.

@Override
publicvoid channelRead(ChannelHandlerContext ctx,Object msg)throwsException{
if(msg instanceofFullHttpRequest){
FullHttpRequest req =(FullHttpRequest)msg;

// Fully asynchronous does not block
        doAsyncOperation
().onSuccess(newFunction(){

publicvoidString call(String response){
                ctx
.fireChannelRead(response);
}
});
}
}

1. Is the approach to handle asynchronous operation in this way correct? Is it ok to hold on the ctx object? I assume that the implementation of ChannelHandlerContext dispatch the write to an executor service so it is not run on the same thread as the callback.
 
Correct.
 
2. Assuming the above implementation is correct - Suppose first http call goes through business logic handler1 - >AsyncHandler1 (it fires the db call and frees up NIOEventLoop thread). Before the the async operation completes, the second request comes on the same connection(channel), and now the parameters are such that it has to modify the pipeline and goes to business logic handler2. Now when the async operation completes  and it fires channel read, the pipeline would have already been modified and it will go to the wrong handler. How can I solve this problem? 
 
You'll have to keep the reference to the future of the last asynchronous operation and add a follow-up async operation to it. In Netty's Future, it's done via addListener(). In CompletableFuture, it's thenApply().
 
3. I looked at the PortUnification example. It also adds the channel handlers dynamically based on some conditions. The difference between the example and my scenario is my all handlers are shareable. Does this make any difference or the example will also have the same problem? Also, this example does 
 
The PortUnification example does not have a race condition because pipeline manipulation is performed only once and it is done from the I/O thread.  There's no chance of race.
 
 
pipeline.remove(this); 
// this is PortUnificationServerHandler which is the decisionHandler
 
Can somebody tell me why this is done? Is this required?
 
4. Is there a way in which pipeline is not reused even if multiple requests come on the same connection(channel) ?
 
There's no way to achieve that currently. I'm not really sure if such a feature will be useful enough to compensate for the loss of performance, though.
 
HTH,
T
 
Reply all
Reply to author
Forward
0 new messages