Как осуществляется пропуск в Spring Batch?

Мне было интересно, как я мог определить в моем ItemWriterнезависимо от того, находился ли Spring Batch в режиме обработки фрагментов или в резервном режиме обработки отдельных элементов. Во-первых, я не нашел информации о том, как реализован этот резервный механизм.

Даже если я еще не нашел решения своей настоящей проблемы, я хотел бы поделиться с вами своими знаниями о резервном механизме.

Не стесняйтесь добавлять ответы с дополнительной информацией, если я что-то пропустил;-)

2 ответа

Решение

Реализация механизма пропуска может быть найдена в FaultTolerantChunkProcessor и в RetryTemplate.

Предположим, вы настроили пропускаемые исключения, но не повторяющиеся исключения. И в текущем чанке есть неисправный элемент, вызывающий исключение.

Теперь, прежде всего, весь кусок будет написан. В процессоре write() метод, который вы можете увидеть, что RetryTemplate называется. Он также получает две ссылки на RetryCallback и RecoveryCallback,

Переключитесь на RetryTemplate, Найдите следующий метод:

protected <T> T doExecute(RetryCallback<T> retryCallback, RecoveryCallback<T> recoveryCallback, RetryState state)

Там вы можете увидеть, что RetryTemplate повторяется до тех пор, пока он не исчерпан (т.е. ровно один раз в нашей конфигурации). Такая повторная попытка будет вызвана повторяющимся исключением. Неповторяющиеся исключения немедленно прервут механизм повтора здесь.

После того, как повторные попытки исчерпаны или прерваны, RecoveryCallback будет называться:

e = handleRetryExhausted(recoveryCallback, context, state);

Вот где сейчас включится режим обработки одного предмета!

RecoveryCallback (который был определен в процессоре write() метод!) установит блокировку входного блока (inputs.setBusy(true) Запусти свой scan() метод. Там вы можете видеть, что из куска взят один элемент:

List<O> items = Collections.singletonList(outputIterator.next());

Если этот единственный элемент может быть обработан ItemWriter правильно, чем чанк будет закончен и ChunkOrientedTasklet будет запускать другой кусок (для следующих отдельных элементов). Это приведет к регулярному звонку на RetryCallback, но так как кусок был заблокирован RecoveryTemplate, scan() метод будет вызван немедленно:

if (!inputs.isBusy()) {
    // ...
}
else {
    scan(contribution, inputs, outputs, chunkMonitor);
}

Таким образом, будет обработан еще один элемент, и это будет повторяться до тех пор, пока исходный фрагмент не будет обработан элемент за элементом:

if (outputs.isEmpty()) {
    inputs.setBusy(false);

Вот и все. Я надеюсь, что вы нашли это полезным. И я еще больше надеюсь, что вы могли бы легко найти это через поисковик и не тратить слишком много времени, выясняя это самостоятельно.;-)

Возможный подход к моей исходной задаче (ItemWriter хотел бы знать, работает ли он в режиме чанков или отдельных элементов), может быть одной из следующих альтернатив:


  • Только когда переданный кусок имеет размер один, любые дальнейшие проверки должны быть сделаны
  • Когда переданный кусок является java.util.Collections.SingletonListмы были бы совершенно уверены, так как FaultTolerantChunkProcessor делает следующее:

    Элементы списка = Collections.singletonList(outputIterator.next());

    К сожалению, этот класс является закрытым, поэтому мы не можем проверить его instanceOf,

  • И наоборот, если кусок является ArrayList мы могли бы также быть совершенно уверены, так как Весенняя партия Chunk класс использует это:

    private List items = new ArrayList ();

  • Одно размытие слева будет буферизованными элементами, считанными из контекста выполнения. Но я ожидаю, что они также будут ArrayLists.

Во всяком случае, я все еще нахожу этот метод слишком расплывчатым. Я бы предпочел, чтобы эта информация была предоставлена ​​структурой.


Альтернативой будет зацепить мой ItemWriter в рамках исполнения. Может быть ItemWriteListener.onWriteError() является целесообразным.

Обновление: onWriteError() метод не будет вызываться, если вы работаете в режиме одного элемента и выбрасываете исключение в ItemWriter, Я думаю, что это ошибка, поданная это: https://jira.springsource.org/browse/BATCH-2027

Так что эта альтернатива выпадает.


Вот фрагмент, чтобы сделать то же самое без каких-либо рамочных средств непосредственно в писателе

    private int writeErrorCount = 0;

@Override
public void write(final List<? extends Long> items) throws Exception {
    try {
        writeWhatever(items);
    } catch (final Exception e) {
        if (this.writeErrorCount == 0) {
            this.writeErrorCount = items.size();
        } else {
            this.writeErrorCount--;
        }

        throw e;
    }
    this.writeErrorCount--;
}

public boolean isWriterInSingleItemMode() {
    return writeErrorCount != 0;
}

Внимание: здесь лучше проверить пропускаемые исключения, а не Exception в общем.

Другие вопросы по тегам