In https://github.com/elastic/elasticsearch/pull/78547 we introduced batching for the ILM master tasks that occur on the happy path. However if a high-shard-count cluster encounters problems while doing ILM-related things—perhaps some nodes are temporarily unavailable for taking a snapshot—then we process the resulting `ilm-retry-failed-step` and `ilm-move-to-error-step` tasks one-by-one which can significantly delay the cluster's recovery from its problems.

We should batch these things together too.

It looks like we also enqueue duplicate `ilm-retry-failed-step` on each poll interval too, although we do appear to treat the duplicates as no-ops at execution time.

Relates https://github.com/elastic/elasticsearch/issues/77466
x-pack/plugin/ilm/src/main/java/org/elasticsearch/xpack/ilm/IndexLifecycleRunner.java
"ilm-retry-failed-step {policy [%s], index [%s], failedStep [%s]}",
                    policy,
                    index,
                    failedStep.getKey()
                ),
                new ClusterStateUpdateTask(TimeValue.MAX_VALUE) {
                    @Override
                    public ClusterState execute(ClusterState currentState) {
                        return IndexLifecycleTransition.moveClusterStateToPreviouslyFailedStep(
                            currentState,
                            index,
                            nowSupplier,
                            stepRegistry,
                            true
                        );
                    }
                    @Override
                    public void onFailure(Exception e) {
                        logger.error(
                            new ParameterizedMessage(
                                "retry execution of step [{}] for index [{}] failed",
                                failedStep.getKey().getName(),
                                index
                            ),
                            e
                        );
                    }
                    @Override
                    public void clusterStateProcessed(ClusterState oldState, ClusterState newState) {
                        if (oldState.equals(newState) == false) {