diff options
author | Jon Marius Venstad <venstad@gmail.com> | 2020-08-21 17:41:51 +0200 |
---|---|---|
committer | Jon Marius Venstad <venstad@gmail.com> | 2020-08-21 17:41:51 +0200 |
commit | dbcc9107e3ae49e61270e002e241d9a07864facd (patch) | |
tree | 761f8a8199bdfb4475324c9c080181eebdb2a07e | |
parent | 67e528443cca68cc527e50c2714ad1717563c458 (diff) |
Call deconstruct in reverse dependency order
4 files changed, 41 insertions, 4 deletions
diff --git a/component/src/main/java/com/yahoo/component/AbstractComponent.java b/component/src/main/java/com/yahoo/component/AbstractComponent.java index 7fc828becb5..163a2b0b7ef 100644 --- a/component/src/main/java/com/yahoo/component/AbstractComponent.java +++ b/component/src/main/java/com/yahoo/component/AbstractComponent.java @@ -124,7 +124,8 @@ public class AbstractComponent implements Component { * <p> * All other calls to this component is completed before this method is called. * It will only be called once. It should block while doing cleanup tasks and return when - * this class is ready for garbage collection. + * this class is ready for garbage collection. This method is called in reverse dependency order, + * so a component will be deconstructed after any other components it is injected into. * <p> * This default implementation does nothing. */ diff --git a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/ComponentGraph.java b/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/ComponentGraph.java index 2e4db01fb1b..a054ef5ffe0 100644 --- a/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/ComponentGraph.java +++ b/container-di/src/main/java/com/yahoo/container/di/componentgraph/core/ComponentGraph.java @@ -15,6 +15,8 @@ import com.yahoo.config.ConfigInstance; import com.yahoo.container.di.componentgraph.Provider; import com.yahoo.container.di.componentgraph.cycle.CycleFinder; import com.yahoo.container.di.componentgraph.cycle.Graph; + +import java.util.Collections; import java.util.logging.Level; import com.yahoo.vespa.config.ConfigKey; @@ -164,8 +166,10 @@ public class ComponentGraph { } } - public Collection<Object> allConstructedComponentsAndProviders() { - return nodes().stream().map(node -> node.constructedInstance().get()).collect(Collectors.toList()); + public List<Object> allConstructedComponentsAndProviders() { + List<Node> orderedNodes = topologicalSort(nodes()); + Collections.reverse(orderedNodes); + return orderedNodes.stream().map(node -> node.constructedInstance().get()).collect(Collectors.toList()); } private void completeComponentRegistryNode(ComponentRegistryNode registry) { diff --git a/container-di/src/test/java/com/yahoo/container/di/componentgraph/core/ComponentGraphTest.java b/container-di/src/test/java/com/yahoo/container/di/componentgraph/core/ComponentGraphTest.java index e7b269e5172..2a30d71c338 100644 --- a/container-di/src/test/java/com/yahoo/container/di/componentgraph/core/ComponentGraphTest.java +++ b/container-di/src/test/java/com/yahoo/container/di/componentgraph/core/ComponentGraphTest.java @@ -27,6 +27,7 @@ import org.junit.Test; import java.lang.annotation.Annotation; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.Executors; @@ -87,6 +88,28 @@ public class ComponentGraphTest { } @Test + public void all_created_components_are_returned_in_reverse_topological_order() { + Node innerComponent = mockComponentNode(SimpleComponent.class); + Node middleComponent = mockComponentNode(ComponentTakingComponent.class); + Node outerComponent = mockComponentNode(ComponentTakingComponentTakingComponent.class); + middleComponent.inject(innerComponent); + outerComponent.inject(innerComponent); + + ComponentGraph componentGraph = new ComponentGraph(); + componentGraph.add(innerComponent); + componentGraph.add(middleComponent); + componentGraph.add(outerComponent); + componentGraph.complete(); + + innerComponent.constructInstance(); + middleComponent.constructInstance(); + outerComponent.constructInstance(); + + assertEquals(List.of(outerComponent.constructedInstance().get(), middleComponent.constructedInstance().get(), innerComponent.constructedInstance().get()), + componentGraph.allConstructedComponentsAndProviders()); + } + + @Test public void component_can_be_injected_into_another_component() { Node injectedComponent = mockComponentNode(SimpleComponent.class); Node targetComponent = mockComponentNode(ComponentTakingComponent.class); @@ -526,6 +549,15 @@ public class ComponentGraphTest { } } + public static class ComponentTakingComponentTakingComponent extends AbstractComponent { + private final ComponentTakingComponent injectedComponent; + + public ComponentTakingComponentTakingComponent(ComponentTakingComponent injectedComponent) { + assertThat(injectedComponent, notNullValue()); + this.injectedComponent = injectedComponent; + } + } + @SuppressWarnings("unused") public static class ComponentTakingConfigAndComponent extends AbstractComponent { private final TestConfig config; diff --git a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusVisitorSession.java b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusVisitorSession.java index 69db27686f0..6203b724e95 100755 --- a/documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusVisitorSession.java +++ b/documentapi/src/main/java/com/yahoo/documentapi/messagebus/MessageBusVisitorSession.java @@ -1152,7 +1152,7 @@ public class MessageBusVisitorSession implements VisitorSession { synchronized (completionMonitor) { // If we are destroying the session before it has completed (e.g. because // waitUntilDone timed out or an interactive visiting was interrupted) - // set us to aborted state so that we'll seize sending new visitors. + // set us to aborted state so that we'll cease sending new visitors. if (!done) { transitionTo(new StateDescription(State.ABORTED, "Session explicitly destroyed before completion")); } |