fix wrong ClassLoader for Delayed-Restart Thread, which has caused an ClassLoader leak.

Also added system properties to configure shutdown only, wait between stop and start and possibility to disable gc.
This commit is contained in:
Sebastian Sdorra
2019-11-21 16:20:55 +01:00
parent 755b99f524
commit d1a5f6f24b
6 changed files with 97 additions and 25 deletions

View File

@@ -5,6 +5,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sonia.scm.event.RecreateEventBusEvent;
import sonia.scm.event.ScmEventBus;
import sonia.scm.event.ShutdownEventBusEvent;
import java.util.concurrent.atomic.AtomicLong;
@@ -13,20 +14,47 @@ import java.util.concurrent.atomic.AtomicLong;
*/
public class InjectionContextRestartStrategy implements RestartStrategy {
private static final String DISABLE_RESTART_PROPERTY = "sonia.scm.restart.disable";
private static final String WAIT_PROPERTY = "sonia.scm.restart.wait";
private static final String DISABLE_GC_PROPERTY = "sonia.scm.restart.disable-gc";
private static final AtomicLong INSTANCE_COUNTER = new AtomicLong();
private static final Logger LOG = LoggerFactory.getLogger(InjectionContextRestartStrategy.class);
private long waitInMs = 250L;
private boolean restartEnabled = !Boolean.getBoolean(DISABLE_RESTART_PROPERTY);
private long waitInMs = Integer.getInteger(WAIT_PROPERTY, 250);
private boolean gcEnabled = !Boolean.getBoolean(DISABLE_GC_PROPERTY);
private final ClassLoader webAppClassLoader;
InjectionContextRestartStrategy(ClassLoader webAppClassLoader) {
this.webAppClassLoader = webAppClassLoader;
}
@VisibleForTesting
void setWaitInMs(long waitInMs) {
this.waitInMs = waitInMs;
}
@VisibleForTesting
void setGcEnabled(boolean gcEnabled) {
this.gcEnabled = gcEnabled;
}
@Override
public void restart(InjectionContext context) {
LOG.warn("destroy injection context");
context.destroy();
stop(context);
if (restartEnabled) {
start(context);
} else {
LOG.warn("restarting context is disabled");
}
}
@SuppressWarnings("squid:S1215") // suppress explicit gc call warning
private void start(InjectionContext context) {
LOG.debug("use WebAppClassLoader as ContextClassLoader, to avoid ClassLoader leaks");
Thread.currentThread().setContextClassLoader(webAppClassLoader);
LOG.warn("send recreate eventbus event");
ScmEventBus.getInstance().post(new RecreateEventBusEvent());
@@ -34,6 +62,12 @@ public class InjectionContextRestartStrategy implements RestartStrategy {
// restart context delayed, to avoid timing problems
new Thread(() -> {
try {
if (gcEnabled){
LOG.info("call gc to clean up memory from old instances");
System.gc();
}
LOG.info("wait {}ms before re starting the context", waitInMs);
Thread.sleep(waitInMs);
LOG.warn("reinitialize injection context");
@@ -45,6 +79,15 @@ public class InjectionContextRestartStrategy implements RestartStrategy {
LOG.error("failed to restart", ex);
}
}, "Delayed-Restart-" + INSTANCE_COUNTER.incrementAndGet()).start();
}
private void stop(InjectionContext context) {
LOG.warn("destroy injection context");
context.destroy();
if (!restartEnabled) {
// shutdown eventbus, but do this only if restart is disabled
ScmEventBus.getInstance().post(new ShutdownEventBusEvent());
}
}
}