Spring批处理-从另一个具有重试机制的Tasklet调用Tasklet?

Spring批处理-从另一个具有重试机制的Tasklet调用Tasklet?,spring,spring-batch,spring-retry,Spring,Spring Batch,Spring Retry,在SpringBatch中,我希望实现重试机制。我在下面配置了步骤 此批处理作业实际上运行并创建支付csv文件,并将其放置到我的应用程序服务器的出站文件夹中,通过Tasklet我调用shellscript,该脚本拾取所有文件并将数据发送到其他服务器。当通过批处理作业执行shell脚本时,出现了一些故障,然后我需要实现重试机制 如何使用重试机制从另一个Tasklet调用Tasklet public class ABCTasklet implements Tasklet, InitializingB

在SpringBatch中,我希望实现重试机制。我在下面配置了步骤

此批处理作业实际上运行并创建支付csv文件,并将其放置到我的应用程序服务器的出站文件夹中,通过Tasklet我调用shellscript,该脚本拾取所有文件并将数据发送到其他服务器。当通过批处理作业执行shell脚本时,出现了一些故障,然后我需要实现重试机制

如何使用重试机制从另一个Tasklet调用Tasklet

public class ABCTasklet implements Tasklet, InitializingBean {

    @Value("${payment.directory}") // location where files are written - CSV
    private String location;

    @Override
    public RepeatStatus execute(StepContribution step, ChunkContext chunkContext) throws Exception {
        Set<String> payFileNames = new HashSet<>();
        List<FileDetails> fileStatusList = new ArrayList<>();

        File folder = new File(location);

        for (File file : folder.listFiles()) {
            FileDetails fileDetails = new FileDetails();
            fileDetails.setFileName(file.getName());
            fileDetails.setStatus(FileStatus.FAILURE.getStatus());
            fileStatusList.add(fileDetails);
            payFileNames.add(file.getName());
        }
        chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext().put("payFileNames", payFileNames);
        chunkContext.getStepContext().getStepExecution().getJobExecution().getExecutionContext().put("fileStatusList", fileStatusList);
        return RepeatStatus.FINISHED;
    }

    public String getLocation() {
        return location;
    }

    public void setLocation(String location) {
        this.location = location;
    }
}

不清楚为什么需要从另一个Tasklet调用一个Tasklet,但是可以显示用于调用的代码吗?然后,我们将能够看到是否有可能在其上添加重试。好的,我明白了。这不是从另一个微线程调用微线程。您可以做的是创建一个流,当XYZListener(它是一个tasklet,不是一个监听器,但命名由您决定)失败时指向ABCTasklet。我可以建议的另一个选项(因为我看到您希望在
XYZListener
中使用
RetryTemplate
)是包装在
RetryCallback
中可能失败的代码。请参见此处的示例:。您可能不需要重试模板。如果调用失败(并增加变量retryCount),则可以返回
RepeatStatus.CONTINUABLE
,如果超过重试计数,则抛出异常。但是我建议创建一个执行流,并在失败时重新执行相应的步骤。@@Mahmoud Ben Hassine-我上面实现的上述逻辑执行了无限次,不确定为什么会发生这种情况。请尽快指导好吗?每次返回
RepeatStatus时,都会重新执行tasklet。可继续执行
,直到返回
RepeatStatus。完成
表示成功或抛出异常表示失败:在您的情况下,您可以在tasklet实现中创建一个名为
retryCount
的计数器。当调用脚本失败时,递增计数器并返回
CONTINUABLE
。如果计数器超过最大重试次数,则抛出异常。否则,返回
FINISHED
。我仍然建议为您的用例创建一个流
public class XYZListener implements Tasklet {
    @Autowired
    private RetryTemplate retryTemplate;

    private ExecutionContext executionContext;
    public ExecutionContext getExecutionContext() {
        return executionContext;
    }
    public void setExecutionContext(ExecutionContext executionContext) {
        this.executionContext = executionContext;
    }

    @Override
    public RepeatStatus execute(StepContribution paramStepContribution,ChunkContext paramChunkContext) throws Exception {
        Set<String> paymentFileNames = new HashSet<>();
        if(null != executionContext && null != executionContext.get("paymentFileNames")) {
            paymentFileNames = (Set<String>) executionContext.get("paymentFileNames");
        }

        try {
            for(String payFileName : paymentFileNames) {
                int exitStatus = 1;
                if (payFileName != null) {
    // execute shell scripts
                    ProcessBuilder procBuilder = new ProcessBuilder("/bin/bash","paymentBatchFiles.sh", payFileName);

                    Map<String, String> env = procBuilder.environment();
                    env.put("PATH", "/usr/local/bin:/bin:XXXXXXXXXXXXXXXXXX"); // many linux env. variables
                    env.put("MAYMENT_HOME","/Deployment/PaymentData"); 
                    ....
                    .....// other needed env variables

                    Process proc = procBuilder.start();
                    BufferedReader br = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
                    exitStatus = proc.waitFor();
                }

                if (0 == exitStatus) {
                    paymentDetailsDAO.updateStatus(EDSProcessStatus.SENT.getStatusCode(), payFileName, JOB_NAME);
                }
                else {
                     // Implement Retry mechanism to call the ABCTasklet
                    retryTemplate.execute(); //TODO                  
                }
            }
            return RepeatStatus.FINISHED;
        } catch (InterruptedException | IOException ie) {

        }
    }
}
<batch:decision id="paymentDecision" decider="paymentDecider">
    <batch:next on="FAILURE" to="failureStep" />
    <batch:next on="SUCCESS" to="x" />
</batch:decision>

<batch:step id="x">
    <batch:tasklet ref="payTasklet" />
    <batch:next on="COMPLETED" to="step1" />
</batch:step>

<batch:step id="step1">
    <batch:tasklet>
        <batch:chunk reader="paymentReader" writer="paymentWriter" commit-interval="100">
            <batch:listeners>
                <batch:listener ref="XYZListener" />
            </batch:listeners>
        </batch:chunk>
    </batch:tasklet>
    <batch:next on="COMPLETED" to="sendPaymentBatchFiles" />
</batch:step>

<batch:step id="sendPaymentBatchFiles">
    <batch:tasklet ref="sendPaymentBatchFilesTasklet">
    </batch:tasklet>
    <batch:next on="COMPLETED" to="lastRunUpdate" />
</batch:step>

<batch:step id="lastRunUpdate" next="Z">
    <batch:tasklet ref="QQQQRunUpdater" />
</batch:step>


<batch:step id="Z">
    <batch:tasklet ref="PPTasklet" />
</batch:step>

<batch:step id="failureStep" next="sendPaymentBatchFiles">
    <batch:tasklet ref="ABCTasklet" />
</batch:step>
return retryTemplate.execute(new RetryCallback<RepeatStatus, RuntimeException>() {
    @Override
    public RepeatStatus doWithRetry(RetryContext context) {
        logger.info("Retry File, Retry Count = "+context.getRetryCount());
        return executeShellScript();
    }
});

Edit-2:

RepeatTemplate template = new RepeatTemplate();
template.setCompletionPolicy(new DefaultResultCompletionPolicy());

StringRepeatCallback callback = new StringRepeatCallback();
callback.setBillingFileNames(billingFileNames);
template.iterate(callback);
public class StringRepeatCallback implements RepeatCallback{
    @Autowired
    private PaymentFilesTasklet tasklet;

    private Set<String> paymentFileNames;

    public void setBillingFileNames(Set<String> paymentFileNames) {
        this.paymentFileNames = paymentFileNames;
    }

    @Override
    public RepeatStatus doInIteration(RepeatContext repeatContext) throws Exception {
        tasklet.executeShellScript(paymentFileNames);
        return RepeatStatus.CONTINUABLE;
    }
}
2018-07-22 13:12:28,287 ERROR [main] (AbstractStep.java:229) - Encountered an error executing step sendPaymentBatchFiles in job paymentBatchJob
java.lang.NullPointerException
        at com.mastercard.ess.eds.billing.callback.StringRepeatCallback.doInIteration(StringRepeatCallback.java:24)
        at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:374)
        at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)
        at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:144)
        at com.mastercard.ess.eds.billing.tasklet.SendBillingBatchFilesTasklet.executeShellScript(SendBillingBatchFilesTasklet.java:132)
        at com.mastercard.ess.eds.billing.tasklet.SendBillingBatchFilesTasklet.execute(SendBillingBatchFilesTasklet.java:152)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at org.springframework.aop.support.DelegatingIntroductionInterceptor.doProceed(DelegatingIntroductionInterceptor.java:133)
        at org.springframework.aop.support.DelegatingIntroductionInterceptor.invoke(DelegatingIntroductionInterceptor.java:121)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
        at com.sun.proxy.$Proxy44.execute(Unknown Source)
        at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:406)
        at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:330)
        at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133)
        at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:271)
        at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:81)
        at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:374)
        at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215)
        at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:144)
        at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:257)
        at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:200)
        at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148)
        at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:64)
        at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:67)
        at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:169)
        at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:144)
        at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:134)
        at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:306)
        at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:135)
        at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50)
        at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:128)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157)
        at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:127)
        at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
        at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
        at com.sun.proxy.$Proxy34.run(Unknown Source)
        at org.springframework.batch.core.launch.support.CommandLineJobRunner.start(CommandLineJobRunner.java:362)
        at org.springframework.batch.core.launch.support.CommandLineJobRunner.main(CommandLineJobRunner.java:592)
2018-07-22 13:12:28,459 ERROR [main] (AbstractJob.java:335) - Encountered fatal error executing job