private State mainLoop(CompletionService<IFileProcessorFutureResult> completionService, TimeoutChecker timeoutChecker) {
        alreadyExecuted = true;
        State state = new State();
        LOG.info("BatchProcess starting up");

        state.start = System.currentTimeMillis();
        if (interrupter != null) {
            completionService.submit(interrupter);
        }
        if (reporter != null) {
            completionService.submit(reporter);
        }
        completionService.submit(fileResourceCrawler);
        completionService.submit(timeoutChecker);

        for (FileResourceConsumer consumer : consumersManager.getConsumers()) {
            completionService.submit(consumer);
        }

        state.numConsumers = consumersManager
                .getConsumers()
                .size();
        CAUSE_FOR_TERMINATION causeForTermination = null;
        //main processing loop
        while (true) {
            try {
                Future<IFileProcessorFutureResult> futureResult = completionService.poll(1, TimeUnit.SECONDS);

                if (futureResult != null) {
                    state.removed++;
                    IFileProcessorFutureResult result = futureResult.get();
                    LOG.trace("result: " + result);
                    if (result instanceof FileConsumerFutureResult) {
                        state.consumersRemoved++;
                    } else if (result instanceof FileResourceCrawlerFutureResult) {
                        state.crawlersRemoved++;
                        if (fileResourceCrawler.wasTimedOut()) {
                            causeForTermination = CAUSE_FOR_TERMINATION.CRAWLER_TIMED_OUT;
                            break;
                        }
                    } else if (result instanceof InterrupterFutureResult) {
                        causeForTermination = CAUSE_FOR_TERMINATION.PARENT_SHUTDOWN;
                        break;
                    } else if (result instanceof TimeoutFutureResult) {
                        causeForTermination = CAUSE_FOR_TERMINATION.TIMED_OUT_CONSUMER;
                        break;
                    } //only thing left should be StatusReporterResult
                }
                if (state.consumersRemoved >= state.numConsumers) {
                    causeForTermination = CAUSE_FOR_TERMINATION.COMPLETED_NORMALLY;
                    break;
                }
                if (aliveTooLong(state.start)) {
                    causeForTermination = CAUSE_FOR_TERMINATION.BATCH_PROCESS_ALIVE_TOO_LONG;
                    break;
                }
            } catch (Throwable e) {
                if (isNonRestart(e)) {
                    causeForTermination = CAUSE_FOR_TERMINATION.MAIN_LOOP_EXCEPTION_NO_RESTART;
                } else {
                    causeForTermination = CAUSE_FOR_TERMINATION.MAIN_LOOP_EXCEPTION;
                }
                LOG.error("Main loop execution exception: {}", e.getMessage(), e);
                break;
            }
        }
        state.causeForTermination = causeForTermination;
        return state;
    }
Runs main execution loop.
<p>
Redirects stdout to stderr to keep clean communications
over stdout with parent process

@return result of the processing
@throws InterruptedException
tika-batch/src/main/java/org/apache/tika/batch/BatchProcess.java