Spring批处理远程分区—有时主步骤在所有分区步骤完成之前完成
我遇到了Spring批处理远程分区作业的一个问题,其中主步骤在所有分区从步骤完成之前完成。在主步骤在所有分区步骤完成后的大部分时间内,这种情况都是随机发生的。 如果配置中缺少任何内容,请告诉我 这是主作业配置 主JMS配置: 从-作业配置: 从JMS配置:Spring批处理远程分区—有时主步骤在所有分区步骤完成之前完成,spring,spring-integration,spring-batch,Spring,Spring Integration,Spring Batch,我遇到了Spring批处理远程分区作业的一个问题,其中主步骤在所有分区从步骤完成之前完成。在主步骤在所有分区步骤完成后的大部分时间内,这种情况都是随机发生的。 如果配置中缺少任何内容,请告诉我 这是主作业配置 主JMS配置: 从-作业配置: 从JMS配置: 问题是什么?问题是-很多时候,主步骤并不总是在所有分区从步骤完成之前完成。这导致了我下一步的问题。你的前提毫无意义;对于您的配置,分区处理程序应该永远等待,直到聚合器将聚合的回复提交给replyChannel。aggregatedReplyC
问题是什么?问题是-很多时候,主步骤并不总是在所有分区从步骤完成之前完成。这导致了我下一步的问题。你的前提毫无意义;对于您的配置,分区处理程序应该永远等待,直到聚合器将聚合的回复提交给replyChannel。aggregatedReplyChannel上没有接收超时。我建议您打开调试日志并观察消息流。感谢Gary的建议。我的主配置有一个错误,我已将其更新并删除了消息驱动通道适配器的auto start=false属性。我遇到的另一个问题是,有时只有少数从机执行从机步骤,但仍有步骤要完成,并且空闲的从机进程可用。感谢你对这件事的想法。
@Autowired
private MessageChannel requestsChannel;
@Autowired
private PollableChannel aggregatedReplyChannel;
@Bean
public JobExecutionListener listener() {
return new RadJobExecutionListener();
}
@Bean
public Job RadItemProcessingJob() {
return jobBuilderFactory.get("radItemProcessingJob")
.incrementer(new RunIdIncrementer())
.listener(listener())
.start(processRadItems_master()).next(updateSetStatusStep())
.build();
}
@Bean
public Tasklet noopTaskLet() {
return new NoopTasklet();
}
@Bean
public Tasklet updateSetStatusStepTasklet() {
return new UpdateSetStatus();
}
@Bean
public Step processRadItems() {
return stepBuilderFactory.get("processRadItems")
.tasklet(noopTaskLet())
.build();
}
@Bean
public Partitioner moduloPartitioner() {
return new ModuloPartitioner();
}
@Bean
public PartitionHandler partitionHandler() {
return createPartitionHandler("processRadItems",
gridSize,
requestsChannel,
aggregatedReplyChannel
);
}
public PartitionHandler createPartitionHandler(String stepName,
int gridSize,
MessageChannel requestChannel,
PollableChannel replyChannel) {
MessageChannelPartitionHandler partitionHandler = new MessageChannelPartitionHandler();
partitionHandler.setStepName(stepName);
partitionHandler.setGridSize(gridSize);
partitionHandler.setReplyChannel(replyChannel);
MessagingTemplate messagingTemplate = new MessagingTemplate(requestChannel);
partitionHandler.setMessagingOperations(messagingTemplate);
return partitionHandler;
}
@Bean Step processRadItems_master() {
return stepBuilderFactory.get("processRadItems.master")
.partitioner("processRadItem",moduloPartitioner())
.partitionHandler(partitionHandler())
.build();
}
@Bean Step updateSetStatusStep() {
return stepBuilderFactory.get("updateSetStatusStep")
.tasklet(updateSetStatusStepTasklet())
.build();
}
@Bean
JobLauncher jobLauncher() {
TaskExecutor taskExecutor = new SimpleAsyncTaskExecutor();
SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
simpleJobLauncher.setTaskExecutor(taskExecutor);
simpleJobLauncher.setJobRepository(jobRepository);
return simpleJobLauncher;
}
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="${activemq.url}"/>
<property name="userName" value="${activemq.userName}"/>
<property name="password" value="${activemq.password}"/>
</bean>
<int:channel id="requestsChannel"/>
<int-jms:outbound-channel-adapter connection-factory="connectionFactory"
channel="requestsChannel"
destination-name="${activemq.requestQueue}"/>
<int:channel id="replyChannel"/>
<int-jms:message-driven-channel-adapter connection-factory="connectionFactory"
channel="replyChannel"
destination-name="${activemq.replyQueue}"/>
<int:channel id="aggregatedReplyChannel">
<int:queue/>
</int:channel>
<int:aggregator ref="partitionHandler"
input-channel="replyChannel"
output-channel="aggregatedReplyChannel"
send-timeout="86420000"/>
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
private DataSource raddAppDataSource;
@Autowired
private PlatformTransactionManager transactionManager;
@Bean
public Step processRadItems() {
final TaskletStep step = stepBuilderFactory.get("processRadItems")
.<RadItem,RadItem>chunk(1)
.reader(pagingItemReader(null,null,null))
.processor(itemProcessor())
.writer(itemWriter())
.build();
step.setTransactionManager(transactionManager);
step.setStepExecutionListeners(new StepExecutionListener[]{radStepListener()});
return step;
}
@Bean
@StepScope
public RadItemProcessorJob itemProcessor() {
return new RadItemProcessorJob();
}
@Bean
public NoOpItemWriter itemWriter() {
return new NoOpItemWriter();
}
@Bean
public RadStepListener radStepListener() {
return new RadStepListener();
}
@Bean
@StepScope
public JdbcPagingItemReader pagingItemReader(@Value("#{stepExecutionContext['mod.divisor']}") Object modDivisor,
@Value("#{stepExecutionContext['mod.remainder']}") Object modRemainder,
@Value("#{jobParameters['setId']}") Long setId) {
final JdbcPagingItemReader pagingItemReader = new JdbcPagingItemReader();
pagingItemReader.setDataSource(raddAppDataSource);
final SqlPagingQueryProviderFactoryBean sqlFactoryBean = new SqlPagingQueryProviderFactoryBean();
sqlFactoryBean.setSelectClause("select rad_item_id, item_oid,coverage_start_date, coverage_end_date, item_status_code, rad_set_id, reprocess_type");
sqlFactoryBean.setFromClause("from rad_item");
sqlFactoryBean.setWhereClause("where rad_set_id = :setId and item_status_code in ('SELECTED','PROCESSED','REVIEWING') and mod(rad_item_id, :modDivisor) = :modRemainder");
sqlFactoryBean.setSortKey("rad_item_id");
sqlFactoryBean.setDataSource(raddAppDataSource);
try {
pagingItemReader.setQueryProvider(sqlFactoryBean.getObject());
} catch (Exception e) {
logger.error("Error creating pagingItemReader",e);
throw new RuntimeException(e);
}
initParameterValues(pagingItemReader, modDivisor, modRemainder, setId);
pagingItemReader.setPageSize(1);
pagingItemReader.setRowMapper(new RadItemRowMapper());
return pagingItemReader;
}
private void initParameterValues(JdbcPagingItemReader pagingItemReader, Object modDivisor, Object modRemainder, Long setId) {
final Map<String,Object> parameterValues = new HashMap<>();
parameterValues.put("modDivisor",modDivisor);
parameterValues.put("modRemainder",modRemainder);
parameterValues.put("setId",setId);
pagingItemReader.setParameterValues(parameterValues);
}
@Bean
public StepExecutionRequestHandler stepExecutionRequestHandler() {
final StepExecutionRequestHandler stepExecutionRequestHandler = new StepExecutionRequestHandler();
stepExecutionRequestHandler.setJobExplorer(jobExplorer());
stepExecutionRequestHandler.setStepLocator(stepLocator());
return stepExecutionRequestHandler;
}
@Bean
public JobExplorer jobExplorer() {
try {
final JobExplorerFactoryBean jobExplorerFactory = new JobExplorerFactoryBean();
jobExplorerFactory.setDataSource(raddAppDataSource);
jobExplorerFactory.afterPropertiesSet();
return jobExplorerFactory.getObject();
} catch (Exception e) {
logger.error("Error creating JobExplorer Bean",e);
throw new RuntimeException(e);
}
}
@Bean
public StepLocator stepLocator() {
return new BeanFactoryStepLocator();
}
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="${activemq.url}"/>
<property name="userName" value="${activemq.userName}"/>
<property name="password" value="${activemq.password}"/>
</bean>
<int:channel id="requestChannel"/>
<int-jms:message-driven-channel-adapter connection-factory="connectionFactory"
destination-name="${activemq.requestQueue}"
channel="requestChannel"/>
<int:channel id="replyChannel"/>
<int-jms:outbound-channel-adapter connection-factory="connectionFactory"
destination-name="${activemq.replyQueue}"
channel="replyChannel"/>
<int:service-activator input-channel="requestChannel"
output-channel="replyChannel"
ref="stepExecutionRequestHandler"/>