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:
An event loop of type NioEventLoopGroup
(i.e. a pool of shared threads that should not be subjected to blocking operations).
A channel of type NioServerSocketChannel
(I believe this is required to correspond with #1 above).
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?
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.
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.
when you use netty as client, use f.channel(). closeFuture(). sync() ,but when you use it as server, you should use f.channel(). close().
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.
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());
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With