You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2020/07/28 10:41:34 UTC
[camel] branch camel-3.4.x updated: CAMEL-15343: Fixed camel-main
to do graceful shutdown on JVM shutdown hook (eg SIGTERM or cltr+c).
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch camel-3.4.x
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-3.4.x by this push:
new c586c96 CAMEL-15343: Fixed camel-main to do graceful shutdown on JVM shutdown hook (eg SIGTERM or cltr+c).
c586c96 is described below
commit c586c96c53a66058a3bdb27a7255f2e5890d8ba9
Author: Claus Ibsen <cl...@gmail.com>
AuthorDate: Tue Jul 28 12:35:54 2020 +0200
CAMEL-15343: Fixed camel-main to do graceful shutdown on JVM shutdown hook (eg SIGTERM or cltr+c).
---
.../main/java/org/apache/camel/spring/Main.java | 17 +++++---
.../camel/main/DefaultMainShutdownStrategy.java | 50 +++++++++++++++++++++-
.../apache/camel/main/MainShutdownStrategy.java | 18 ++++++++
.../java/org/apache/camel/main/MainSupport.java | 2 +-
.../camel/main/SimpleMainShutdownStrategy.java | 20 +++++++++
.../camel/main/MainSupportCommandLineTest.java | 1 +
.../test/java/org/apache/camel/main/MainTest.java | 23 ++++++++--
7 files changed, 120 insertions(+), 11 deletions(-)
diff --git a/components/camel-spring-main/src/main/java/org/apache/camel/spring/Main.java b/components/camel-spring-main/src/main/java/org/apache/camel/spring/Main.java
index da7480b..706d5cb 100644
--- a/components/camel-spring-main/src/main/java/org/apache/camel/spring/Main.java
+++ b/components/camel-spring-main/src/main/java/org/apache/camel/spring/Main.java
@@ -192,14 +192,19 @@ public class Main extends MainCommandLineSupport {
@Override
protected void doStop() throws Exception {
- super.doStop();
- if (additionalApplicationContext != null) {
- LOG.debug("Stopping Additional ApplicationContext: {}", additionalApplicationContext.getId());
+ try {
+ if (additionalApplicationContext != null) {
+ LOG.debug("Stopping Additional ApplicationContext: {}", additionalApplicationContext.getId());
+ additionalApplicationContext.stop();
+ }
+ if (applicationContext != null) {
+ LOG.debug("Stopping Spring ApplicationContext: {}", applicationContext.getId());
+ applicationContext.stop();
+ }
IOHelper.close(additionalApplicationContext);
- }
- if (applicationContext != null) {
- LOG.debug("Stopping Spring ApplicationContext: {}", applicationContext.getId());
IOHelper.close(applicationContext);
+ } finally {
+ super.doStop();
}
}
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/DefaultMainShutdownStrategy.java b/core/camel-main/src/main/java/org/apache/camel/main/DefaultMainShutdownStrategy.java
index 638dc4b..e08bcad 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/DefaultMainShutdownStrategy.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/DefaultMainShutdownStrategy.java
@@ -16,9 +16,14 @@
*/
package org.apache.camel.main;
+import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
+import org.apache.camel.CamelContext;
+import org.apache.camel.spi.CamelContextTracker;
+import org.apache.camel.util.StopWatch;
+import org.apache.camel.util.TimeUtils;
import org.apache.camel.util.concurrent.ThreadHelper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -31,10 +36,12 @@ public class DefaultMainShutdownStrategy extends SimpleMainShutdownStrategy {
protected static final Logger LOG = LoggerFactory.getLogger(DefaultMainShutdownStrategy.class);
private final AtomicBoolean hangupIntercepted;
+ private final BaseMainSupport main;
private volatile boolean hangupInterceptorEnabled;
- public DefaultMainShutdownStrategy() {
+ public DefaultMainShutdownStrategy(BaseMainSupport main) {
+ this.main = main;
this.hangupIntercepted = new AtomicBoolean();
}
@@ -67,6 +74,47 @@ public class DefaultMainShutdownStrategy extends SimpleMainShutdownStrategy {
private void handleHangup() {
LOG.info("Received hang up - stopping the main instance.");
+ // and shutdown listener to allow camel context to graceful shutdown if JVM shutdown hook is triggered
+ // as otherwise the JVM terminates before Camel is graceful shutdown
+ addShutdownListener(() -> {
+ LOG.trace("OnShutdown");
+ // attempt to wait for main to complete its shutdown of camel context
+ if (main.getCamelContext() != null) {
+ final CountDownLatch latch = new CountDownLatch(1);
+ // use tracker to know when camel context is destroyed so we can complete this listener quickly
+ CamelContextTracker tracker = new CamelContextTracker() {
+ @Override
+ public void contextDestroyed(CamelContext camelContext) {
+ latch.countDown();
+ }
+ };
+ tracker.open();
+
+ // use timeout from camel shutdown strategy and add 5 second extra to allow camel to shutdown graceful
+ long max = 5000 + main.getCamelContext().getShutdownStrategy().getTimeUnit().toMillis(main.getCamelContext().getShutdownStrategy().getTimeout());
+ int waits = 0;
+ boolean done = false;
+ StopWatch watch = new StopWatch();
+ while (!main.getCamelContext().isStopped() && !done && watch.taken() < max) {
+ String msg = "Waiting for CamelContext to graceful shutdown, elapsed: " + TimeUtils.printDuration(watch.taken());
+ if (waits % 5 == 0) {
+ // do some info logging every 5th time
+ LOG.info(msg);
+ } else {
+ LOG.trace(msg);
+ }
+ waits++;
+ try {
+ // wait 1 sec and loop and log activity so we can see we are waiting
+ done = latch.await(1000, TimeUnit.MILLISECONDS);
+ } catch (InterruptedException e) {
+ // ignore
+ }
+ }
+ tracker.close();
+ }
+ LOG.trace("OnShutdown complete");
+ });
shutdown();
}
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/MainShutdownStrategy.java b/core/camel-main/src/main/java/org/apache/camel/main/MainShutdownStrategy.java
index 0a28303..c5c9cc2 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/MainShutdownStrategy.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/MainShutdownStrategy.java
@@ -18,7 +18,25 @@ package org.apache.camel.main;
import java.util.concurrent.TimeUnit;
+/**
+ * Graceful shutdown when using Camel Main.
+ */
public interface MainShutdownStrategy {
+
+ /**
+ * Event listener when shutting down.
+ */
+ interface ShutdownEventListener {
+
+ /**
+ * Callback on shutdown
+ */
+ void onShutdown();
+
+ }
+
+ void addShutdownListener(ShutdownEventListener listener);
+
/**
* @return true if the application is allowed to run.
*/
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/MainSupport.java b/core/camel-main/src/main/java/org/apache/camel/main/MainSupport.java
index aeb8982..231fc7a 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/MainSupport.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/MainSupport.java
@@ -45,7 +45,7 @@ public abstract class MainSupport extends BaseMainSupport {
}
protected MainSupport() {
- this.shutdownStrategy = new DefaultMainShutdownStrategy();
+ this.shutdownStrategy = new DefaultMainShutdownStrategy(this);
}
/**
diff --git a/core/camel-main/src/main/java/org/apache/camel/main/SimpleMainShutdownStrategy.java b/core/camel-main/src/main/java/org/apache/camel/main/SimpleMainShutdownStrategy.java
index 4fcd180..8b8b7a0 100644
--- a/core/camel-main/src/main/java/org/apache/camel/main/SimpleMainShutdownStrategy.java
+++ b/core/camel-main/src/main/java/org/apache/camel/main/SimpleMainShutdownStrategy.java
@@ -16,6 +16,8 @@
*/
package org.apache.camel.main;
+import java.util.LinkedHashSet;
+import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
@@ -26,6 +28,7 @@ import org.slf4j.LoggerFactory;
public class SimpleMainShutdownStrategy implements MainShutdownStrategy {
protected static final Logger LOG = LoggerFactory.getLogger(SimpleMainShutdownStrategy.class);
+ private final Set<ShutdownEventListener> listeners = new LinkedHashSet<>();
private final AtomicBoolean completed;
private final CountDownLatch latch;
@@ -40,9 +43,24 @@ public class SimpleMainShutdownStrategy implements MainShutdownStrategy {
}
@Override
+ public void addShutdownListener(ShutdownEventListener listener) {
+ listeners.add(listener);
+ }
+
+ @Override
public boolean shutdown() {
if (completed.compareAndSet(false, true)) {
+ LOG.debug("Setting shutdown completed state from false to true");
latch.countDown();
+ for (ShutdownEventListener l : listeners) {
+ try {
+ LOG.trace("ShutdownEventListener: {}", l);
+ l.onShutdown();
+ } catch (Throwable e) {
+ // ignore as we must continue
+ LOG.debug("Error during ShutdownEventListener: {}. This exception is ignored.", l, e);
+ }
+ }
return true;
}
@@ -51,11 +69,13 @@ public class SimpleMainShutdownStrategy implements MainShutdownStrategy {
@Override
public void await() throws InterruptedException {
+ LOG.debug("Await shutdown to complete");
latch.await();
}
@Override
public void await(long timeout, TimeUnit unit) throws InterruptedException {
+ LOG.debug("Await shutdown to complete with timeout: {} {}", timeout, unit);
latch.await(timeout, unit);
}
}
diff --git a/core/camel-main/src/test/java/org/apache/camel/main/MainSupportCommandLineTest.java b/core/camel-main/src/test/java/org/apache/camel/main/MainSupportCommandLineTest.java
index bd8072c..3f22c32 100644
--- a/core/camel-main/src/test/java/org/apache/camel/main/MainSupportCommandLineTest.java
+++ b/core/camel-main/src/test/java/org/apache/camel/main/MainSupportCommandLineTest.java
@@ -20,6 +20,7 @@ import org.apache.camel.CamelContext;
import org.apache.camel.ProducerTemplate;
import org.apache.camel.impl.DefaultCamelContext;
import org.junit.jupiter.api.Test;
+
public class MainSupportCommandLineTest {
private class MyMainSupport extends MainCommandLineSupport {
diff --git a/core/camel-main/src/test/java/org/apache/camel/main/MainTest.java b/core/camel-main/src/test/java/org/apache/camel/main/MainTest.java
index d3e1b51..fac91b2 100644
--- a/core/camel-main/src/test/java/org/apache/camel/main/MainTest.java
+++ b/core/camel-main/src/test/java/org/apache/camel/main/MainTest.java
@@ -58,11 +58,12 @@ public class MainTest {
@Test
public void testDisableHangupSupport() throws Exception {
- DefaultMainShutdownStrategy shutdownStrategy = new DefaultMainShutdownStrategy();
- shutdownStrategy.disableHangupSupport();
-
// lets make a simple route
Main main = new Main();
+
+ DefaultMainShutdownStrategy shutdownStrategy = new DefaultMainShutdownStrategy(main);
+ shutdownStrategy.disableHangupSupport();
+
main.setShutdownStrategy(shutdownStrategy);
main.configure().addRoutesBuilder(new MyRouteBuilder());
main.enableTrace();
@@ -151,6 +152,22 @@ public class MainTest {
main.stop();
}
+ @Test
+ public void testDurationIdleSeconds() throws Exception {
+ Main main = new Main();
+ main.configure().addRoutesBuilder(new MyRouteBuilder());
+ main.configure().withDurationMaxIdleSeconds(2);
+ main.run();
+ }
+
+ @Test
+ public void testDurationMaxSeconds() throws Exception {
+ Main main = new Main();
+ main.configure().addRoutesBuilder(new MyRouteBuilder());
+ main.configure().withDurationMaxSeconds(2);
+ main.run();
+ }
+
public static class MyRouteBuilder extends RouteBuilder {
@Override
public void configure() throws Exception {