diff options
author | gjoranv <gv@yahoo-inc.com> | 2017-05-18 16:03:06 +0200 |
---|---|---|
committer | gjoranv <gv@yahoo-inc.com> | 2017-05-18 16:19:15 +0200 |
commit | f692397d9af72e7992229d7e3d34975bf7dace3b (patch) | |
tree | 4c6d7cec89ad62755684196e72f613ea1f65ec7c /container-di | |
parent | a20ede3c2016d6542020651fc51733d4fbc33c63 (diff) |
Exit if the first component graph cannot be created successfully.
- Add ignored test to use for manual verification.
Diffstat (limited to 'container-di')
-rw-r--r-- | container-di/src/main/scala/com/yahoo/container/di/Container.scala | 76 | ||||
-rw-r--r-- | container-di/src/test/scala/com/yahoo/container/di/ContainerTest.scala | 16 |
2 files changed, 70 insertions, 22 deletions
diff --git a/container-di/src/main/scala/com/yahoo/container/di/Container.scala b/container-di/src/main/scala/com/yahoo/container/di/Container.scala index bc3f9fbe79e..a710e588f7f 100644 --- a/container-di/src/main/scala/com/yahoo/container/di/Container.scala +++ b/container-di/src/main/scala/com/yahoo/container/di/Container.scala @@ -1,23 +1,23 @@ // Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. package com.yahoo.container.di +import java.util.{IdentityHashMap, Random} +import java.util.logging.{Level, Logger} + +import com.google.inject.{Guice, Injector} +import com.yahoo.config._ +import com.yahoo.container.bundle.BundleInstantiationSpecification import com.yahoo.container.di.ConfigRetriever.{BootstrapConfigs, ComponentsConfigs} +import com.yahoo.container.di.Container._ +import com.yahoo.container.di.componentgraph.core.ComponentNode.ComponentConstructorException import com.yahoo.container.di.componentgraph.core.{ComponentGraph, ComponentNode, JerseyNode} import com.yahoo.container.di.config.{RestApiContext, SubscriberFactory} -import Container._ +import com.yahoo.container.{BundlesConfig, ComponentsConfig} +import com.yahoo.protect.Process +import com.yahoo.vespa.config.ConfigKey import scala.collection.JavaConversions._ import scala.math.max -import com.yahoo.config._ -import com.yahoo.vespa.config.ConfigKey -import java.util.IdentityHashMap -import java.util.logging.{Level, Logger} - -import com.yahoo.container.bundle.BundleInstantiationSpecification -import com.google.inject.{Guice, Injector} -import com.yahoo.container.di.componentgraph.core.ComponentNode.ComponentConstructorException -import com.yahoo.container.{BundlesConfig, ComponentsConfig} -import com.yahoo.log.LogLevel /** @@ -46,9 +46,9 @@ class Container( def deconstructObsoleteComponents(oldGraph: ComponentGraph, newGraph: ComponentGraph) { val oldComponents = new IdentityHashMap[AnyRef, AnyRef]() - oldGraph.allComponentsAndProviders foreach(oldComponents.put(_, null)) - newGraph.allComponentsAndProviders foreach(oldComponents.remove(_)) - oldComponents.keySet foreach(componentDeconstructor.deconstruct(_)) + oldGraph.allComponentsAndProviders foreach (oldComponents.put(_, null)) + newGraph.allComponentsAndProviders foreach (oldComponents.remove(_)) + oldComponents.keySet foreach (componentDeconstructor.deconstruct(_)) } try { @@ -58,18 +58,52 @@ class Container( deconstructObsoleteComponents(oldGraph, newGraph) newGraph } catch { - case userException : ComponentConstructorException => - invalidateGeneration("Failed to set up new component graph due to error when constructing one of the components.", userException) + case userException: ComponentConstructorException => + invalidateGeneration(oldGraph.generation, userException) throw userException - case t : Throwable => - invalidateGeneration("Failed to set up new component graph.", t) + case t: Throwable => + invalidateGeneration(oldGraph.generation, t) throw t } } - private def invalidateGeneration(message: String, cause: Throwable) { - log.log(Level.WARNING, message, cause) - leastGeneration = max(configurer.getComponentsGeneration, configurer.getBootstrapGeneration) + 1 + private def invalidateGeneration(generation: Long, cause: Throwable) { + val maxWaitToExit = 180L + + def newGraphErrorMessage(generation: Long, cause: Throwable): String = { + val exitMessage = s"Exiting within $maxWaitToExit seconds." + val retainMessage = "Retaining previous component generation." + generation match { + case 0 => + cause match { + case _: ComponentConstructorException => s"Failed to set up first component graph due to error when constructing one of the components. $exitMessage" + case _ => s"Failed to set up first component graph. $exitMessage" + } + case _ => + cause match { + case _: ComponentConstructorException => s"Failed to set up new component graph due to error when constructing one of the components. $retainMessage" + case _ => s"Failed to set up new component graph. $retainMessage" + } + } + } + + def logAndDie(message: String, cause: Throwable): Unit = { + log.log(Level.SEVERE, message) + try { + Thread.sleep((new Random(System.nanoTime).nextDouble * maxWaitToExit * 1000).toLong) + } catch { + case _: InterruptedException => // Do nothing + } + Process.logAndDie("Exited.", cause) + } + + val message = newGraphErrorMessage(generation, cause) + generation match { + case 0 => logAndDie(message, cause) + case _ => + log.log(Level.WARNING, message, cause) + leastGeneration = max(configurer.getComponentsGeneration, configurer.getBootstrapGeneration) + 1 + } } final def createNewGraph(graph: ComponentGraph = new ComponentGraph, diff --git a/container-di/src/test/scala/com/yahoo/container/di/ContainerTest.scala b/container-di/src/test/scala/com/yahoo/container/di/ContainerTest.scala index 31c0f787269..d8f3d0fc2ab 100644 --- a/container-di/src/test/scala/com/yahoo/container/di/ContainerTest.scala +++ b/container-di/src/test/scala/com/yahoo/container/di/ContainerTest.scala @@ -4,7 +4,7 @@ package com.yahoo.container.di import com.yahoo.container.di.componentgraph.core.ComponentGraphTest.{SimpleComponent, SimpleComponent2} import com.yahoo.container.di.componentgraph.Provider import com.yahoo.container.di.componentgraph.core.{ComponentGraph, Node} -import org.junit.{After, Before, Test} +import org.junit.{After, Before, Ignore, Test} import org.junit.Assert._ import org.hamcrest.CoreMatchers._ import com.yahoo.config.test.TestConfig @@ -118,6 +118,20 @@ class ContainerTest { assertTrue(componentToDestruct.deconstructed) } + @Ignore + @Test + def manually_verify_what_happens_when_first_graph_contains_component_that_throws_exception_in_ctor() { + writeBootstrapConfigs("thrower", classOf[ComponentThrowingExceptionInConstructor]) + val container = newContainer(dirConfigSource) + var currentGraph: ComponentGraph = null + try { + currentGraph = container.runOnce() + fail("Expected to log and die.") + } catch { + case _: Throwable => fail("Expected to log and die") + } + } + @Test def previous_graph_is_retained_when_new_graph_contains_component_that_throws_exception_in_ctor() { val simpleComponentEntry = ComponentEntry("simpleComponent", classOf[SimpleComponent]) |