Skip to content

Commit 9e8855a

Browse files
Add async job event bus publisher (#12971)
* Async event bus publishing in AsyncJobManagerImpl to reduce API thread contention publishOnEventBus() was calling _messageBus.publish() synchronously on the request thread, which blocks on MessageBusBase$Gate (an exclusive mutex). JFR analysis showed this causing up to 107ms waits on Jetty request threads, contributing to 502 errors from the upstream load balancer. Move event bus publishing to a dedicated single-threaded executor so API request threads are no longer blocked by Gate contention. Event ordering is preserved by the single-threaded executor. * Wrap async event bus publish in ManagedContextRunnable for DB connection safety The sole subscriber (ApiServer.handleAsyncJobPublishEvent) performs DAO reads (getUserIncludingRemoved, getAccount, findById) inside its callback. Without ManagedContextRunnable, the EventBus thread would not have proper TransactionLegacy lifecycle management, risking DB connection leaks. * logger fix * review comments * review changes --------- Co-authored-by: Aaron Chung <aaron_chung@apple.com>
1 parent 7c2a876 commit 9e8855a

1 file changed

Lines changed: 22 additions & 2 deletions

File tree

framework/jobs/src/main/java/org/apache/cloudstack/framework/jobs/impl/AsyncJobManagerImpl.java

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,7 @@ public class AsyncJobManagerImpl extends ManagerBase implements AsyncJobManager,
184184
private volatile long _executionRunNumber = 1;
185185

186186
private final ScheduledExecutorService _heartbeatScheduler = Executors.newScheduledThreadPool(1, new NamedThreadFactory("AsyncJobMgr-Heartbeat"));
187+
private final ExecutorService _eventBusPublisher = Executors.newSingleThreadExecutor(new NamedThreadFactory("AsyncJobMgr-EventBus"));
187188
private ExecutorService _apiJobExecutor;
188189
private ExecutorService _workerJobExecutor;
189190

@@ -1378,6 +1379,7 @@ public boolean start() {
13781379
@Override
13791380
public boolean stop() {
13801381
_heartbeatScheduler.shutdown();
1382+
_eventBusPublisher.shutdown();
13811383
_apiJobExecutor.shutdown();
13821384
_workerJobExecutor.shutdown();
13831385
return true;
@@ -1397,8 +1399,26 @@ protected AsyncJobManagerImpl() {
13971399
}
13981400

13991401
private void publishOnEventBus(AsyncJob job, String jobEvent) {
1400-
_messageBus.publish(null, AsyncJob.Topics.JOB_EVENT_PUBLISH, PublishScope.LOCAL,
1401-
new Pair<AsyncJob, String>(job, jobEvent));
1402+
try {
1403+
_eventBusPublisher.submit(new ManagedContextRunnable() {
1404+
@Override
1405+
protected void runInContext() {
1406+
publishJobEvent(job, jobEvent);
1407+
}
1408+
});
1409+
} catch (RejectedExecutionException e) {
1410+
logger.warn("Failed to publish async job event, event bus publisher is shut down", e);
1411+
}
1412+
}
1413+
1414+
private void publishJobEvent(AsyncJob job, String jobEvent) {
1415+
try {
1416+
_messageBus.publish(null, AsyncJob.Topics.JOB_EVENT_PUBLISH, PublishScope.LOCAL,
1417+
new Pair<>(job, jobEvent));
1418+
} catch (Throwable t) {
1419+
logger.warn("Failed to publish async job event on message bus. jobId={}, jobEvent={}",
1420+
job != null ? job.getId() : null, jobEvent, t);
1421+
}
14021422
}
14031423

14041424
@Override

0 commit comments

Comments
 (0)