【发布时间】:2019-11-26 16:06:27
【问题描述】:
有没有办法使用 JSR 352 Batch API 实现以下逻辑? 我有一系列步骤,每个步骤都需要根据开始工作时已知的不同条件执行。 条件实体由外部系统提供。
public List<Steps> createStepSequence(ConditionsEntity conditions) {
if (conditions.isStep1Enabled()) {
steps.add(step1)
}
if (conditions.isStep2Enabled()) {
steps.add(step2)
}
if (conditions.isStep3Enabled()) {
steps.add(step3)
}
//many more ifs
return steps;
}
我的第一次尝试失败了,因为:com.ibm.jbatch.container.exception.BatchContainerRuntimeException:一个决定不能先于另一个决定。我在这里添加失败代码
<?xml version="1.0" encoding="UTF-8"?>
<job id="myJob" xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/jobXML_1_0.xsd" version="1.0">
<properties>
<property name="isExecuteStep2" value="false"/>
<property name="isExecuteStep3" value="false"/>
</properties>
<step id="step1" next="decider1">
<batchlet ref="myBatchlet1"/>
</step>
<decision id="decider1" ref="SkipNextStepDecider">
<properties>
<property name="isExecuteNextStep" value="#{jobProperties['isExecuteStep2']}"/>
</properties>
<next on="EXECUTE" to="step2"/>
<next on="SKIP" to="decider2"/>
</decision>
<step id="step2">
<batchlet ref="myBatchlet2"/>
</step>
<decision id="decider2" ref="SkipNextStepDecider">
<properties>
<property name="isExecuteNextStep" value="#{jobProperties['isExecuteStep3']}"/>
</properties>
<next on="EXECUTE" to="step3"/>
<end on="SKIP"/>
</decision>
<step id="step3">
<batchlet ref="myBatchlet3"/>
</step>
</job>
@Named
public class SkipNextStepDecider implements Decider {
@Inject
@BatchProperty
private String isExecuteNextStep;
@Override
public String decide(StepExecution[] ses) throws Exception {
if (isExecuteNextStep.equalsIgnoreCase("true")) {
return "EXECUTE";
} else {
return "SKIP";
}
}
}
更新 我已经使用 passThroughStep 实现了以下建议的解决方案。它工作正常,但我仍然希望能够避免所有这些代码重复。
<?xml version="1.0" encoding="UTF-8"?>
<job id="decisionpoc" xmlns="http://xmlns.jcp.org/xml/ns/javaee" version="1.0">
<step id="dummy0" next="decider1">
<batchlet ref="dummyBatchlet"/>
</step>
<decision id="decider1" ref="skipNextStepDecider">
<properties>
<property name="condition" value="isExecuteStep1"/>
</properties>
<next on="EXECUTE" to="step1"/>
<next on="SKIP" to="dummy1"/>
</decision>
<step id="step1" next="decider2">
<batchlet ref="myBatchlet1"/>
</step>
<step id="dummy1" next="decider2">
<batchlet ref="dummyBatchlet"/>
</step>
<decision id="decider2" ref="skipNextStepDecider">
<properties>
<property name="condition" value="isExecuteStep2"/>
</properties>
<next on="EXECUTE" to="step2"/>
<next on="SKIP" to="dummy2"/>
</decision>
<step id="step2">
<batchlet ref="myBatchlet2"/>
</step>
<step id="dummy2" next="decider3">
<batchlet ref="dummyBatchlet"/>
</step>
<decision id="decider3" ref="skipNextStepDecider">
<properties>
<property name="condition" value="isExecuteStep3"/>
</properties>
<next on="EXECUTE" to="step3"/>
<end on="SKIP"/>
</decision>
<step id="step3">
<batchlet ref="myBatchlet3"/>
</step>
</job>
决定者
@Named
public class SkipNextStepDecider implements Decider {
@Inject
@BatchProperty
private String condition;
@Inject
private JobContext jobContext;
@Override
public String decide(StepExecution[] ses) throws Exception {
Properties parameters = getParameters();
String isExecuteNextStep = parameters.getProperty(condition);
if (isExecuteNextStep.equalsIgnoreCase("true")) {
return "EXECUTE";
} else {
return "SKIP";
}
}
private Properties getParameters() {
JobOperator operator = getJobOperator();
return operator.getParameters(jobContext.getExecutionId());
}
}
我的测试
public class DecisionPOCTest extends AbstractBatchLOT {
@Test
public void testProcess() throws Exception {
JobOperator jobOperator = getJobOperator();
Properties properties = new Properties();
properties.setProperty("isExecuteStep1", "true");
properties.setProperty("isExecuteStep2", "false");
properties.setProperty("isExecuteStep3", "true");
Long executionId = jobOperator.start("poc/decisionPOC", properties);
JobExecution jobExecution = jobOperator.getJobExecution(executionId);
jobExecution = BatchTestHelper.keepTestAlive(jobExecution);
List<StepExecution> stepExecutions = jobOperator.getStepExecutions(executionId);
List<String> executedSteps = new ArrayList<>();
for (StepExecution stepExecution : stepExecutions) {
executedSteps.add(stepExecution.getStepName());
}
assertEquals(COMPLETED, jobExecution.getBatchStatus());
assertEquals(4, stepExecutions.size());
assertArrayEquals(new String[]{"dummy0", "step1", "dummy2", "step3"}, executedSteps.toArray());
assertFalse(executedSteps.contains("step2"));
}
}
【问题讨论】:
-
我正在使用 Websphere Liberty。我只是注意到这可能是相关的,因为规范说应该可以从一个决定转到另一个决定。
-
是的,这是相关的。请针对 Open Liberty(我正在研究)提出一个问题:github.com/openliberty/open-liberty/issues。
-
我没有意识到我们有一个规范声明来支持这应该是可能的概念(@cheng 通过引用这个...在 Decider javadoc (jakarta.ee/specifications/platform/8/apidocs/javax/batch/api/…) 并注意到“从决策过渡”的情况没有描述。如果它在规范中,我认为我们可以支持向 Open Liberty 添加功能的情况。我们应该仔细考虑关于 StepExecution 是否通过。
-
@ScottKurz 我已经添加了问题:github.com/OpenLiberty/open-liberty/issues/10102
标签: jakarta-ee batch-processing jsr352 java-batch jbatch