[#5882] Ensure we even process tasks if processing of ready channels throws an Exception in event loop.
Motivation: If an exception is thrown while processing the ready channels in the EventLoop we should still run all tasks as this may allow to recover. For example a OutOfMemoryError may be thrown and runAllTasks() will free up memory again. Beside this we should also ensure we always allow to shutdown even if an exception was thrown. Modifications: - Call runAllTasks() in a finally block - Ensure shutdown is always handles. Result: More robust EventLoop implementations for NIO and Epoll.
This commit is contained in:
parent
3cf7ccbd3c
commit
a09e56850e
@ -291,24 +291,36 @@ final class EpollEventLoop extends SingleThreadEventLoop {
|
||||
|
||||
final int ioRatio = this.ioRatio;
|
||||
if (ioRatio == 100) {
|
||||
if (strategy > 0) {
|
||||
processReady(events, strategy);
|
||||
try {
|
||||
if (strategy > 0) {
|
||||
processReady(events, strategy);
|
||||
}
|
||||
} finally {
|
||||
// Ensure we always run tasks.
|
||||
runAllTasks();
|
||||
}
|
||||
runAllTasks();
|
||||
} else {
|
||||
final long ioStartTime = System.nanoTime();
|
||||
|
||||
if (strategy > 0) {
|
||||
processReady(events, strategy);
|
||||
try {
|
||||
if (strategy > 0) {
|
||||
processReady(events, strategy);
|
||||
}
|
||||
} finally {
|
||||
// Ensure we always run tasks.
|
||||
final long ioTime = System.nanoTime() - ioStartTime;
|
||||
runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
|
||||
}
|
||||
|
||||
final long ioTime = System.nanoTime() - ioStartTime;
|
||||
runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
|
||||
}
|
||||
if (allowGrowing && strategy == events.length()) {
|
||||
//increase the size of the array as we needed the whole space for the events
|
||||
events.increase();
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
handleLoopException(t);
|
||||
}
|
||||
// Always handle shutdown even if the loop processing threw an exception.
|
||||
try {
|
||||
if (isShuttingDown()) {
|
||||
closeAll();
|
||||
if (confirmShutdown()) {
|
||||
@ -316,19 +328,23 @@ final class EpollEventLoop extends SingleThreadEventLoop {
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger.warn("Unexpected exception in the selector loop.", t);
|
||||
|
||||
// Prevent possible consecutive immediate failures that lead to
|
||||
// excessive CPU consumption.
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// Ignore.
|
||||
}
|
||||
handleLoopException(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void handleLoopException(Throwable t) {
|
||||
logger.warn("Unexpected exception in the selector loop.", t);
|
||||
|
||||
// Prevent possible consecutive immediate failures that lead to
|
||||
// excessive CPU consumption.
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// Ignore.
|
||||
}
|
||||
}
|
||||
|
||||
private void closeAll() {
|
||||
try {
|
||||
Native.epollWait(epollFd.intValue(), events, 0);
|
||||
|
@ -438,34 +438,48 @@ public final class NioEventLoop extends SingleThreadEventLoop {
|
||||
needsToSelectAgain = false;
|
||||
final int ioRatio = this.ioRatio;
|
||||
if (ioRatio == 100) {
|
||||
processSelectedKeys();
|
||||
runAllTasks();
|
||||
try {
|
||||
processSelectedKeys();
|
||||
} finally {
|
||||
// Ensure we always run tasks.
|
||||
runAllTasks();
|
||||
}
|
||||
} else {
|
||||
final long ioStartTime = System.nanoTime();
|
||||
|
||||
processSelectedKeys();
|
||||
|
||||
final long ioTime = System.nanoTime() - ioStartTime;
|
||||
runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
|
||||
}
|
||||
|
||||
if (isShuttingDown()) {
|
||||
closeAll();
|
||||
if (confirmShutdown()) {
|
||||
break;
|
||||
try {
|
||||
processSelectedKeys();
|
||||
} finally {
|
||||
// Ensure we always run tasks.
|
||||
final long ioTime = System.nanoTime() - ioStartTime;
|
||||
runAllTasks(ioTime * (100 - ioRatio) / ioRatio);
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
logger.warn("Unexpected exception in the selector loop.", t);
|
||||
|
||||
// Prevent possible consecutive immediate failures that lead to
|
||||
// excessive CPU consumption.
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// Ignore.
|
||||
}
|
||||
handleLoopException(t);
|
||||
}
|
||||
// Always handle shutdown even if the loop processing threw an exception.
|
||||
try {
|
||||
if (isShuttingDown()) {
|
||||
closeAll();
|
||||
if (confirmShutdown()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (Throwable t) {
|
||||
handleLoopException(t);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void handleLoopException(Throwable t) {
|
||||
logger.warn("Unexpected exception in the selector loop.", t);
|
||||
|
||||
// Prevent possible consecutive immediate failures that lead to
|
||||
// excessive CPU consumption.
|
||||
try {
|
||||
Thread.sleep(1000);
|
||||
} catch (InterruptedException e) {
|
||||
// Ignore.
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user