2013-05-01 6 views
2

TL; DR: Как создать Spring Batch Jobs с использованием Spring Batch Job? Сделка транзакций, по-видимому, является проблемой. Это, кажется, классический вопрос, но вот он снова:Использование весенних партий или запуск рабочих мест в задании

У меня следующий прецедент: мне нужно опросить FTP-сервер и зарегистрировать найденные XML-файлы в виде блоба в базе данных. XML имеет 0 ... N интересующих записей I необходимо отправить во внешнюю веб-службу и сохранить ответ . Ответы могут быть нерешаемыми или повторными, и мне нужно, чтобы хранит каждый запрос и их ответы для целей аудита.

Модель домена/JPA выглядит следующим образом: Batch (содержит XML blob) содержит 0-N объектов BatchRow. BatchRow содержит данные, которые должны быть отправлены в службу сервиса , а также содержит 1 ... N объектов BatchRowHistory, имеющих статус информацию о вызовах веб-сервисов.

Меня попросили реализовать это с использованием Spring Batch (Spring Integration , возможно, была другая возможность с момента интеграции). Теперь Я боролся с разными подходами, и я нахожу эту задачу намного более сложной и потому сложной, как это должно быть ИМХО.

я разделить задачи на следующие рабочие места:

Job1:

  • Step11: Fetch файл и хранить в базе данных в виде сгустка.

  • Шаг 12: Разделите XML на записи и сохраните эти записи в db.

  • Step13: Создать Job2 и запустить его для каждой записи, хранящейся в Шаг12. Марк Job2 создал флаг в базе данных домена для записей.

Job2:

  • Step21: Вызов веб-службы для каждой записи и хранения результата в БД. Здесь повторяется повторная попытка и . Для типов Job2 необходимо перезапустить вручную.

Логикой этой структуры является то, что Job1 запускается периодически запланировано (один раз в минуту). Job2 запускается всякий раз, когда есть этих Рабочих мест, и они либо преуспели, либо их лимит повторной попытки , и они потерпели неудачу. Модель домена сохраняет в основном только результаты и Spring Batch отвечает за запуск шоу. Ручные перезагрузки и т. Д. Могут обрабатываться через Spring Batch Admin (по крайней мере, я надеюсь, что так). Также Job2 имеет идентификатор BatchRow на карте JobParameters, поэтому он может быть просмотрен в Spring Batch Admin.

Вопрос 1: Имеет ли смысл эта структура работы? I.e. создавая новые Spring Batch Jobs для каждой строки в db, похоже, что это побеждает цель и заново изобретает колесо на некотором уровне?

Вопрос 2: Как создать эти записи Job2 в шаге 13?

я получил первые проблемы с сделкой и JobRepository но удался запустить несколько рабочих мест с последующей установкой:

<batch:step id="Step13" parent="stepParent"> 
<batch:tasklet> 
    <batch:transaction-attributes propagation="NEVER"/> 
    <batch:chunk reader="rowsWithoutJobReader" processor="batchJobCreator" writer="itemWriter" 
       commit-interval="10" /> 
</batch:tasklet> 
</batch:step> 

<bean id="stepParent" class="org.springframework.batch.core.step.item.FaultTolerantStepFactoryBean" abstract="true"/> 

Пожалуйста, обратите внимание, что совершить интервал = «10» означает, что это может создать до 10 рабочих мест в настоящее время и все ... потому что batchJobCreator вызывает метод JobLauncher.run, и он идет плавно, НО itemWriter не может пишет BatchRows обратно в базу данных с обновленной информацией (boolean jobCreated flag toggled on). Очевидной причиной этого является распространение.NEVER в транзакционных атрибутах, но без этого я не могу создавать задания с помощью jobLauncher.

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

org.springframework.batch.retry.RetryException: Non-skippable exception in recoverer while processing; nested exception is org.springframework.batch.core.repository.JobExecutionAlreadyRunningException: A job execution for this job is already running: JobInstance: id=1, version=0, JobParameters=[{batchRowId=71}], Job=[foo.bar] 
     at org.springframework.batch.core.step.item.FaultTolerantChunkProcessor$2.recover(FaultTolerantChunkProcessor.java:278) 
     at org.springframework.batch.retry.support.RetryTemplate.handleRetryExhausted(RetryTemplate.java:420) 
     at org.springframework.batch.retry.support.RetryTemplate.doExecute(RetryTemplate.java:289) 
     at org.springframework.batch.retry.support.RetryTemplate.execute(RetryTemplate.java:187) 
     at org.springframework.batch.core.step.item.BatchRetryTemplate.execute(BatchRetryTemplate.java:215) 
     at org.springframework.batch.core.step.item.FaultTolerantChunkProcessor.transform(FaultTolerantChunkProcessor.java:287) 
     at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:190) 
     at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:74) 
     at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:386) 
     at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:130) 
     at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:264) 
     at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:76) 
     at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:367) 
     at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:214) 
     at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:143) 
     at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:250) 
     at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:195) 
     at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:135) 
     at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:61) 
     at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:60) 
     at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:144) 
     at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:124) 
     at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:135) 
     at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:293) 
     at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:120) 
     at java.lang.Thread.run(Thread.java:680) 

Это означает, что работа уже была создана весной Batch и он пытается снова создайте эти файлы при последующих запусках этапа 13. I может обойти эту настройку, если флаг JobCreated равен true в Job2/Step21, но для меня это похоже на неприятный случай.

Вопрос 3: У меня было больше ориентированного на объект объекта; У меня была Spring Пакетные задания для сканирования доменных таблиц с использованием довольно сложных JPQL-запросов и JPAItemReaders. Проблема с этим подходом заключается в том, что не использует более тонкие функции Spring Batch. Логика истории и повтора - это проблема . Мне нужно запрограммировать логику повтора на запросы JPQL (например, если BatchRow имеет более 3 элементов BatchRowHistory , это не сработало и необходимо вручную пересмотреть). Должен ли я укусить пулю и продолжить этот подход вместо того, чтобы пытаться установить индивидуальное Весеннее пакетное задание для каждого вызова веб-службы?

Информация о программе если необходимо: Spring Batch 2.1.9, Hibernate 4.1.2, Spring 3.1.2, Java 6.

Заранее спасибо и извините за длинный рассказ, Тимо

Edit 1: Причина, почему я думаю, что мне нужно, чтобы породить новые рабочие места это:

  • Loop в то время как читатель возвращает нуль или исключение

  • Transaction начать

  • читателя - процессор - цикл автора для целых N строк

  • конца транзакции для размера партии N

Каждой запись не удался проблема; Я хочу, чтобы вручную перезагружались исполнения (только задания перезапускаются в Spring Batch Admin, правда?) Для каждой строки в пакете, чтобы я мог использовать Spring Batch Admin для просмотра неудачных заданий (с их параметрами задания которые содержат идентификаторы строк из домена db) и перезапускают их и т. д. Как это сделать выполнить этот вид поведения без нереста и сохранить историю домена db?

ответ

0

Хорошо, я ненавижу отвечать на вопросы ... но мне нужно что-то знать?

1) Если ваши входные файлы являются XML, почему вы не используете StaxEventItemReader на них и просто сохраняете свои записи на шаге 1?

2) Начиная вторую работу с шага !!!! я даже не знаю, должно ли это работать ... но IMO .. это пахнет ;-)

Почему вы просто не определяете другой шаг, который использует JdbcCursorItemReader, чтобы читать ваши записи и вызывать веб-службы в ItemProcessor, затем записать результат в базу данных?

Возможно, я не понимаю вашего требования создавать разные задания для каждого вызова веб-сервиса !!!

Я сделал что-то похожее на ваш прецеденту и это было сделано с помощью этого сценария:

Работа 1: шаг 1: чтение XML, процесс pojo-> домен OBJ, написать домен OBJ в БД

Работа 2: шага 1: прочитать OBJ из БДА, процесс = WS вызова, запись ответа в БД

Это было просто и работал очень хорошо (включая перезапускаемые и пропустить функции)

Надеется, что это поможет

Отношения

+0

Благодарим за отзыв. 1: Мне нужно сохранить исходный файл в db для аудита целей. StaxReader не может прочитать этот файл непосредственно из db afaik. 2: Да, это, кажется, проблема, которая не очень легко делается ;-) О вашей структуре: Job1 выглядит так же, как моя, кроме работы нерестовая часть. – tfriman

+0

Работа 2 примерно такая же, когда счастливая дорожка идет, когда нет проблем с IO. Поэтому, когда вызов WS преуспевает, он пишет ответ красиво на db. Когда возникают проблемы, ничто не получает , записанный в db, потому что транзакция откатывается. Как вы позаботились о повторной попытке, если сможете написать результат WS-вызова результат в базу данных? Пропуск элемента должен быть зарегистрирован в базе данных , вам удалось это сделать? Я знаю интерфейсы RetryListener и SkipListener, но позволяют ли они записывать записи (JPA) обратно в базу данных? – tfriman

Смежные вопросы