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
+ ") but it was "
                    + currentStep.getKey()
            );
        }
        if (currentStep instanceof AsyncActionStep) {
            logger.debug("[{}] running policy with async action step [{}]", index, currentStep.getKey());
            ((AsyncActionStep) currentStep).performAction(
                indexMetadata,
                currentState,
                new ClusterStateObserver(clusterService, null, logger, threadPool.getThreadContext()),
                new ActionListener<>() {
                    @Override
                    public void onResponse(Void unused) {
                        logger.trace("cs-change-async-action-callback, [{}], current-step: {}", index, currentStep.getKey());
                        if (((AsyncActionStep) currentStep).indexSurvives()) {
                            moveToStep(indexMetadata.getIndex(), policy, currentStep.getKey(), currentStep.getNextStepKey());
                        } else {
                            
                            
                            
                            registerDeleteOperation(indexMetadata);
                        }
                    }
                    @Override
                    public void onFailure(Exception e) {
                        moveToErrorStep(indexMetadata.getIndex(), policy, currentStep.getKey(), e);
                    }
                }
            );
        } else {