Spring批处理远程分区—有时主步骤在所有分区步骤完成之前完成

Spring批处理远程分区—有时主步骤在所有分区步骤完成之前完成,spring,spring-integration,spring-batch,Spring,Spring Integration,Spring Batch,我遇到了Spring批处理远程分区作业的一个问题,其中主步骤在所有分区从步骤完成之前完成。在主步骤在所有分区步骤完成后的大部分时间内,这种情况都是随机发生的。 如果配置中缺少任何内容,请告诉我 这是主作业配置 主JMS配置: 从-作业配置: 从JMS配置: 问题是什么?问题是-很多时候,主步骤并不总是在所有分区从步骤完成之前完成。这导致了我下一步的问题。你的前提毫无意义;对于您的配置,分区处理程序应该永远等待,直到聚合器将聚合的回复提交给replyChannel。aggregatedReplyC

我遇到了Spring批处理远程分区作业的一个问题,其中主步骤在所有分区从步骤完成之前完成。在主步骤在所有分区步骤完成后的大部分时间内,这种情况都是随机发生的。 如果配置中缺少任何内容,请告诉我

这是主作业配置

主JMS配置:

从-作业配置:

从JMS配置:


问题是什么?问题是-很多时候,主步骤并不总是在所有分区从步骤完成之前完成。这导致了我下一步的问题。你的前提毫无意义;对于您的配置,分区处理程序应该永远等待,直到聚合器将聚合的回复提交给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"/>