diff options
author | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2022-01-25 15:45:26 +0100 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@verizonmedia.com> | 2022-01-26 16:29:55 +0100 |
commit | 67eb29473e277f49a1e2a64555f33653432c8e29 (patch) | |
tree | efb649bda10da05a4936c6cce73f598f5ae485d9 /container-disc/src/main/java/com | |
parent | 2b59e93968a32b354ce637650bd8836ca6c0dbac (diff) |
Move shutdown timeout logic to separate class
Diffstat (limited to 'container-disc/src/main/java/com')
-rw-r--r-- | container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java | 38 | ||||
-rw-r--r-- | container-disc/src/main/java/com/yahoo/container/jdisc/ShutdownDeadline.java | 52 |
2 files changed, 57 insertions, 33 deletions
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java b/container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java index d686bb9a3dd..1d50686680d 100644 --- a/container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java +++ b/container-disc/src/main/java/com/yahoo/container/jdisc/ConfiguredApplication.java @@ -8,7 +8,6 @@ import com.google.inject.Injector; import com.yahoo.cloud.config.SlobroksConfig; import com.yahoo.component.Vtag; import com.yahoo.component.provider.ComponentRegistry; -import com.yahoo.concurrent.DaemonThreadFactory; import com.yahoo.config.ConfigInstance; import com.yahoo.config.subscription.ConfigInterruptedException; import com.yahoo.container.Container; @@ -43,7 +42,6 @@ import com.yahoo.log.LogSetup; import com.yahoo.messagebus.network.rpc.SlobrokConfigSubscriber; import com.yahoo.net.HostName; import com.yahoo.vespa.config.ConfigKey; -import com.yahoo.vespa.defaults.Defaults; import com.yahoo.yolean.Exceptions; import com.yahoo.yolean.UncheckedInterruptedException; @@ -56,8 +54,6 @@ import java.util.Optional; import java.util.Set; import java.util.WeakHashMap; import java.util.concurrent.CountDownLatch; -import java.util.concurrent.ScheduledThreadPoolExecutor; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.logging.Level; import java.util.logging.Logger; @@ -71,7 +67,6 @@ public final class ConfiguredApplication implements Application { private static final Logger log = Logger.getLogger(ConfiguredApplication.class.getName()); private static final Set<ClientProvider> startedClients = Collections.newSetFromMap(new WeakHashMap<>()); - static final String SANITIZE_FILENAME = "[/,;]"; private static final Set<ServerProvider> startedServers = Collections.newSetFromMap(new IdentityHashMap<>()); private final SubscriberFactory subscriberFactory; @@ -86,6 +81,7 @@ public final class ConfiguredApplication implements Application { // to config to make sure that container will be registered in slobrok (by {@link com.yahoo.jrt.slobrok.api.Register}) // if slobrok config changes (typically slobroks moving to other nodes) private final Optional<SlobrokConfigSubscriber> slobrokConfigSubscriber; + private final ShutdownDeadline shutdownDeadline; //TODO: FilterChainRepository should instead always be set up in the model. private final FilterChainRepository defaultFilterChainRepository = @@ -96,7 +92,6 @@ public final class ConfiguredApplication implements Application { new ComponentRegistry<>()); private final OsgiFramework restrictedOsgiFramework; private HandlersConfigurerDi configurer; - private ScheduledThreadPoolExecutor shutdownDeadlineExecutor; private Thread reconfigurerThread; private Thread portWatcher; private QrConfig qrConfig; @@ -136,6 +131,7 @@ public final class ConfiguredApplication implements Application { ? Optional.of(new SlobrokConfigSubscriber(configId)) : Optional.empty(); this.restrictedOsgiFramework = new DisableOsgiFramework(new RestrictedBundleContext(osgiFramework.bundleContext())); + this.shutdownDeadline = new ShutdownDeadline(configId); } @Override @@ -371,9 +367,8 @@ public final class ConfiguredApplication implements Application { @Override public void stop() { - startShutdownDeadlineExecutor(); + shutdownDeadline.schedule((long)(shutdownTimeoutS.get() * 1000), dumpHeapOnShutdownTimeout.get()); shutdownReconfigurerThread(); - log.info("Stop: Closing servers"); for (ServerProvider server : Container.get().getServerProviderRegistry().allComponents()) { if (startedServers.contains(server)) { @@ -418,31 +413,8 @@ public final class ConfiguredApplication implements Application { @Override public void destroy() { - if (shutdownDeadlineExecutor != null) { //stop() is not called when exception happens during start - shutdownDeadlineExecutor.shutdownNow(); - } - } - - static String santizeFileName(String s) { - return s.trim() - .replace('\\', '.') - .replaceAll(SANITIZE_FILENAME, "."); - } - - // Workaround for ApplicationLoader.stop not being able to shutdown - private void startShutdownDeadlineExecutor() { - shutdownDeadlineExecutor = new ScheduledThreadPoolExecutor(1, new DaemonThreadFactory("Shutdown deadline timer")); - shutdownDeadlineExecutor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); - long delayMillis = (long)(shutdownTimeoutS.get() * 1000.0); - shutdownDeadlineExecutor.schedule(() -> { - if (dumpHeapOnShutdownTimeout.get()) { - String heapDumpName = Defaults.getDefaults().underVespaHome("var/crash/java_pid.") + santizeFileName(configId) + "." + ProcessHandle.current().pid() + ".hprof"; - com.yahoo.protect.Process.dumpHeap(heapDumpName, true); - } - com.yahoo.protect.Process.logAndDie( - "Timed out waiting for application shutdown. Please check that all your request handlers " + - "drain their request content channels.", true); - }, delayMillis, TimeUnit.MILLISECONDS); + shutdownDeadline.cancel(); + log.info("Destroy: completed"); } private static void addHandlerBindings(ContainerBuilder builder, diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/ShutdownDeadline.java b/container-disc/src/main/java/com/yahoo/container/jdisc/ShutdownDeadline.java new file mode 100644 index 00000000000..15af216c210 --- /dev/null +++ b/container-disc/src/main/java/com/yahoo/container/jdisc/ShutdownDeadline.java @@ -0,0 +1,52 @@ +// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. +package com.yahoo.container.jdisc; + +import com.yahoo.concurrent.DaemonThreadFactory; +import com.yahoo.vespa.defaults.Defaults; + +import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import static com.yahoo.protect.Process.dumpHeap; +import static com.yahoo.protect.Process.logAndDie; + +/** + * Kills the JVM if the application is unable to shutdown before deadline. + * + * @author bjorncs + */ +class ShutdownDeadline implements AutoCloseable { + + private final String configId; + private final ScheduledThreadPoolExecutor executor; + + ShutdownDeadline(String configId) { + this.configId = configId; + executor = new ScheduledThreadPoolExecutor(1, new DaemonThreadFactory("Shutdown deadline timer")); + executor.setExecuteExistingDelayedTasksAfterShutdownPolicy(false); + } + + ShutdownDeadline schedule(long millis, boolean heapdumpOnShutdown) { + executor.schedule(() -> onDeadline(heapdumpOnShutdown), millis, TimeUnit.MILLISECONDS); + return this; + } + + void cancel() { executor.shutdownNow(); } + @Override public void close() { cancel(); } + + private void onDeadline(boolean heapdumpOnShutdown) { + if (heapdumpOnShutdown) dumpHeap(heapdumpFilename(), true); + logAndDie("Timed out waiting for application shutdown. Please check that all your request handlers " + + "drain their request content channels.", true); + } + + private String heapdumpFilename() { + return Defaults.getDefaults().underVespaHome("var/crash/java_pid.") + sanitizeFileName(configId) + "." + + ProcessHandle.current().pid() + ".hprof"; + } + + static String sanitizeFileName(String s) { + return s.trim().replace('\\', '.').replaceAll("[/,;]", "."); + } + +} |