如果使用spring集成在远程分区中不存在资源路径,那么Spring批处理中的MessageChannelPartitionHandler如何运行?

时间:2014-07-25 12:07:51

标签: spring batch-processing spring-batch spring-integration spring-batch-admin

我正在使用spring批量远程分区。以下是我的配置

<task:executor id="taskExecutor" pool-size="50" />

<rabbit:template id="computeAmqpTemplate"
    connection-factory="rabbitConnectionFactory" routing-key="computeQueue"
    reply-timeout="${compute.partition.timeout}">
</rabbit:template>

<int:channel id="computeOutboundChannel">
    <int:dispatcher task-executor="taskExecutor" />
</int:channel>

<int:channel id="computeInboundStagingChannel" />

<amqp:outbound-gateway request-channel="computeOutboundChannel"
    reply-channel="computeInboundStagingChannel" amqp-template="computeAmqpTemplate"
    mapped-request-headers="correlationId, sequenceNumber, sequenceSize, STANDARD_REQUEST_HEADERS"
    mapped-reply-headers="correlationId, sequenceNumber, sequenceSize, STANDARD_REQUEST_HEADERS" />


<beans:bean id="computeMessagingTemplate"
    class="org.springframework.integration.core.MessagingTemplate"
    p:defaultChannel-ref="computeOutboundChannel"
    p:receiveTimeout="${compute.partition.timeout}" />


<beans:bean id="computePartitionHandler"
    class="org.springframework.batch.integration.partition.MessageChannelPartitionHandler"
    p:stepName="computeStep" p:gridSize="${compute.grid.size}"
    p:messagingOperations-ref="computeMessagingTemplate" />

<int:aggregator ref="computePartitionHandler"
    send-partial-result-on-expiry="true" send-timeout="${compute.step.timeout}"
    input-channel="computeInboundStagingChannel" />

<amqp:inbound-gateway concurrent-consumers="${compute.consumer.concurrency}"
    request-channel="computeInboundChannel" 
    reply-channel="computeOutboundStagingChannel" queue-names="computeQueue"
    connection-factory="rabbitConnectionFactory"
    mapped-request-headers="correlationId, sequenceNumber, sequenceSize, STANDARD_REQUEST_HEADERS"
    mapped-reply-headers="correlationId, sequenceNumber, sequenceSize, STANDARD_REQUEST_HEADERS" />


<int:channel id="computeInboundChannel" />

<int:service-activator ref="stepExecutionRequestHandler"
    input-channel="computeInboundChannel" output-channel="computeOutboundStagingChannel" />

<int:channel id="computeOutboundStagingChannel" />


<beans:bean id="computePartitioner"
    class="org.springframework.batch.core.partition.support.MultiResourcePartitioner"
    p:resources="file:${spring.tmp.batch.dir}/#{jobParameters[batch_id]}/shares_rics/shares_rics_*.txt"
    scope="step" />



<beans:bean id="computeFileItemReader"
    class="org.springframework.batch.item.file.FlatFileItemReader"
    p:resource="#{stepExecutionContext[fileName]}" p:lineMapper-ref="stLineMapper"
    scope="step" />

<beans:bean id="computeItemWriter"
    class="com.st.batch.foundation.writers.ComputeItemWriter"
    p:symfony-ref="symfonyStepScoped" p:timeout="${compute.item.timeout}"
    p:batchId="#{jobParameters[batch_id]}" scope="step" />


<step id="computeStep">
    <tasklet transaction-manager="transactionManager">
        <chunk reader="computeFileItemReader" writer="computeItemWriter"
            commit-interval="${compute.commit.interval}" />
    </tasklet>
</step>

<flow id="computeFlow">
    <step id="computeStep.master">
        <partition partitioner="computePartitioner"
            handler="computePartitionHandler" />
    </step>
</flow>

<job id="computeJob" restartable="true">
    <flow id="computeJob.computeFlow" parent="computeFlow" />
</job>

问题是,在multiresouce分区器中,我将模式传递给查找文件并创建等于文件数的分区。但是该目录是在运行时和有条件地创建的。

如果目录不存在(输入文件不可用),我希望此步骤成功,然后继续下一步。

现在,工作只是挂起,做任何事情。它既不会认为步骤成功也不会引发异常,所以甚至都不会失败。它只是在这一步变得空闲。

<beans:bean id="computePartitioner"
    class="org.springframework.batch.core.partition.support.MultiResourcePartitioner"
    p:resources="file:${spring.tmp.batch.dir}/#{jobParameters[batch_id]}/shares_rics/shares_rics_*.txt"
    scope="step" />

有没有办法解决这个问题?我只想把这一步视为成功,并考虑下一步。

Upate:

刚刚使用创建分区步骤进行测试,该步骤在本地服务器而不是远程服务器上运行,如果文件不存在,则默认情况下将步骤标记为已完成。所以问题不在于MultiResourcePartitioner,当我们使用分区步骤在具有上述配置的远程服务器上运行时会出现问题。

我想,即使没有发送步骤执行消息,它的聚合逻辑仍在等待响应?是否由于默认的SequenceSizeReleaseStrategy依赖于IntegrationMessageHeaderAccessor.SEQUENCE_SIZE标头属性,并且因为所有聚合器都没有消息无法访问SEQUENCE_SIZE?

@MessageEndpoint
public class MessageChannelPartitionHandler implements PartitionHandler {


    public Collection<StepExecution> handle(StepExecutionSplitter stepExecutionSplitter,
            StepExecution masterStepExecution) throws Exception {

        Set<StepExecution> split = stepExecutionSplitter.split(masterStepExecution, gridSize);
        int count = 0;

        if (replyChannel == null) {
            replyChannel = new QueueChannel();
        }//end if 

        for (StepExecution stepExecution : split) {
            Message<StepExecutionRequest> request = createMessage(count++, split.size(), new StepExecutionRequest(
                    stepName, stepExecution.getJobExecutionId(), stepExecution.getId()), replyChannel);
            if (logger.isDebugEnabled()) {
                logger.debug("Sending request: " + request);
            }
            messagingGateway.send(request);
        }

        Message<Collection<StepExecution>> message = messagingGateway.receive(replyChannel);
        if (logger.isDebugEnabled()) {
            logger.debug("Received replies: " + message);
        }
        Collection<StepExecution> result = message.getPayload();
        return result;

    }

    private Message<StepExecutionRequest> createMessage(int sequenceNumber, int sequenceSize,
            StepExecutionRequest stepExecutionRequest, PollableChannel replyChannel) {
        return MessageBuilder.withPayload(stepExecutionRequest).setSequenceNumber(sequenceNumber)
                .setSequenceSize(sequenceSize)
                .setCorrelationId(stepExecutionRequest.getJobExecutionId() + ":" + stepExecutionRequest.getStepName())
                .setReplyChannel(replyChannel)
                .build();
    }
}

如果没有步骤执行请求,即拆分计数为0,那么它不会进入forloop,因此不会发送任何消息,但仍然在for循环后它将等待接收响应。 可能是什么解决方案?

2 个答案:

答案 0 :(得分:1)

使用decider检查目录并返回CONTINUE或SKIP(或您想要的任何其他有意义的值)

答案 1 :(得分:0)

我在Spring批量跟踪器Jira https://jira.spring.io/browse/BATCH-2283上提出了问题。

它与MessageChannelPartitionHandler的问题,目前尚未处理此方案。临时修复是覆盖MessageChannelPartitionHandler.handle,检查消息集的大小,并按上面提出的票证中的建议返回NULL。

这个方法应该如何,它对我有用。

public Collection<StepExecution> handle(StepExecutionSplitter stepExecutionSplitter,
            StepExecution masterStepExecution) throws Exception {

        Set<StepExecution> split = stepExecutionSplitter.split(masterStepExecution, gridSize);

        if(split.size() == 0) {
            return null;
        }

        int count = 0;

        if (replyChannel == null) {
            replyChannel = new QueueChannel();
        }//end if 

        for (StepExecution stepExecution : split) {
            Message<StepExecutionRequest> request = createMessage(count++, split.size(), new StepExecutionRequest(
                    stepName, stepExecution.getJobExecutionId(), stepExecution.getId()), replyChannel);
            if (logger.isDebugEnabled()) {
                logger.debug("Sending request: " + request);
            }
            messagingGateway.send(request);
        }

        if (logger.isDebugEnabled()) {
            logger.debug("No message sent but waiting for reply: ");
        }

        Message<Collection<StepExecution>> message = messagingGateway.receive(replyChannel);
        if (logger.isDebugEnabled()) {
            logger.debug("Received replies: " + message);
        }
        Collection<StepExecution> result = message.getPayload();
        return result;

    }