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
);
    }
    /**
     * Mark the index with step info for a given error encountered while retrieving policy
     * information. This is opposed to lifecycle execution errors, which would cause a transition to
     * the ERROR step, however, the policy may be unparseable in which case there is no way to move
     * to the ERROR step, so this is the best effort at capturing the error retrieving the policy.
     */
    private void markPolicyRetrievalError(String policyName, Index index, LifecycleExecutionState executionState, Exception e) {
        logger.debug(
            new ParameterizedMessage(
                "unable to retrieve policy [{}] for index [{}], recording this in step_info for this index",
                policyName,
                index.getName()
            ),
            e
        );
        setStepInfo(index, policyName, Step.getCurrentStepKey(executionState), new SetStepInfoUpdateTask.ExceptionWrapper(e));
    }
    /**
     * For the given index metadata, register (index a document) that the index has transitioned
     * successfully into this new state using the {@link ILMHistoryStore}
     */
    void registerSuccessfulOperation(IndexMetadata indexMetadata) {
        if (indexMetadata == null) {
            
            return;
        }
        Long origination = calculateOriginationMillis(indexMetadata);
        ilmHistoryStore.putAsync(