`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/gateway/GatewayService.java
@Override
    public void clusterChanged(final ClusterChangedEvent event) {
        if (lifecycle.stoppedOrClosed()) {
            return;
        }
        final ClusterState state = event.state();
        if (state.nodes().isLocalNodeElectedMaster() == false) {
            
            return;
        }
        if (state.blocks().hasGlobalBlock(STATE_NOT_RECOVERED_BLOCK) == false) {
            
            return;
        }
        final DiscoveryNodes nodes = state.nodes();
        if (state.nodes().getMasterNodeId() == null) {
            logger.debug("not recovering from gateway, no master elected yet");
        } else if (recoverAfterDataNodes != -1 && nodes.getDataNodes().size() < recoverAfterDataNodes) {
            logger.debug(
                "not recovering from gateway, nodes_size (data) [{}] < recover_after_data_nodes [{}]",
                nodes.getDataNodes().size(),
                recoverAfterDataNodes
            );
        } else {
            boolean enforceRecoverAfterTime;
            String reason;
            if (expectedDataNodes == -1) {
                
                enforceRecoverAfterTime = true;
                reason = "recover_after_time was set to [" + recoverAfterTime + "]";