`GatewayService` implements logic for delaying state recovery in the cluster until enough data nodes have joined and/or some timeout has occurred. The implementation is pretty old and doesn't make use of much modern infrastructure for doing this kind of thing, making it pretty hard to follow and to improve (see e.g. #86588). We should clean it up and simplify it.
server/src/main/java/org/elasticsearch/cluster/ClusterStateTaskExecutor.java
/**
     * Update the cluster state based on the current state and the given tasks. Return {@code batchExecutionContext.initialState()} to avoid
     * publishing any update.
     * <p>
     * If this method throws an exception then the cluster state is unchanged and every task's {@link ClusterStateTaskListener#onFailure}
     * method is called.
     * <p>
     * A common implementation pattern is to iterate through the tasks, constructing a new and updated {@link ClusterState} for each one.
     * This works ok but beware that constructing a whole new {@link ClusterState} can be somewhat expensive, and there may sometimes be
     * surprisingly many tasks to process in the batch. If it's possible to accumulate the effects of the tasks at a lower level then you
     * should do that instead.
     * <p>
     * Returning {@code batchExecutionContext.initialState()} is an important and useful optimisation in most cases, but note that this
     * fast-path exposes APIs to the risk of stale reads in the vicinity of a master failover: a node {@code N} that handles such a no-op
     * task batch does not verify with its peers that it's still the master, and if it's not the master then another node {@code M} may
     * already have become master and updated the state in a way that would be inconsistent with the response that {@code N} sends back to
     * clients.
     *
     * @return The resulting cluster state after executing all the tasks. If {code batchExecutionContext.initialState()} is returned then no
     * update is published.
     */
    ClusterState execute(BatchExecutionContext<T> batchExecutionContext) throws Exception;
    /**
     * @return {@code true} iff this executor should only run on the elected master.
     */
    default boolean runOnlyOnMaster() {
        return true;
    }
    /**