Netty messageReceived超时

时间:2016-10-17 23:50:07

标签: java timeout netty

我需要在我的ChannelHandler中使用messageReceived(或channelRead0 for netty 4.0)方法在一定时间阈值后超时。我尝试过Read / WriteTimeoutHandlers,但是当我的messageReceived处理时间超过超时时,无法生成异常。这就是我的尝试:

$posts = $wpdb->get_results("SELECT *, ( 6371 * acos( cos( radians($currLat) ) * cos( radians( m1.meta_value ) ) * cos( radians( m2.meta_value ) - radians($currLong) ) + sin( radians($currLat) ) * sin( radians( m1.meta_value ) ) ) ) AS distance, m3.meta_value as bAddressOne, m1.meta_value as bLat, m2.meta_value as bLong, m4.meta_value as bOpenClose
FROM wp_posts p
LEFT JOIN wp_postmeta m1
    ON p.id = m1.post_id AND m1.meta_key = 'bLat'
LEFT JOIN wp_postmeta m2
    ON p.id = m2.post_id AND m2.meta_key = 'bLong'
LEFT JOIN wp_postmeta m3
    ON p.id = m3.post_id AND m3.meta_key = 'bAddressOne'
LEFT JOIN wp_postmeta m4
    ON p.id = m4.post_id AND m4.meta_key = 'bOpenClose'
     WHERE post_type='el2-business' HAVING distance < $thedistance ORDER BY distance");

我添加了一个冗余for循环,用于在channelRead0方法中模拟等待,以模拟较长的处理时间。但是没有生成超时异常。 我也尝试安排等待,但没有得到超时异常 你能提出任何解决方案吗?

1 个答案:

答案 0 :(得分:1)

你要做的事情有两个问题,一个是睡眠线程而不是通过调度使用异步延迟引起的,另一个是你需要回到使用 ReadTimeoutHandler

不要睡觉或阻止

而不是Thread.sleep为什么不尝试延迟安排工作。使用Netty,您的超时将发生在您发送到睡眠的同一个线程中,因此您仍然可以在超时检查发生之前编写响应。如果您安排延迟,则线程可以自由检测超时并触发异常。

请记住,netty为多个通道使用一个IO线程,因此您不应该在该线程中执行任何阻塞/同步工作。 Thread.sleep,busy循环,同步调用,阻塞调用(例如Future.get())不应该在IO线程中完成,因为这会影响其他通道的性能。

您可以使用context获取遗嘱执行人来安排延迟工作。

public void channelRead0(ChannelHandlerContext ctx, FullHttpRequest request) {
    ctx.executor().schedule(new Runnable() {
        @Override
        public void run() {
            // Put your try/catch in here
        }
    }, 5000, TimeUnit.MILLISECONDS);
}

如果您必须进行阻止呼叫

如果您不能进行阻塞调用或进行一些密集处理,则在添加处理程序时使用不同的EventExecutorGroup,以允许从IO Worker线程异步完成该工作。请确保为其提供足够的线程以满足您的预期工作负载和连接数。

下面的示例代码应该与您的Thread.sleep或繁忙循环一起使用。请务必使用符合您需求的编号定义/替换OFFLOAD_THREADS。

public class HttpServerInitializer extends ChannelInitializer<SocketChannel> {
    private final EventExecutorGroup executors = new DefaultEventExecutorGroup(OFFLOAD_THREADS);
    @Override
    public void initChannel(SocketChannel ch) {
        ChannelPipeline p = ch.pipeline();

        p.addLast(new HttpRequestDecoder());
        p.addLast(new HttpResponseEncoder());
        p.addLast(new HttpObjectAggregator(1048576));
        p.addLast(new HttpContentCompressor());
        p.addLast("idleTimeoutHandler", new IdleStateHandler(0, 1, 0));
        p.addLast(executors, new HttpRequestHandler());
    }
}

使用IdleStateHandler

如果写入时间过长,WriteTimeoutHandler会超时。在你开始第一次写作之前,它甚至不会开始计时。看起来你试图在写入甚至开始之前导致延迟,所以即使你按照上面的建议停止使用睡眠,WriteTimeoutHandler也不会触发你。

如果您真的想要超时开始编写所需的时间,那么您应该使用 IdleStateHandler 并处理它触发的用户事件。与WriteTimeoutHandler不同,IdleStateHandler将在通道变为活动状态时开始计数,而不是等待写入开始,因此如果处理时间过长(但只有在处理异步时才会触发),它将触发。

确保在使用IdleStateHandler

时捕获并响应用户事件
@Override
public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception {
    if (evt == IdleStateEvent.FIRST_WRITER_IDLE_STATE_EVENT) {
        // Handle the event here
    }
    else {
        super.userEventTriggered(ctx, evt);
    }
}