summaryrefslogtreecommitdiffstats
path: root/container-disc/src/main/java/com/yahoo/container/jdisc/component/Deconstructor.java
diff options
context:
space:
mode:
Diffstat (limited to 'container-disc/src/main/java/com/yahoo/container/jdisc/component/Deconstructor.java')
-rw-r--r--container-disc/src/main/java/com/yahoo/container/jdisc/component/Deconstructor.java45
1 files changed, 40 insertions, 5 deletions
diff --git a/container-disc/src/main/java/com/yahoo/container/jdisc/component/Deconstructor.java b/container-disc/src/main/java/com/yahoo/container/jdisc/component/Deconstructor.java
index 0bb60c8aca8..47e36809a48 100644
--- a/container-disc/src/main/java/com/yahoo/container/jdisc/component/Deconstructor.java
+++ b/container-disc/src/main/java/com/yahoo/container/jdisc/component/Deconstructor.java
@@ -9,6 +9,10 @@ import com.yahoo.container.di.componentgraph.Provider;
import com.yahoo.jdisc.SharedResource;
import java.util.List;
+
+
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
@@ -35,13 +39,29 @@ public class Deconstructor implements ComponentDeconstructor {
private static final Logger log = Logger.getLogger(Deconstructor.class.getName());
+ private static final Duration SHUTDOWN_DECONSTRUCT_TIMEOUT = Duration.ofMinutes(10);
+
+ public enum Mode {
+ RECONFIG, // Delay deconstruction to allow old components to finish processing in-flight requests.
+ SHUTDOWN // The container is shutting down. Start deconstructing immediately, and wait until all components
+ // are deconstructed, to prevent shutting down while deconstruct is in progress.
+ }
+
+ // TODO: make private again
final ScheduledExecutorService executor =
- Executors.newScheduledThreadPool(1, ThreadFactoryFactory.getThreadFactory("component-deconstructor"));
+ Executors.newScheduledThreadPool(2, ThreadFactoryFactory.getThreadFactory("component-deconstructor"));
+ private final Mode mode;
private final Duration delay;
- public Deconstructor(boolean delayDeconstruction) {
- this.delay = delayDeconstruction ? Duration.ofSeconds(60) : Duration.ZERO;
+ public Deconstructor(Mode mode) {
+ this(mode, (mode == Mode.RECONFIG) ? Duration.ofSeconds(60) : Duration.ZERO);
+ }
+
+ // For testing only
+ Deconstructor(Mode mode, Duration reconfigDeconstructDelay) {
+ this.mode = mode;
+ this.delay = reconfigDeconstructDelay;
}
@Override
@@ -61,9 +81,24 @@ public class Deconstructor implements ComponentDeconstructor {
((SharedResource) component).release();
}
}
- if (! destructibleComponents.isEmpty() || ! bundles.isEmpty())
- executor.schedule(new DestructComponentTask(destructibleComponents, bundles),
+ if (!destructibleComponents.isEmpty() || !bundles.isEmpty()) {
+ var task = executor.schedule(new DestructComponentTask(destructibleComponents, bundles),
delay.getSeconds(), TimeUnit.SECONDS);
+ if (mode.equals(Mode.SHUTDOWN)) {
+ // Wait for deconstruction to finish
+ try {
+ log.info("Waiting up to " + SHUTDOWN_DECONSTRUCT_TIMEOUT.toSeconds() + " seconds for all components to deconstruct.");
+ task.get(SHUTDOWN_DECONSTRUCT_TIMEOUT.toMillis(), TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ log.info("Interrupted while waiting for component deconstruction to finish.");
+ Thread.currentThread().interrupt();
+ } catch (ExecutionException e) {
+ log.warning("Component deconstruction threw an exception: " + e.getMessage());
+ } catch (TimeoutException e) {
+ log.warning("Component deconstruction timed out.");
+ }
+ }
+ }
}
private static class DestructComponentTask implements Runnable {