Restart BP container after dependency wait time out 20/42320/3
authorTom Pantelis <tpanteli@brocade.com>
Fri, 22 Jul 2016 04:11:44 +0000 (00:11 -0400)
committerTom Pantelis <tpanteli@brocade.com>
Mon, 25 Jul 2016 01:25:36 +0000 (01:25 +0000)
The blueprint container first waits for all dependencies (ie OSGi
services, clustered app config etc). By default it waits 5 min after
which it fails the container. For a missing OSGi service this is
probably OK but it could take longer for a clustered-app-config if the
data store isn't available. Ideally we would use an infinite timeout but
unfortunately the timeout can't be configured globally - it can only be set
at the bundle level in the manifest and we don't want to have to
configure it in every bundle (although it may be possible with some maven
magic in odlparent). Therefore I added code in BlueprintBundleTracker to
listen for container FAILURE events and restart the container if it's
due to missing dependencies.

Change-Id: Ib8ebb1a02dfd601e48722f9fc3011df7391432cb
Signed-off-by: Tom Pantelis <tpanteli@brocade.com>
opendaylight/blueprint/src/main/java/org/opendaylight/controller/blueprint/BlueprintBundleTracker.java
opendaylight/blueprint/src/main/java/org/opendaylight/controller/blueprint/BlueprintContainerRestartServiceImpl.java

index 6781b65..218f1d1 100644 (file)
@@ -121,7 +121,8 @@ public class BlueprintBundleTracker implements BundleActivator, BundleTrackerCus
 
     private void registerBlueprintEventHandler(BundleContext context) {
         Dictionary<String, Object> props = new Hashtable<>();
-        props.put(org.osgi.service.event.EventConstants.EVENT_TOPIC, EventConstants.TOPIC_CREATED);
+        props.put(org.osgi.service.event.EventConstants.EVENT_TOPIC,
+                new String[]{EventConstants.TOPIC_CREATED, EventConstants.TOPIC_FAILURE});
         eventHandlerReg = context.registerService(EventHandler.class.getName(), this, props);
     }
 
@@ -197,6 +198,22 @@ public class BlueprintBundleTracker implements BundleActivator, BundleTrackerCus
         if(EventConstants.TOPIC_CREATED.equals(event.getTopic())) {
             LOG.info("Blueprint container for bundle {} was successfully created",
                     event.getProperty(EventConstants.BUNDLE));
+        } else if(EventConstants.TOPIC_FAILURE.equals(event.getTopic())) {
+            // If the container timed out waiting for dependencies, we'll destroy it and start it again. This
+            // is indicated via a non-null DEPENDENCIES property containing the missing dependencies. The
+            // default timeout is 5 min and ideally we would set this to infinite but the timeout can only
+            // be set at the bundle level in the manifest - there's no way to set it globally.
+            if(event.getProperty(EventConstants.DEPENDENCIES) != null) {
+                Bundle bundle = (Bundle) event.getProperty(EventConstants.BUNDLE);
+
+                List<Object> paths = findBlueprintPaths(bundle);
+                if(!paths.isEmpty()) {
+                    LOG.warn("Blueprint container for bundle {} timed out waiting for dependencies - restarting it",
+                            event.getProperty(EventConstants.BUNDLE));
+
+                    restartService.restartContainer(bundle, paths);
+                }
+            }
         }
     }
 
index e70fc37..02b7bac 100644 (file)
@@ -75,6 +75,22 @@ class BlueprintContainerRestartServiceImpl implements AutoCloseable, BlueprintCo
         this.blueprintExtenderService = blueprintExtenderService;
     }
 
+    public void restartContainer(final Bundle bundle, final List<Object> paths) {
+        if(restartExecutor.isShutdown()) {
+            return;
+        }
+
+        LOG.debug("restartContainer for bundle {}", bundle);
+
+        restartExecutor.execute(new Runnable() {
+            @Override
+            public void run() {
+                blueprintExtenderService.destroyContainer(bundle, blueprintExtenderService.getContainer(bundle));
+                blueprintExtenderService.createContainer(bundle, paths);
+            }
+        });
+    }
+
     @Override
     public void restartContainerAndDependents(final Bundle bundle) {
         if(restartExecutor.isShutdown()) {