I am using Undertow to create a simple application.
public class App {
public static void main(String[] args) {
Undertow server = Undertow.builder().addListener(8080, "localhost")
.setHandler(new HttpHandler() {
public void handleRequest(HttpServerExchange exchange) throws Exception {
Thread.sleep(5000);
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain");
exchange.getResponseSender().send("Hello World");
}
}).build();
server.start();
}
}
I open a browser tab on localhost:8080 and I open a second
tab also on localhost:8080
This time the first tab will wait 5 seconds, and the second will wait 10 seconds
Why is it so?
The HttpHandler is executing in an I/O thread. As noted in the documentation:
IO threads perform non blocking tasks, and should never perform blocking operations because they are responsible for multiple connections, so while the operation is blocking other connections will essentially hang. One IO thread per CPU core is a reasonable default.
The request lifecycle docs discuss how to dispatch a request to a worker thread:
import io.undertow.Undertow;
import io.undertow.server.*;
import io.undertow.util.Headers;
public class Under {
public static void main(String[] args) {
Undertow server = Undertow.builder()
.addListener(8080, "localhost")
.setHandler(new HttpHandler() {
public void handleRequest(HttpServerExchange exchange)
throws Exception {
if (exchange.isInIoThread()) {
exchange.dispatch(this);
return;
}
exchange.getResponseHeaders()
.put(Headers.CONTENT_TYPE, "text/plain");
exchange.getResponseSender()
.send("Hello World");
}
})
.build();
server.start();
}
}
I noted that you won't necessarily get one worker thread per request - when I set a breakpoint on the header put I got about one thread per client. There are gaps in both the Undertow and the underlying XNIO docs so I'm not sure what the intention is.
Undertow uses NIO, which means that a single thread handles all the requests. If you want to do blocking operations in your request handler, you have to dispatch this operation to a worker thread.
In your example, you put the thread to sleep, which means tha any request handling is put to sleep, since this thread handles all requests.
However even if you dispatched the operation to worker thread and put that to sleep, you still would see the blocking issue you mention. This is because you open the same url in several tabs on the same browser. The browsers have an internal blocking of their own. If you open the same url in different tabs, the second url will start the request after the first has finished. Try any url you want to see for yourself. You can easily be confused with this browser behaviour.
The easiest thing to do would be to wrap your handler in a BlockingHandler.
import io.undertow.Undertow;
import io.undertow.server.*;
import io.undertow.server.handlers.BlockingHandler;
import io.undertow.util.Headers;
public class Under {
public static void main(String[] args) {
Undertow server = Undertow.builder()
.addHttpListener(8080, "localhost")
.setHandler(new BlockingHandler(new HttpHandler() {
public void handleRequest(HttpServerExchange exchange)
throws Exception {
exchange.getResponseHeaders()
.put(Headers.CONTENT_TYPE, "text/plain");
exchange.getResponseSender()
.send("Hello World");
}
})).build();
server.start();
}
}
Related
I need to create a RMI service which can notify events to clients.
Each client register itself on the server, the client can emit an event and the server will broadcast it to all other clients.
The program works, but, the client reference on the server is never garbage collected, an the thread which the server uses to check if the client reference will never terminate.
So each time a client connects to the server, a new thread is created and never terminated.
The Notifier class can register and unregister a listener.
The broadcast method call each registered listener and send the message back.
public class Notifier extends UnicastRemoteObject implements INotifier{
private List<IListener> listeners = Collections.synchronizedList(new ArrayList());
public Notifier() throws RemoteException {
super();
}
#Override
public void register(IListener listener) throws RemoteException{
listeners.add(listener);
}
#Override
public void unregister(IListener listener) throws RemoteException{
boolean remove = listeners.remove(listener);
if(remove) {
System.out.println(listener+" removed");
} else {
System.out.println(listener+" NOT removed");
}
}
#Override
public void broadcast(String msg) throws RemoteException {
for (IListener listener : listeners) {
try {
listener.onMessage(msg);
} catch (RemoteException e) {
e.printStackTrace();
}
}
}
}
The listener is just printing each received message.
public class ListenerImpl extends UnicastRemoteObject implements IListener {
public ListenerImpl() throws RemoteException {
super();
}
#Override
public void onMessage(String msg) throws RemoteException{
System.out.println("Received: "+msg);
}
}
The RunListener client subscribes a listener wait few seconds to receive a message and then terminates.
public class RunListener {
public static void main(String[] args) throws Exception {
Registry registry = LocateRegistry.getRegistry();
INotifier notifier = (INotifier) registry.lookup("Notifier");
ListenerImpl listener = new ListenerImpl();
notifier.register(listener);
Thread.sleep(6000);
notifier.unregister(listener);
UnicastRemoteObject.unexportObject(listener, true);
}
}
The RunNotifier just publish the service and periodically sends a message.
public class RunNotifier {
static AtomicInteger counter = new AtomicInteger();
public static void main(String[] args) throws RemoteException, AlreadyBoundException, NotBoundException {
Registry registry = LocateRegistry.createRegistry(1099);
INotifier notifier = new Notifier();
registry.bind("Notifier", notifier);
ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
executor.scheduleAtFixedRate(new Runnable() {
#Override
public void run() {
try {
int n = counter.incrementAndGet();
System.out.println("Broadcasting "+n);
notifier.broadcast("Hello ("+n+ ")");
} catch (RemoteException e) {
e.printStackTrace();
}
}
},5 , 5, TimeUnit.SECONDS);
try {
System.in.read();
} catch (IOException e) {
}
executor.shutdown();
registry.unbind("Notifier");
UnicastRemoteObject.unexportObject(notifier, true);
}
}
I've seen many Q&A on stack overflow about RMI, but none addresses this kind of problem.
I guess I'm doing some very big mistake, but I can't spot it.
As you can see in the picture, a new RMI RenewClean thread is created for each incoming connection, and this thread will never terminate.
Once the client disconnects, and terminates, the RenewClean thread will silently swallow all ConnectionException thrown and will keep polling a client which will never reply.
As a side note, I even tried to keep just weak reference of the IListener in the Notifier class, and still the results are the same.
This may not be very helpful if you are stuck on JDK1.8, but when I test on JDK17 the multiple rmi server threads created for each incoming client RMI RenewClean-[IPADDRESS:PORT] are cleaned up on the server, and not showing "will never terminate" behaviour you may have observed on JDK1.8. It may be a JDK1.8 issue, or simply that you are not waiting long enough for the threads to end.
For quicker cleanup, try adjusting the system property for client thread garbage collection setting from the default (3600000 = 1 hour):
java -Dsun.rmi.dgc.client.gcInterval=3600000 ...
On my server I added this in one of the API callbacks:
Function<Thread,String> toString = t -> t.getName()+(t.isDaemon() ? " DAEMON" :"");
Set<Thread> threads = Thread.getAllStackTraces().keySet();
System.out.println("-".repeat(40)+" Threads x "+threads.size());
threads.stream().map(toString).forEach(System.out::println);
After RMI server startup it printed names of threads and no instances of "RMI RenewClean":
---------------------------------------- Threads x 12
After connecting many times from a client, the server reported corresponding instances of "RMI RenewClean":
---------------------------------------- Threads x 81
Leaving the RMI server for a while, these gradually shrank back - not to 12 threads -, but low enough to suggest that RMI thread handling is not filling up with many unnecessary daemon threads:
---------------------------------------- Threads x 20
After about an hour all the remaining "RMI RenewClean" were removed - probably due to housekeeping performed at the interval defined by the VM setting sun.rmi.dgc.client.gcInterval=3600000:
---------------------------------------- Threads x 13
Note also that RMI server shutdown is instant at any point - the "RMI RenewClean" daemon threads do not hold up rmi server shutdown.
As described in a separate question, when using Undertow, all the processing should be done in a dedicated Worker thread pool, which looks like this:
public class Start {
public static void main(String[] args) {
Undertow server = Undertow.builder()
.addListener(8080, "localhost")
.setHandler(new HttpHandler() {
public void handleRequest(HttpServerExchange exchange)
throws Exception {
if (exchange.isInIoThread()) {
exchange.dispatch(this);
return;
}
exchange.getResponseHeaders()
.put(Headers.CONTENT_TYPE, "text/plain");
exchange.getResponseSender()
.send("Hello World");
}
})
.build();
server.start();
}
}
I understand that BlockingHandler can be used for explicitly telling Undertow to schedule the request on a dedicated thread pool for blocking requests. We could adapt the above example by wrapping the HttpHandler in an instance of BlockingHandler, like so:
.setHandler(new BlockingHandler(new HttpHandler() {
This would work for calls that we know are always blocking.
However, in case some code is non-blocking most of the time, but sometimes requires a blocking call, how to turn that blocking call into a non-blocking one? For example, if the requested value is present in cache, the following code would not block (it's just fetching from some Map<>), but if it's not, it has to be fetched from the database.
public class Start {
public static void main(String[] args) {
Undertow server = Undertow.builder()
.addListener(8080, "localhost")
.setHandler(new HttpHandler() {
public void handleRequest(HttpServerExchange exchange)
throws Exception {
if (exchange.isInIoThread()) {
exchange.dispatch(this);
return;
}
if (valueIsPresentInCache(exchange)) {
return valueFromCache; // non-blocking
} else {
return fetchValueFromDatabase(); // blocking!!!
}
}
})
.build();
server.start();
}
}
According to the docs, there is a method HttpServerExchange.startBlocking(), but according to JavaDoc, unless you really need to use the input stream, this call is still a blocking one.
Calling this method puts the exchange in blocking mode, and creates a
BlockingHttpExchange object to store the streams. When an exchange is
in blocking mode the input stream methods become available, other than
that there is presently no major difference between blocking an
non-blocking modes
How would one turn this blocking call into a non-blocking one?
The correct way is to actually do the logic in the IO thread, if it is non-blocking. Otherwise, delegate the request to a dedicated thread, like this:
public class Example {
public static void main(String[] args) {
Undertow server = Undertow.builder()
.addListener(8080, "localhost")
.setHandler(new HttpHandler() {
public void handleRequest(HttpServerExchange exchange)
throws Exception {
if (valueIsPresentInCache(exchange)) {
getValueFromCache(); // non-blocking, can be done from IO thread
} else {
if (exchange.isInIoThread()) {
exchange.dispatch(this);
// we return immediately, otherwise this request will be
// handled both in IO thread and a Worker thread, throwing
// an exception
return;
}
fetchValueFromDatabase(); // blocking!!!
}
}
})
.build();
server.start();
}
}
I am in the middle of learning Netty an started some tutorials using spring boot. My goal is to create an application which set up a tcp port for receiving messages and to present them over a rest api.
Most of the tutorials are saying that I should add something like this
serverChannel = serverBootstrap.bind(tcpPort).sync().channel().closeFuture().sync().channel();
to start netty.
When I do that, the rest services which I implemented are not working.
Now when I use the following code snippet to start the application:
serverChannel = serverBootstrap.bind(tcpPort).sync().channel();
everything seems to be working just fine.
Could someone explain me what might cause this issue?
Thanks
The first part start the server,
1) binding it on a TCP port,
2) wait for the server to be ready (socket is listening)
3) and return the associated channel.
serverBootstrap.bind(tcpPort).sync().channel();
(1) (2) (3)
The second part is to wait for the main channel (listening socket) to shutdown (closeFuture().sync()) where closeFuture gives you the "future" on "close" operation (meaning shutdown of the server socket), and sync waiting for this future to be done. channel() gives you back the very same channel than first time, except it is now closed.
So you might find this code in various example because generally you start the server (bind) in the main thread or so, and then if you don't wait for something, the main thread will end up, giving your JVM finishing, and therefore your server to stop immediately after starting.
So in general, what we do is:
start the server
add in the pipeline the necessary handlers to handle your business logic (and the network protocol of course)
then finish your main by waiting on closeFuture, such that, once in your business logic you get the order to shutdown, you close the main channel, and therefore your main thread is closing too.
See for instance Shutdown netty programmatically
Old, but I had same issue with my RestController not starting. Other answer helped solve it for me but here is full code for the Spring component.
import com.myserver.netty.handler.ClientInboundHandler;
import com.myserver.netty.handler.PacketDecoder;
import com.myserver.netty.handler.PacketEncoder;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
#Component
#Log4j2
public class NettyServer {
private EventLoopGroup masters = new NioEventLoopGroup();
private EventLoopGroup workers = new NioEventLoopGroup();
private Channel mainChannel;
#PostConstruct
public void start() {
try {
ServerBootstrap bootstrap = init();
mainChannel = bootstrap.bind(8484).sync().channel(); // save the main channel so we can cleanly close it when app is shutdown
log.info("Netty Server started......");
} catch (Exception e) {
e.printStackTrace();
}
}
#PreDestroy
public void stop() throws InterruptedException {
log.info("Shutting down netty server");
workers.shutdownGracefully().sync();
masters.shutdownGracefully().sync();
mainChannel.closeFuture().sync();
log.info("Shutdown complete");
}
private ServerBootstrap init() {
return new ServerBootstrap()
.group(masters, workers)
.channel(NioServerSocketChannel.class)
.option(ChannelOption.SO_BACKLOG, 5000)
.option(ChannelOption.TCP_NODELAY, true)
.option(ChannelOption.SO_KEEPALIVE, true)
.childHandler(new ChannelInitializer<SocketChannel>() {
#Override
protected void initChannel(SocketChannel channel) throws Exception {
channel.pipeline()
.addLast(new PacketDecoder())
.addLast(new ClientInboundHandler())
.addLast(new PacketEncoder());
}
});
}
}
I have the following code in my main application:
package acast;
import java.net.SocketException;
import java.util.concurrent.ConcurrentLinkedQueue;
public class ACast {
private ConcurrentLinkedQueue<String> queue;
public ACast() throws SocketException{
queue = new ConcurrentLinkedQueue<String>();
UDPServer srv = new UDPServer(4321);
srv.addUDPacketListener(new UDPPacketListener() {
#Override
public void onPacketReceived(String packet) {
ACast.this.queue.offer(packet);
}
});
srv.start();
}
public static void main(String[] args) throws SocketException {
try{
new ACast();
}
catch(SocketException e){
//e.printStackTrace();
System.out.println("Socket allready opened. Can't start application");
System.exit(1);
}
}
}
My UDPServer extends Thread and calls onPacketReceived every time it receives an UDP datagram. I want my main app to do something every time a configured timeout passes since the last received datagram. I would like to avoid running a Thread that just checks the timeout from second to second. I would like to start a countdown thread exactly on the moment of the last received datagram and cancel any other ongoing timeout threads if available. Any help ?
A simple solution would be to start a Timer with the timeout task, and every time a new datagram is received, cancel the currently running timer and start a new one.
I would lose the asynchronicity altogether, and use blocking I/O with a read timeout.
Looking at the code block in the Java library AsyncHttpClient, the client starts a new thread (a Future) to make the request. Will the callback happen on the same thread, or will it run on the "main" thread (in this case, the thread where new AsyncHttpClient() was called?
import com.ning.http.client.*;
import java.util.concurrent.Future;
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
asyncHttpClient.prepareGet("http://www.ning.com/ ").execute(new AsyncCompletionHandler<Response>(){
#Override
public Response onCompleted(Response response) throws Exception{
// Do something with the Response
// ...
return response;
}
#Override
public void onThrowable(Throwable t){
// Something wrong happened.
}
});
the client starts a new thread (a Future) to make the request.
Nope. The Future basically means: this method already returned but it didn't yet finished processing. The processing will continue in background (in some other thread you have no control over) and will finish some time in the future. You can ask this Future object to see whether the future already came or not (processing is done). You are not creating any thread yourself.
Think about ExecutorService. You are submitting some task to be done and waiting for a result. But instead of blocking, you get a Future which will give you back the result as soon as your submitted task reaches the thread pool and is processed.
Will the callback happen on the same thread, or will it run on the "main" thread
Neither. Your thread (the one that called AsyncHttpClient.execute()), by the time the response came back, is most likely doing something completely different. Maybe it serves another client or is already dead. You cannot just call arbitrary code on behalf of some thread.
In fact, this piece of code will be executed by internal NIO thread created by AsyncHttpClient library. You have absolutely no control over this thread. But you have to remember that this will happen asynchronously, so synchronization or some locking might be required if you access global objects.
You can check that by that piece of code:
import java.io.IOException;
import com.ning.http.client.AsyncCompletionHandler;
import com.ning.http.client.AsyncHttpClient;
import com.ning.http.client.Response;
public class Asink {
public static void main(String... args) throws IOException {
AsyncHttpClient asyncHttpClient = new AsyncHttpClient();
asyncHttpClient.prepareGet("http://www.google.com/").execute(
new AsyncCompletionHandler<Response>() {
#Override
public Response onCompleted(Response response)
throws Exception {
// Do something with the Response
// ...
String threadName = Thread.currentThread().getName();
System.out.println(threadName);
return response;
}
#Override
public void onThrowable(Throwable t) {
// Something wrong happened.
}
});
}
}