Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can you safely perform blocking operations in a Netty channel handler?

I'm building a small Netty-based application that performs I/O operations across a socket connections (i.e. telnet/ssh). I am starting up my socket server with Netty's ServerBootstrap class, giving it:

  1. An event loop of type NioEventLoopGroup (i.e. a pool of shared threads that should not be subjected to blocking operations).

  2. A channel of type NioServerSocketChannel (I believe this is required to correspond with #1 above).

  3. A very simple pipeline, with a channel handler that extends ChannelInboundHandlerAdapter.

My handler's channelRead(...) method is called whenever a command string is received from a client socket connection, and returns some response string depending on the command.

Everything is fine for the commands which involve no blocking operations. However, there are SOME commands for which I now need to read from or write to a database. Those JDBC calls are inherently going to be blocking... although I could use a CompletableFuture (or whatever) to handle them in a separate thread.

But even if I did "roll-my-own async" by performing blocking operations in separate threads, I'm not sure how I would reconnect the results from those spawned threads back to the Netty channel handler in the main thread.

I see that the ChannelHandlerContext class has methods like:

ChannelFuture writeAndFlush(Object msg, ChannelPromise promise);

... as alternatives to the ones I'm currently using:

ChannelFuture writeAndFlush(Object msg);

But I can't find any documentation or guidance (or even helpful Javadocs) explaining how one might use this ChannelPromise type in this use case. It's name suggests that it might be relevant, but it might not be. After all, the writeAndFlush method still takes the outgoing message as its first parameter... so what good would it do to stuff your blocking operation into a "promise" second parameter, if you need its result to be already on-hand for the first parameter?

What is the right track here? Is there some way to handle blocking operations in separate threads, so that Netty's NioEventLoopGroup does not block? Or is this simply not how Netty works, and you should use a different event loop implementation (i.e. one that spawns a separate thread for each client socket connection) if you need to support blocking?

like image 965
Steve Perkins Avatar asked Mar 06 '18 14:03

Steve Perkins


People also ask

What is the use of Netty handler?

Netty allows you to write your own network protocol tailored to your specific requirements, optimizing the traffic flow for your specific situation, without the unnecessary overhead of something like HTTP or FTP.

How does Netty Channel work?

Netty Channel Channel is a component providing users a ways to process I/O operations, such as read and write. A ChannelPipeline encapsulates a series of ChannelHandler instances as two-way linked list. Inbound and outbound events that flow through a channel can be intercepted by the ChannelPipeline.

How do I disable Netty server?

when you use netty as client, use f.channel(). closeFuture(). sync() ,but when you use it as server, you should use f.channel(). close().

How Netty works internally?

Netty uses an event-driven application paradigm, so the pipeline of the data processing is a chain of events going through handlers. Events and handlers can be related to the inbound and outbound data flow. Inbound events can be the following: Channel activation and deactivation.


1 Answers

If an operation in Netty takes longer time to complete or is blocking it is advisable to perform that in a handler that uses a separate ExecutorGroup so that the main EventLoop thread is not blocked.

You can specify that during the pipeline creation.

Quoting an example that uses executor group for DB operation from ChannelPipeline javadoc

static final EventExecutorGroup group = new DefaultEventExecutorGroup(16);
 ...

 ChannelPipeline pipeline = ch.pipeline();

 pipeline.addLast("decoder", new MyProtocolDecoder());
 pipeline.addLast("encoder", new MyProtocolEncoder());

 // Tell the pipeline to run MyBusinessLogicHandler's event handler methods
 // in a different thread than an I/O thread so that the I/O thread is not blocked by
 // a time-consuming task.
 // If your business logic is fully asynchronous or finished very quickly, you don't
 // need to specify a group.
 pipeline.addLast(group, "handler", new MyBusinessLogicHandler());
like image 121
Madhusudana Reddy Sunnapu Avatar answered Sep 18 '22 05:09

Madhusudana Reddy Sunnapu