@@ -285,20 +285,32 @@ private boolean send(String serverId, String deliveryId, JsonEnvelope envelope,
285285 }
286286
287287 private void finishClose () {
288- try {
289- try { shutdown (handlerExecutor ); }
290- finally { shutdown (listenerExecutor ); }
291- } finally {
292- try {
293- synchronized (backends ) {
294- for (BackendState backend : backends .values ()) { backend .seal (); backend .signal (); }
295- backends .clear ();
296- }
297- } finally { try { if (durableOutgoing != null ) durableOutgoing .close (); }
298- finally {
299- synchronized (closeMonitor ) { closeFinalizing = false ; closeFinalized = true ; closeMonitor .notifyAll (); }
300- } }
288+ boolean handlersTerminated ;
289+ try { handlersTerminated = shutdown (handlerExecutor ); }
290+ finally { shutdown (listenerExecutor ); }
291+ if (!handlersTerminated ) {
292+ Thread reaper = new Thread (this ::finishCloseAfterHandlers , "SimpleAPI-HTTP-proxy-handler-reaper" );
293+ reaper .setDaemon (true );
294+ reaper .start ();
295+ return ;
301296 }
297+ sealAfterHandlers ();
298+ }
299+ private void finishCloseAfterHandlers () {
300+ boolean interrupted = false ;
301+ while (!handlerExecutor .isTerminated ()) try { handlerExecutor .awaitTermination (1 , TimeUnit .DAYS ); }
302+ catch (InterruptedException ignored ) { interrupted = true ; }
303+ if (interrupted ) Thread .currentThread ().interrupt ();
304+ sealAfterHandlers ();
305+ }
306+ private void sealAfterHandlers () {
307+ try {
308+ synchronized (backends ) {
309+ for (BackendState backend : backends .values ()) { backend .seal (); backend .signal (); }
310+ backends .clear ();
311+ }
312+ } finally { try { if (durableOutgoing != null ) durableOutgoing .close (); }
313+ finally { synchronized (closeMonitor ) { closeFinalizing = false ; closeFinalized = true ; closeMonitor .notifyAll (); } } }
302314 }
303315
304316 private void awaitClose () {
@@ -472,13 +484,13 @@ private static ThreadPoolExecutor executor(String name, int threads, int queue,
472484 return new ThreadPoolExecutor (threads , threads , 0L , TimeUnit .MILLISECONDS , new ArrayBlockingQueue <>(queue ), factory , new ThreadPoolExecutor .AbortPolicy ());
473485 }
474486 private static void setDefault (String name , String value ) { if (System .getProperty (name ) == null ) System .setProperty (name , value ); }
475- static void shutdown (ExecutorService executor ) {
487+ static boolean shutdown (ExecutorService executor ) {
476488 executor .shutdown ();
477489 boolean interrupted = false ;
478490 try {
479491 if (!executor .awaitTermination (5 , TimeUnit .SECONDS )) {
480492 executor .shutdownNow ();
481- executor .awaitTermination (1 , TimeUnit .SECONDS );
493+ return executor .awaitTermination (1 , TimeUnit .SECONDS );
482494 }
483495 } catch (InterruptedException stopRequested ) {
484496 interrupted = true ;
@@ -487,6 +499,7 @@ static void shutdown(ExecutorService executor) {
487499 catch (InterruptedException repeated ) { interrupted = true ; }
488500 }
489501 if (interrupted ) Thread .currentThread ().interrupt ();
502+ return executor .isTerminated ();
490503 }
491504
492505 public record ReceivedEnvelope (String serverId , String messageId , JsonEnvelope envelope ) { }
0 commit comments