@@ -246,6 +246,7 @@ protected void doClose() {}
246246     * other lenience to handle that. It'd be better to wait for the shard locks to be released and then delete the data. See #74149. 
247247     */ 
248248    private  volatile  SubscribableListener <Void > lastClusterStateShardsClosedListener  = SubscribableListener .nullSuccess ();
249+     private  int  shardsClosedListenerChainLength  = 0 ;
249250
250251    @ Nullable  // if not currently applying a cluster state 
251252    private  RefCountingListener  currentClusterStateShardsClosedListeners ;
@@ -274,8 +275,26 @@ public synchronized void applyClusterState(final ClusterChangedEvent event) {
274275        lastClusterStateShardsClosedListener  = new  SubscribableListener <>();
275276        currentClusterStateShardsClosedListeners  = new  RefCountingListener (lastClusterStateShardsClosedListener );
276277        try  {
277-             previousShardsClosedListener .addListener (currentClusterStateShardsClosedListeners .acquire ());
278278            doApplyClusterState (event );
279+             // HACK: chain listeners but avoid too deep of a stack 
280+             {
281+                 if  (previousShardsClosedListener .isDone ()) {
282+                     shardsClosedListenerChainLength  = 0 ;
283+                 }
284+                 previousShardsClosedListener .addListener (
285+                     currentClusterStateShardsClosedListeners .acquire (),
286+                     // Sometimes fork the listener on a different thread. 
287+                     // Chaining too many listeners might trigger a stackoverflow exception on the thread that eventually gets to 
288+                     // execute them all (because the last thread that decreases the ref count to 0 of a {@link RefCountingListener} 
289+                     // also executes its listeners, which in turn might decrease the ref count to 0 of another 
290+                     // {@link RefCountingListerner}, again executing its listeners, etc...). 
291+                     shardsClosedListenerChainLength ++ < 10  ? EsExecutors .DIRECT_EXECUTOR_SERVICE  : threadPool .generic (),
292+                     null 
293+                 );
294+                 if  (shardsClosedListenerChainLength  >= 10 ) {
295+                     shardsClosedListenerChainLength  = 0 ;
296+                 }
297+             }
279298        } finally  {
280299            currentClusterStateShardsClosedListeners .close ();
281300            currentClusterStateShardsClosedListeners  = null ;
0 commit comments