ARTEMIS-297 Handle Exceptions during server stop

Stopping the server should be able to handle exceptions thrown by
individual components.  Before this patch the stop method would throw
any raised exception and exit.  This can lead to partial shutdowns of
the server resulting in leaking threads.  This patch catches any
component exceptions and logs an appropriate error message, allowing the
server to properly shutdown.
This commit is contained in:
Martyn Taylor 2015-11-04 12:53:39 +00:00 committed by Clebert Suconic
parent a4018e4817
commit 046c3b1942
3 changed files with 93 additions and 24 deletions

View File

@ -346,7 +346,14 @@ public class RemotingServiceImpl implements RemotingService, ConnectionLifeCycle
if (ActiveMQServerLogger.LOGGER.isDebugEnabled()) {
ActiveMQServerLogger.LOGGER.debug("Pausing acceptor " + acceptor);
}
acceptor.pause();
try {
acceptor.pause();
}
catch (Throwable t) {
ActiveMQServerLogger.LOGGER.errorStoppingAcceptor();
}
}
if (ActiveMQServerLogger.LOGGER.isDebugEnabled()) {
@ -368,7 +375,12 @@ public class RemotingServiceImpl implements RemotingService, ConnectionLifeCycle
}
for (Acceptor acceptor : acceptors.values()) {
acceptor.stop();
try {
acceptor.stop();
}
catch (Throwable t) {
ActiveMQServerLogger.LOGGER.errorStoppingAcceptor();
}
}
acceptors.clear();
@ -391,7 +403,6 @@ public class RemotingServiceImpl implements RemotingService, ConnectionLifeCycle
}
started = false;
}
@Override

View File

@ -1457,4 +1457,12 @@ public interface ActiveMQServerLogger extends BasicLogger {
@LogMessage(level = Logger.Level.ERROR)
@Message(id = 224067, value = "Error populating security roles from LDAP", format = Message.Format.MESSAGE_FORMAT)
void errorPopulatingSecurityRolesFromLDAP(@Cause Exception e);
@LogMessage(level = Logger.Level.ERROR)
@Message(id = 224068, value = "Unable to stop component: {0}", format = Message.Format.MESSAGE_FORMAT)
void errorStoppingComponent(@Cause Throwable t, String componentClassName);
@LogMessage(level = Logger.Level.DEBUG)
@Message(id = 224070, value = "Received Interrupt Exception whilst waiting for component to shutdown: {0}", format = Message.Format.MESSAGE_FORMAT)
void interruptWhilstStoppingComponent(String componentClassName);
}

View File

@ -572,7 +572,7 @@ public class ActiveMQServerImpl implements ActiveMQServer {
*
* @param criticalIOError whether we have encountered an IO error with the journal etc
*/
void stop(boolean failoverOnServerShutdown, final boolean criticalIOError, boolean restarting) throws Exception {
void stop(boolean failoverOnServerShutdown, final boolean criticalIOError, boolean restarting) {
synchronized (this) {
if (state == SERVER_STATE.STOPPED || state == SERVER_STATE.STOPPING) {
return;
@ -587,7 +587,7 @@ public class ActiveMQServerImpl implements ActiveMQServer {
// aren't removed in case of failover
if (groupingHandler != null) {
managementService.removeNotificationListener(groupingHandler);
groupingHandler.stop();
stopComponent(groupingHandler);
}
stopComponent(clusterManager);
@ -598,11 +598,16 @@ public class ActiveMQServerImpl implements ActiveMQServer {
// allows for graceful shutdown
if (remotingService != null && configuration.isGracefulShutdownEnabled()) {
long timeout = configuration.getGracefulShutdownTimeout();
if (timeout == -1) {
remotingService.getConnectionCountLatch().await();
try {
if (timeout == -1) {
remotingService.getConnectionCountLatch().await();
}
else {
remotingService.getConnectionCountLatch().await(timeout);
}
}
else {
remotingService.getConnectionCountLatch().await(timeout);
catch (InterruptedException e) {
ActiveMQServerLogger.LOGGER.interruptWhilstStoppingComponent(remotingService.getClass().getName());
}
}
@ -629,24 +634,45 @@ public class ActiveMQServerImpl implements ActiveMQServer {
callDeActiveCallbacks();
stopComponent(backupManager);
activation.preStorageClose();
try {
activation.preStorageClose();
}
catch (Throwable t) {
ActiveMQServerLogger.LOGGER.errorStoppingComponent(t, activation.getClass().getName());
}
stopComponent(pagingManager);
if (storageManager != null)
storageManager.stop(criticalIOError);
try {
storageManager.stop(criticalIOError);
}
catch (Throwable t) {
ActiveMQServerLogger.LOGGER.errorStoppingComponent(t, storageManager.getClass().getName());
}
// We stop remotingService before otherwise we may lock the system in case of a critical IO
// error shutdown
if (remotingService != null)
remotingService.stop(criticalIOError);
try {
remotingService.stop(criticalIOError);
}
catch (Throwable t) {
ActiveMQServerLogger.LOGGER.errorStoppingComponent(t, remotingService.getClass().getName());
}
// Stop the management service after the remoting service to ensure all acceptors are deregistered with JMX
if (managementService != null)
managementService.unregisterServer();
try {
managementService.unregisterServer();
}
catch (Throwable t) {
ActiveMQServerLogger.LOGGER.errorStoppingComponent(t, managementService.getClass().getName());
}
stopComponent(managementService);
stopComponent(resourceManager);
stopComponent(postOffice);
if (scheduledPool != null && !scheduledPoolSupplied) {
@ -667,7 +693,7 @@ public class ActiveMQServerImpl implements ActiveMQServer {
}
}
catch (InterruptedException e) {
// Ignore
ActiveMQServerLogger.LOGGER.interruptWhilstStoppingComponent(threadPool.getClass().getName());
}
}
@ -676,8 +702,15 @@ public class ActiveMQServerImpl implements ActiveMQServer {
if (!scheduledPoolSupplied)
scheduledPool = null;
if (securityStore != null)
securityStore.stop();
if (securityStore != null) {
try {
securityStore.stop();
}
catch (Throwable t) {
ActiveMQServerLogger.LOGGER.errorStoppingComponent(t, managementService.getClass().getName());
}
}
pagingManager = null;
securityStore = null;
@ -699,11 +732,22 @@ public class ActiveMQServerImpl implements ActiveMQServer {
// to display in the log message
SimpleString tempNodeID = getNodeID();
if (activation != null) {
activation.close(failoverOnServerShutdown, restarting);
try {
activation.close(failoverOnServerShutdown, restarting);
}
catch (Throwable t) {
ActiveMQServerLogger.LOGGER.errorStoppingComponent(t, activation.getClass().getName());
}
}
if (backupActivationThread != null) {
backupActivationThread.join(30000);
if (backupActivationThread != null) {
try {
backupActivationThread.join(30000);
}
catch (InterruptedException e) {
ActiveMQServerLogger.LOGGER.interruptWhilstStoppingComponent(backupActivationThread.getClass().getName());
}
if (backupActivationThread.isAlive()) {
ActiveMQServerLogger.LOGGER.backupActivationDidntFinish(this);
backupActivationThread.interrupt();
@ -790,9 +834,15 @@ public class ActiveMQServerImpl implements ActiveMQServer {
}
static void stopComponent(ActiveMQComponent component) throws Exception {
if (component != null)
component.stop();
static void stopComponent(ActiveMQComponent component) {
try {
if (component != null) {
component.stop();
}
}
catch (Throwable t) {
ActiveMQServerLogger.LOGGER.errorStoppingComponent(t, component.getClass().getName());
}
}
// ActiveMQServer implementation