static <ID, T> TaskExecutors<ID, T> batchExecutors(final String name,
                                                       int workerCount,
                                                       final TaskProcessor<T> processor,
                                                       final AcceptorExecutor<ID, T> acceptorExecutor) {
        final AtomicBoolean isShutdown = new AtomicBoolean();
        final TaskExecutorMetrics metrics = new TaskExecutorMetrics(name);
        registeredMonitors.put(name, metrics);
        return new TaskExecutors<>(idx -> new BatchWorkerRunnable<>("TaskBatchingWorker-" + name + '-' + idx, isShutdown, metrics, processor, acceptorExecutor), workerCount, isShutdown);
    }
@Test
    public void testBatchProcessingWithTransientError() throws Exception {
        taskExecutors = TaskExecutors.batchExecutors("TEST", 1, processor, acceptorExecutor);

        List<TaskHolder<Integer, ProcessingResult>> taskHolderBatch = asList(transientErrorTaskHolder(1), transientErrorTaskHolder(2));
        taskBatchQueue.add(taskHolderBatch);

        // Verify that transient task is be re-scheduled
        processor.expectTransientErrors(2);
        verify(acceptorExecutor, timeout(500).times(1)).reprocess(taskHolderBatch, ProcessingResult.TransientError);
    }