Named Plan ExecutorService pools, Fixed WebServer thread leak on reload

WebServer ThreadPoolExecutor was never shutdown, as it was assumed
HTTPServer.shutdown() would perform that.
In extreme cases 250 reloads could lead to a OutOfMemoryException due to
Heap size allocation for threads not being possible.

Change: Shut down ThreadPoolExecutor manually.
This commit is contained in:
Rsl1122 2018-09-15 10:38:05 +03:00
parent f846bd5b0e
commit 3ae0855ef5
2 changed files with 25 additions and 7 deletions

View File

@ -9,6 +9,7 @@ import com.djrapitops.plan.system.locale.lang.PluginLang;
import com.djrapitops.plugin.StaticHolder; import com.djrapitops.plugin.StaticHolder;
import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.api.utility.log.Log;
import com.djrapitops.plugin.utilities.Verify; import com.djrapitops.plugin.utilities.Verify;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.util.List; import java.util.List;
import java.util.concurrent.*; import java.util.concurrent.*;
@ -23,8 +24,8 @@ public class Processing implements SubSystem {
public Processing(Supplier<Locale> locale) { public Processing(Supplier<Locale> locale) {
this.locale = locale; this.locale = locale;
nonCriticalExecutor = Executors.newFixedThreadPool(6); nonCriticalExecutor = Executors.newFixedThreadPool(6, new ThreadFactoryBuilder().setNameFormat("Plan Non critical-pool-%d").build());
criticalExecutor = Executors.newFixedThreadPool(2); criticalExecutor = Executors.newFixedThreadPool(2, new ThreadFactoryBuilder().setNameFormat("Plan Critical-pool-%d").build());
saveInstance(nonCriticalExecutor); saveInstance(nonCriticalExecutor);
saveInstance(criticalExecutor); saveInstance(criticalExecutor);
saveInstance(this); saveInstance(this);

View File

@ -12,6 +12,7 @@ import com.djrapitops.plugin.StaticHolder;
import com.djrapitops.plugin.api.Check; import com.djrapitops.plugin.api.Check;
import com.djrapitops.plugin.api.utility.log.Log; import com.djrapitops.plugin.api.utility.log.Log;
import com.djrapitops.plugin.utilities.Verify; import com.djrapitops.plugin.utilities.Verify;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.sun.net.httpserver.HttpServer; import com.sun.net.httpserver.HttpServer;
import com.sun.net.httpserver.HttpsConfigurator; import com.sun.net.httpserver.HttpsConfigurator;
import com.sun.net.httpserver.HttpsParameters; import com.sun.net.httpserver.HttpsParameters;
@ -27,9 +28,7 @@ import java.nio.file.Paths;
import java.security.*; import java.security.*;
import java.security.cert.Certificate; import java.security.cert.Certificate;
import java.security.cert.CertificateException; import java.security.cert.CertificateException;
import java.util.concurrent.ArrayBlockingQueue; import java.util.concurrent.*;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier; import java.util.function.Supplier;
/** /**
@ -108,7 +107,11 @@ public class WebServer implements SubSystem {
} }
server.createContext("/", requestHandler); server.createContext("/", requestHandler);
server.setExecutor(new ThreadPoolExecutor(4, 8, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100))); ExecutorService executor = new ThreadPoolExecutor(
4, 8, 30, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100),
new ThreadFactoryBuilder().setNameFormat("Plan WebServer Thread-%d").build()
);
server.setExecutor(executor);
server.start(); server.start();
enabled = true; enabled = true;
@ -199,12 +202,26 @@ public class WebServer implements SubSystem {
@Override @Override
public void disable() { public void disable() {
if (server != null) { if (server != null) {
shutdown();
Log.info(locale.get().getString(PluginLang.DISABLED_WEB_SERVER)); Log.info(locale.get().getString(PluginLang.DISABLED_WEB_SERVER));
server.stop(0);
} }
enabled = false; enabled = false;
} }
private void shutdown() {
server.stop(0);
Executor executor = server.getExecutor();
if (executor instanceof ExecutorService) {
ExecutorService service = (ExecutorService) executor;
service.shutdown();
try {
service.awaitTermination(5, TimeUnit.SECONDS);
} catch (InterruptedException timeoutExceededEx) {
service.shutdownNow();
}
}
}
public String getProtocol() { public String getProtocol() {
return usingHttps ? "https" : "http"; return usingHttps ? "https" : "http";
} }