在 Spring Batch 中,我希望实现重试机制。我在下面配置了步骤
此批处理作业实际上运行并创建Payment 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:
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>
如何从XYZListener调用重试机制,即ABCTasklet类?代码更新将受到赞赏
EDIT-1 我在下面做了,但似乎没有用吗?
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