You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by gn...@apache.org on 2020/03/27 17:31:51 UTC

[camel] 01/02: Fix the lifecycle for services added with early start

This is an automated email from the ASF dual-hosted git repository.

gnodet pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/camel.git

commit aa6a4f590f5a29fa92ddadd1b7f14d7f5b22a70b
Author: Guillaume Nodet <gn...@gmail.com>
AuthorDate: Fri Mar 27 18:31:02 2020 +0100

    Fix the lifecycle for services added with early start
---
 .../org/apache/camel/ExtendedStartupListener.java  | 11 ---------
 .../java/org/apache/camel/StartupListener.java     | 27 ++++++++++++++++++++++
 .../camel/impl/engine/AbstractCamelContext.java    | 25 ++++++++++++++------
 .../impl/engine/DeferServiceStartupListener.java   | 18 +++++++++++++--
 4 files changed, 61 insertions(+), 20 deletions(-)

diff --git a/core/camel-api/src/main/java/org/apache/camel/ExtendedStartupListener.java b/core/camel-api/src/main/java/org/apache/camel/ExtendedStartupListener.java
index 941bd9e..6ec1942 100644
--- a/core/camel-api/src/main/java/org/apache/camel/ExtendedStartupListener.java
+++ b/core/camel-api/src/main/java/org/apache/camel/ExtendedStartupListener.java
@@ -25,15 +25,4 @@ package org.apache.camel;
  */
 public interface ExtendedStartupListener extends StartupListener {
 
-    /**
-     * Callback invoked when the {@link CamelContext} has been fully started.
-     *
-     * @param context        the Camel context
-     * @param alreadyStarted whether or not the {@link CamelContext} already has been started. For example the context
-     *                       could already have been started, and then a service is added/started later which still
-     *                       triggers this callback to be invoked.
-     * @throws Exception     can be thrown in case of errors to fail the startup process and have the application
-     *                       fail on startup.
-     */
-    void onCamelContextFullyStarted(CamelContext context, boolean alreadyStarted) throws Exception;
 }
diff --git a/core/camel-api/src/main/java/org/apache/camel/StartupListener.java b/core/camel-api/src/main/java/org/apache/camel/StartupListener.java
index d7efbe3..6aeebd2 100644
--- a/core/camel-api/src/main/java/org/apache/camel/StartupListener.java
+++ b/core/camel-api/src/main/java/org/apache/camel/StartupListener.java
@@ -42,6 +42,19 @@ package org.apache.camel;
 public interface StartupListener {
 
     /**
+     * Callback invoked when the {@link CamelContext} is being started.
+     *
+     * @param context        the Camel context
+     * @param alreadyStarted whether or not the {@link CamelContext} already has been started. For example the context
+     *                       could already have been started, and then a service is added/started later which still
+     *                       triggers this callback to be invoked.
+     * @throws Exception     can be thrown in case of errors to fail the startup process and have the application
+     *                       fail on startup.
+     */
+    default void onCamelContextStarting(CamelContext context, boolean alreadyStarted) throws Exception {
+    }
+
+    /**
      * Callback invoked when the {@link CamelContext} is about to be fully started (not started yet).
      * Yes we are aware of the method name, but we can all have a bad-naming day.
      *
@@ -53,4 +66,18 @@ public interface StartupListener {
      *                       fail on startup.
      */
     void onCamelContextStarted(CamelContext context, boolean alreadyStarted) throws Exception;
+
+    /**
+     * Callback invoked when the {@link CamelContext} has been fully started.
+     *
+     * @param context        the Camel context
+     * @param alreadyStarted whether or not the {@link CamelContext} already has been started. For example the context
+     *                       could already have been started, and then a service is added/started later which still
+     *                       triggers this callback to be invoked.
+     * @throws Exception     can be thrown in case of errors to fail the startup process and have the application
+     *                       fail on startup.
+     */
+    default void onCamelContextFullyStarted(CamelContext context, boolean alreadyStarted) throws Exception {
+    }
+
 }
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
index e6cabb6..83b6b0a 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/AbstractCamelContext.java
@@ -1480,6 +1480,7 @@ public abstract class AbstractCamelContext extends BaseService
                     ServiceHelper.startService(service);
                 } else {
                     ServiceHelper.initService(service);
+                    deferStartService(object, stopOnShutdown, true);
                 }
             }
         }
@@ -1543,6 +1544,10 @@ public abstract class AbstractCamelContext extends BaseService
 
     @Override
     public void deferStartService(Object object, boolean stopOnShutdown) throws Exception {
+        deferStartService(object, stopOnShutdown, false);
+    }
+
+    public void deferStartService(Object object, boolean stopOnShutdown, boolean startEarly) throws Exception {
         if (object instanceof Service) {
             Service service = (Service)object;
 
@@ -1564,7 +1569,7 @@ public abstract class AbstractCamelContext extends BaseService
             if (isStarted()) {
                 ServiceHelper.startService(service);
             } else {
-                deferStartupListener.addService(service);
+                deferStartupListener.addService(service, startEarly);
             }
         }
     }
@@ -2463,12 +2468,10 @@ public abstract class AbstractCamelContext extends BaseService
 
         // now call the startup listeners where the routes has been started
         for (StartupListener startup : startupListeners) {
-            if (startup instanceof ExtendedStartupListener) {
-                try {
-                    ((ExtendedStartupListener)startup).onCamelContextFullyStarted(this, isStarted());
-                } catch (Exception e) {
-                    throw RuntimeCamelException.wrapRuntimeException(e);
-                }
+            try {
+                startup.onCamelContextFullyStarted(this, isStarted());
+            } catch (Exception e) {
+                throw RuntimeCamelException.wrapRuntimeException(e);
             }
         }
     }
@@ -2717,6 +2720,14 @@ public abstract class AbstractCamelContext extends BaseService
             }
         }
 
+        // sort the startup listeners so they are started in the right order
+        startupListeners.sort(OrderedComparator.get());
+        // now call the startup listeners where the routes has been warmed up
+        // (only the actual route consumer has not yet been started)
+        for (StartupListener startup : startupListeners) {
+            startup.onCamelContextStarting(getCamelContextReference(), isStarted());
+        }
+
         // start notifiers as services
         for (EventNotifier notifier : getManagementStrategy().getEventNotifiers()) {
             if (notifier instanceof Service) {
diff --git a/core/camel-base/src/main/java/org/apache/camel/impl/engine/DeferServiceStartupListener.java b/core/camel-base/src/main/java/org/apache/camel/impl/engine/DeferServiceStartupListener.java
index 483bb84..8e8e109 100644
--- a/core/camel-base/src/main/java/org/apache/camel/impl/engine/DeferServiceStartupListener.java
+++ b/core/camel-base/src/main/java/org/apache/camel/impl/engine/DeferServiceStartupListener.java
@@ -33,14 +33,28 @@ import org.apache.camel.support.service.ServiceHelper;
  */
 public class DeferServiceStartupListener implements StartupListener, Ordered {
 
+    private final Set<Service> earlyServices = new CopyOnWriteArraySet<>();
     private final Set<Service> services = new CopyOnWriteArraySet<>();
 
-    public void addService(Service service) {
-        services.add(service);
+    public void addService(Service service, boolean startEarly) {
+        if (startEarly) {
+            earlyServices.add(service);
+        } else {
+            services.add(service);
+        }
+    }
+
+    @Override
+    public void onCamelContextStarting(CamelContext context, boolean alreadyStarted) throws Exception {
+        doStart(earlyServices, context, alreadyStarted);
     }
 
     @Override
     public void onCamelContextStarted(CamelContext context, boolean alreadyStarted) throws Exception {
+        doStart(services, context, alreadyStarted);
+    }
+
+    protected void doStart(Set<Service> services, CamelContext context, boolean alreadyStarted) throws Exception {
         // new services may be added while starting a service
         // so use a while loop to get the newly added services as well
         while (!services.isEmpty()) {