From 3d4d68c26fbffc6f2978043ff903a517ee890b40 Mon Sep 17 00:00:00 2001 From: Juergen Hoeller Date: Thu, 1 Feb 2024 11:07:02 +0100 Subject: [PATCH] Run listener/send task locally as fallback on RejectedExecutionException Closes gh-32171 --- .../event/SimpleApplicationEventMulticaster.java | 11 +++++++++-- .../support/ExecutorSubscribableChannel.java | 16 ++++++++++++---- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/spring-context/src/main/java/org/springframework/context/event/SimpleApplicationEventMulticaster.java b/spring-context/src/main/java/org/springframework/context/event/SimpleApplicationEventMulticaster.java index ac7613f072d6..a9a067a92791 100644 --- a/spring-context/src/main/java/org/springframework/context/event/SimpleApplicationEventMulticaster.java +++ b/spring-context/src/main/java/org/springframework/context/event/SimpleApplicationEventMulticaster.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,7 @@ package org.springframework.context.event; import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; @@ -143,7 +144,13 @@ public void multicastEvent(ApplicationEvent event, @Nullable ResolvableType even Executor executor = getTaskExecutor(); for (ApplicationListener listener : getApplicationListeners(event, type)) { if (executor != null && listener.supportsAsyncExecution()) { - executor.execute(() -> invokeListener(listener, event)); + try { + executor.execute(() -> invokeListener(listener, event)); + } + catch (RejectedExecutionException ex) { + // Probably on shutdown -> invoke listener locally instead + invokeListener(listener, event); + } } else { invokeListener(listener, event); diff --git a/spring-messaging/src/main/java/org/springframework/messaging/support/ExecutorSubscribableChannel.java b/spring-messaging/src/main/java/org/springframework/messaging/support/ExecutorSubscribableChannel.java index 1a2081f68dbb..1d8b56531d52 100644 --- a/spring-messaging/src/main/java/org/springframework/messaging/support/ExecutorSubscribableChannel.java +++ b/spring-messaging/src/main/java/org/springframework/messaging/support/ExecutorSubscribableChannel.java @@ -1,5 +1,5 @@ /* - * Copyright 2002-2023 the original author or authors. + * Copyright 2002-2024 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,6 +19,7 @@ import java.util.ArrayList; import java.util.List; import java.util.concurrent.Executor; +import java.util.concurrent.RejectedExecutionException; import org.springframework.lang.Nullable; import org.springframework.messaging.Message; @@ -96,11 +97,18 @@ private void updateExecutorInterceptorsFor(ChannelInterceptor interceptor) { public boolean sendInternal(Message message, long timeout) { for (MessageHandler handler : getSubscribers()) { SendTask sendTask = new SendTask(message, handler); - if (this.executor == null) { - sendTask.run(); + if (this.executor != null) { + try { + this.executor.execute(sendTask); + } + catch (RejectedExecutionException ex) { + // Probably on shutdown -> run send task locally instead + sendTask.run(); + } } else { - this.executor.execute(sendTask); + // No executor configured -> always run send tasks locally + sendTask.run(); } } return true;