@@ -140,32 +140,40 @@ private void processEvent(MainEventBusContext context) {
140140 LOGGER .debug ("MainEventBusProcessor: Processing event for task {}: {} (queue type: {})" ,
141141 taskId , event .getClass ().getSimpleName (), eventQueue .getClass ().getSimpleName ());
142142
143- // Step 1: Update TaskStore FIRST (persistence before clients see it)
144- updateTaskStore (taskId , event );
145-
146- // Step 2: Send push notification AFTER persistence (ensures notification sees latest state)
147- sendPushNotification (taskId );
148-
149- // Step 3: Then distribute to ChildQueues (clients see it AFTER persistence + notification)
150- if (eventQueue instanceof EventQueue .MainQueue mainQueue ) {
151- int childCount = mainQueue .getChildCount ();
152- LOGGER .debug ("MainEventBusProcessor: Distributing event to {} children for task {}" , childCount , taskId );
153- mainQueue .distributeToChildren (context .eventQueueItem ());
154- LOGGER .debug ("MainEventBusProcessor: Distributed event {} to {} children for task {}" ,
155- event .getClass ().getSimpleName (), childCount , taskId );
156- } else {
157- LOGGER .warn ("MainEventBusProcessor: Expected MainQueue but got {} for task {}" ,
158- eventQueue .getClass ().getSimpleName (), taskId );
159- }
143+ try {
144+ // Step 1: Update TaskStore FIRST (persistence before clients see it)
145+ updateTaskStore (taskId , event );
146+
147+ // Step 2: Send push notification AFTER persistence (ensures notification sees latest state)
148+ sendPushNotification (taskId );
149+
150+ // Step 3: Then distribute to ChildQueues (clients see it AFTER persistence + notification)
151+ if (eventQueue instanceof EventQueue .MainQueue mainQueue ) {
152+ int childCount = mainQueue .getChildCount ();
153+ LOGGER .debug ("MainEventBusProcessor: Distributing event to {} children for task {}" , childCount , taskId );
154+ mainQueue .distributeToChildren (context .eventQueueItem ());
155+ LOGGER .debug ("MainEventBusProcessor: Distributed event {} to {} children for task {}" ,
156+ event .getClass ().getSimpleName (), childCount , taskId );
157+ } else {
158+ LOGGER .warn ("MainEventBusProcessor: Expected MainQueue but got {} for task {}" ,
159+ eventQueue .getClass ().getSimpleName (), taskId );
160+ }
160161
161- LOGGER .debug ("MainEventBusProcessor: Completed processing event for task {}" , taskId );
162+ LOGGER .debug ("MainEventBusProcessor: Completed processing event for task {}" , taskId );
162163
163- // Step 4: Notify callback after all processing is complete
164- callback .onEventProcessed (taskId , event );
164+ // Step 4: Notify callback after all processing is complete
165+ callback .onEventProcessed (taskId , event );
165166
166- // Step 5: If this is a final event, notify task finalization
167- if (isFinalEvent (event )) {
168- callback .onTaskFinalized (taskId );
167+ // Step 5: If this is a final event, notify task finalization
168+ if (isFinalEvent (event )) {
169+ callback .onTaskFinalized (taskId );
170+ }
171+ } finally {
172+ // ALWAYS release semaphore, even if processing fails
173+ // Balances the acquire() in MainQueue.enqueueEvent()
174+ if (eventQueue instanceof EventQueue .MainQueue mainQueue ) {
175+ mainQueue .releaseSemaphore ();
176+ }
169177 }
170178 }
171179
0 commit comments