Skip to content

Commit

Permalink
CAMEL-21185: camel-management - ShutdownStrategy should be a MBean so…
Browse files Browse the repository at this point in the history
… we can better define its JMX API. Also fix so all its attributes was exposed so you can configure timeout again. (#15471)
  • Loading branch information
davsclaus authored Sep 7, 2024
1 parent 43dd6ef commit cf70d57
Show file tree
Hide file tree
Showing 8 changed files with 241 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -229,9 +229,19 @@ boolean shutdown(CamelContext context, RouteStartupOrder route, long timeout, Ti

/**
* Whether a timeout has occurred during a shutdown.
*
* @deprecated use {@link #isTimeoutOccurred()}
*/
@Deprecated(since = "4.8.0")
boolean hasTimeoutOccurred();

/**
* Whether a timeout has occurred during a shutdown.
*/
default boolean isTimeoutOccurred() {
return hasTimeoutOccurred();
}

/**
* Gets the logging level used for logging shutdown activity (such as starting and stopping routes). The default
* logging level is DEBUG.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,11 @@ public boolean isForceShutdown() {

@Override
public boolean hasTimeoutOccurred() {
return isTimeoutOccurred();
}

@Override
public boolean isTimeoutOccurred() {
return timeoutOccurred.get();
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.api.management.mbean;

import java.util.concurrent.TimeUnit;

import org.apache.camel.api.management.ManagedAttribute;

public interface ManagedShutdownStrategyMBean extends ManagedServiceMBean {

@ManagedAttribute(description = "Shutdown timeout")
void setTimeout(long timeout);

@ManagedAttribute(description = "Shutdown timeout")
long getTimeout();

@ManagedAttribute(description = "Shutdown timeout time unit")
void setTimeUnit(TimeUnit timeUnit);

@ManagedAttribute(description = "Shutdown timeout time unit")
TimeUnit getTimeUnit();

@ManagedAttribute(description = "Whether Camel should try to suppress logging during shutdown and timeout was triggered, meaning forced shutdown is happening.")
void setSuppressLoggingOnTimeout(boolean suppressLoggingOnTimeout);

@ManagedAttribute(description = "Whether Camel should try to suppress logging during shutdown and timeout was triggered, meaning forced shutdown is happening.")
boolean isSuppressLoggingOnTimeout();

@ManagedAttribute(description = "Whether to force shutdown of all consumers when a timeout occurred.")
void setShutdownNowOnTimeout(boolean shutdownNowOnTimeout);

@ManagedAttribute(description = "Whether to force shutdown of all consumers when a timeout occurred.")
boolean isShutdownNowOnTimeout();

@ManagedAttribute(description = "Sets whether routes should be shutdown in reverse or the same order as they were started")
void setShutdownRoutesInReverseOrder(boolean shutdownRoutesInReverseOrder);

@ManagedAttribute(description = "Sets whether routes should be shutdown in reverse or the same order as they were started")
boolean isShutdownRoutesInReverseOrder();

@ManagedAttribute(description = "Whether to log information about the inflight Exchanges which are still running during a shutdown which didn't complete without the given timeout.")
void setLogInflightExchangesOnTimeout(boolean logInflightExchangesOnTimeout);

@ManagedAttribute(description = "Whether to log information about the inflight Exchanges which are still running during a shutdown which didn't complete without the given timeout.")
boolean isLogInflightExchangesOnTimeout();

@ManagedAttribute(description = "Whether the shutdown strategy is forcing to shutdown")
boolean isForceShutdown();

@ManagedAttribute(description = "Whether a timeout has occurred during a shutdown.")
boolean isTimeoutOccurred();

@ManagedAttribute(description = "logging level used for logging shutdown activity (such as starting and stopping routes). The default logging level is DEBUG.")
String getLoggingLevel();

@ManagedAttribute(description = "logging level used for logging shutdown activity (such as starting and stopping routes). The default logging level is DEBUG.")
void setLoggingLevel(String loggingLevel);

}
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
import org.apache.camel.management.mbean.ManagedRoute;
import org.apache.camel.management.mbean.ManagedRuntimeEndpointRegistry;
import org.apache.camel.management.mbean.ManagedService;
import org.apache.camel.management.mbean.ManagedShutdownStrategy;
import org.apache.camel.management.mbean.ManagedStreamCachingStrategy;
import org.apache.camel.management.mbean.ManagedThrottlingExceptionRoutePolicy;
import org.apache.camel.management.mbean.ManagedThrottlingInflightRoutePolicy;
Expand Down Expand Up @@ -104,6 +105,7 @@
import org.apache.camel.spi.ProducerCache;
import org.apache.camel.spi.RestRegistry;
import org.apache.camel.spi.RuntimeEndpointRegistry;
import org.apache.camel.spi.ShutdownStrategy;
import org.apache.camel.spi.StreamCachingStrategy;
import org.apache.camel.spi.Tracer;
import org.apache.camel.spi.TransformerRegistry;
Expand Down Expand Up @@ -565,8 +567,10 @@ private Object getManagedObjectForService(CamelContext context, Service service,
answer = new ManagedRuntimeEndpointRegistry(context, runtimeEndpointRegistry);
} else if (service instanceof StreamCachingStrategy streamCachingStrategy) {
answer = new ManagedStreamCachingStrategy(context, streamCachingStrategy);
} else if (service instanceof ShutdownStrategy shutdownStrategy) {
answer = new ManagedShutdownStrategy(context, shutdownStrategy);
} else if (service instanceof EventNotifier eventNotifier)
answer = getManagementObjectStrategy().getManagedObjectForEventNotifier(context, (EventNotifier) service);
answer = getManagementObjectStrategy().getManagedObjectForEventNotifier(context, eventNotifier);
else if (service instanceof TransformerRegistry transformerRegistry) {
answer = new ManagedTransformerRegistry(context, transformerRegistry);
} else if (service instanceof ValidatorRegistry validatorRegistry) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.camel.management.mbean;

import java.util.concurrent.TimeUnit;

import org.apache.camel.CamelContext;
import org.apache.camel.LoggingLevel;
import org.apache.camel.api.management.ManagedResource;
import org.apache.camel.api.management.mbean.ManagedShutdownStrategyMBean;
import org.apache.camel.spi.ShutdownStrategy;

@ManagedResource(description = "Managed ShutdownStrategy")
public class ManagedShutdownStrategy extends ManagedService implements ManagedShutdownStrategyMBean {

private final ShutdownStrategy strategy;

public ManagedShutdownStrategy(CamelContext context, ShutdownStrategy controller) {
super(context, controller);
this.strategy = controller;
}

public ShutdownStrategy getShutdownStrategy() {
return strategy;
}

@Override
public void setTimeout(long timeout) {
strategy.setTimeout(timeout);
}

@Override
public long getTimeout() {
return strategy.getTimeout();
}

@Override
public void setTimeUnit(TimeUnit timeUnit) {
strategy.setTimeUnit(timeUnit);
}

@Override
public TimeUnit getTimeUnit() {
return strategy.getTimeUnit();
}

@Override
public void setSuppressLoggingOnTimeout(boolean suppressLoggingOnTimeout) {
strategy.setSuppressLoggingOnTimeout(suppressLoggingOnTimeout);
}

@Override
public boolean isSuppressLoggingOnTimeout() {
return strategy.isSuppressLoggingOnTimeout();
}

@Override
public void setShutdownNowOnTimeout(boolean shutdownNowOnTimeout) {
strategy.setShutdownNowOnTimeout(shutdownNowOnTimeout);
}

@Override
public boolean isShutdownNowOnTimeout() {
return strategy.isShutdownNowOnTimeout();
}

@Override
public void setShutdownRoutesInReverseOrder(boolean shutdownRoutesInReverseOrder) {
strategy.setShutdownRoutesInReverseOrder(shutdownRoutesInReverseOrder);
}

@Override
public boolean isShutdownRoutesInReverseOrder() {
return strategy.isShutdownRoutesInReverseOrder();
}

@Override
public void setLogInflightExchangesOnTimeout(boolean logInflightExchangesOnTimeout) {
strategy.setLogInflightExchangesOnTimeout(logInflightExchangesOnTimeout);
}

@Override
public boolean isLogInflightExchangesOnTimeout() {
return strategy.isLogInflightExchangesOnTimeout();
}

@Override
public boolean isForceShutdown() {
return strategy.isForceShutdown();
}

@Override
public boolean isTimeoutOccurred() {
return strategy.isTimeoutOccurred();
}

@Override
public String getLoggingLevel() {
return strategy.getLoggingLevel().toString();
}

@Override
public void setLoggingLevel(String loggingLevel) {
strategy.setLoggingLevel(LoggingLevel.valueOf(loggingLevel));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.apache.camel.management;

import java.util.Locale;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import javax.management.MBeanServer;
Expand All @@ -27,7 +28,10 @@
import org.junit.jupiter.api.condition.DisabledOnOs;
import org.junit.jupiter.api.condition.OS;

import static org.apache.camel.management.DefaultManagementObjectNameStrategy.TYPE_SERVICE;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;

@DisabledOnOs(OS.AIX)
public class ManagedShutdownStrategyTest extends ManagementTestSupport {
Expand All @@ -39,13 +43,30 @@ public void testManagedShutdownStrategy() throws Exception {

MBeanServer mbeanServer = getMBeanServer();

ObjectName on = getContextObjectName();
ObjectName on = getCamelObjectName(TYPE_SERVICE, "*");

Long timeout = (Long) mbeanServer.getAttribute(on, "Timeout");
// number of services
Set<ObjectName> names = mbeanServer.queryNames(on, null);
ObjectName name = null;
for (ObjectName service : names) {
if (service.toString().contains("DefaultShutdownStrategy")) {
name = service;
break;
}
}
assertNotNull(name, "Cannot find DefaultShutdownStrategy");

Long timeout = (Long) mbeanServer.getAttribute(name, "Timeout");
assertEquals(300, timeout.longValue());

TimeUnit unit = (TimeUnit) mbeanServer.getAttribute(on, "TimeUnit");
TimeUnit unit = (TimeUnit) mbeanServer.getAttribute(name, "TimeUnit");
assertEquals("seconds", unit.toString().toLowerCase(Locale.ENGLISH));

String level = (String) mbeanServer.getAttribute(name, "LoggingLevel");
assertEquals("DEBUG", level);

Boolean order = (Boolean) mbeanServer.getAttribute(name, "ShutdownRoutesInReverseOrder");
assertTrue(order);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ protected boolean isCausedByRollbackExchangeException(Throwable exception) {
protected boolean isSuppressLogging() {
if (camelContext != null) {
return (camelContext.getStatus().isStopping() || camelContext.getStatus().isStopped())
&& camelContext.getShutdownStrategy().hasTimeoutOccurred()
&& camelContext.getShutdownStrategy().isTimeoutOccurred()
&& camelContext.getShutdownStrategy().isSuppressLoggingOnTimeout();
} else {
return false;
Expand Down
4 changes: 3 additions & 1 deletion docs/user-manual/modules/ROOT/pages/graceful-shutdown.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,9 @@ context.getShutdownStrategy().setLogInflightExchangesOnTimeout(false);
=== JMX managed

The `ShutdownStrategy` is JMX aware, so you can manage it from a
JMX console. This allows to adjust the strategy at runtime, such as changing the timeout setting.
JMX console. This allows to adjust the strategy at runtime.

TIP: The timeout settings can also be changed on the `CamelContextMBean`.

== Controlling ordering of routes

Expand Down

0 comments on commit cf70d57

Please sign in to comment.