Событие ошибки Граница изменяемой электронной почты не отслеживается
Я хотел бы BpmnError
быть брошенным, когда электронная почта не может быть отправлена по какой-либо причине, поэтому я могу обработать ее в потоке процесса.
Я заметил, что org.flowable.engine.impl.bpmn.behavior.MailActivityBehavior
бросает FlowableException
который не может быть пойман граничным событием, поэтому я сделал следующий класс:
@Slf4j
public class MailBpmnThrowingBehaviour extends MailActivityBehavior {
@Override
protected void handleException(final DelegateExecution execution, final String msg, final Exception e, final boolean doIgnoreException, final String exceptionVariable) {
if (doIgnoreException) {
log.info("Ignoring email send error: {}", msg, e);
if (exceptionVariable != null && exceptionVariable.length() > 0) {
execution.setVariable(exceptionVariable, msg);
}
} else {
if (e instanceof EmailException) {
throw new BpmnError("mailFailed", e.getMessage());
}
if (e instanceof FlowableException) {
throw (FlowableException) e;
} else {
throw new FlowableException(msg, e);
}
}
}
}
Единственная разница между моей реализацией и версией по умолчанию состоит в том, что я перебрасываю EmailException
как BpmnError
вместо FlowableException
,
Вот мой простой процесс для тестирования:
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns:flowable="http://flowable.org/bpmn" xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" targetNamespace="http://www.flowable.org/processdef">
<process id="MailErrorTest" name="MailErrorTest" isExecutable="true">
<startEvent id="start" name="start"/>
<sequenceFlow sourceRef="start" targetRef="pauseTask"/>
<userTask id="pauseTask" name="pauseTask"/>
<sequenceFlow sourceRef="pauseTask" targetRef="emailTask"/>
<serviceTask id="emailTask" name="emailTask" flowable:type="mail">
<extensionElements>
<flowable:field name="to">
<flowable:string><![CDATA[receiver@localhost]]></flowable:string>
</flowable:field>
<flowable:field name="from">
<flowable:string><![CDATA[sender@localhost]]></flowable:string>
</flowable:field>
<flowable:field name="subject">
<flowable:string><![CDATA[BPMN MailErrorTest]]></flowable:string>
</flowable:field>
<flowable:field name="text">
<flowable:string><![CDATA[Test...]]></flowable:string>
</flowable:field>
</extensionElements>
</serviceTask>
<sequenceFlow sourceRef="emailTask" targetRef="successEnd"/>
<endEvent id="successEnd" name="successEnd"/>
<boundaryEvent id="mailError" name="mailError" attachedToRef="emailTask">
<errorEventDefinition/>
</boundaryEvent>
<sequenceFlow sourceRef="mailError" targetRef="failEnd"/>
<endEvent id="failEnd" name="failEnd"/>
</process>
</definitions>
Визуализация:
pauseTask
служит точкой, где я могу убить почтовый сервер и возобновить процесс, чтобы он не сработал.
Вот упомянутый тест Spring Boot:
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {
ExampleApplication.class,
MailErrorTestConfiguration.class
})
public class MailErrorTest {
@Autowired
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
private ProcessEngine processEngine;
// this is a fake SMTP server
private Wiser wiser;
@Before
public void setUp() {
wiser = new Wiser();
wiser.start();
}
@After
public void tearDown() {
wiser.stop();
}
@Test
public void shouldSendEmailSuccessfully() {
assertThat(processEngine.getTaskService().createTaskQuery().list()).isEmpty();
final ProcessInstance processInstance = processEngine.getRuntimeService().startProcessInstanceByKey("MailErrorTest");
final Task pauseTask = processEngine.getTaskService().createTaskQuery().singleResult();
processEngine.getTaskService().complete(pauseTask.getId());
final HistoricProcessInstance historicProcessInstance = processEngine.getHistoryService().createHistoricProcessInstanceQuery()
.processInstanceId(processInstance.getProcessInstanceId())
.singleResult();
assertReceivedMessage(wiser)
.from("sender@localhost")
.to("receiver@localhost")
.withSubject("BPMN MailErrorTest")
.withContent("Test...");
assertThat(historicProcessInstance.getEndActivityId()).isEqualTo("successEnd");
}
@Test
public void shouldCatchEmailBoundaryErrorEvent() {
assertThat(processEngine.getTaskService().createTaskQuery().list()).isEmpty();
final ProcessInstance processInstance = processEngine.getRuntimeService().startProcessInstanceByKey("MailErrorTest");
final Task pauseTask = processEngine.getTaskService().createTaskQuery().singleResult();
// killing SMTP server to cause sending error
wiser.stop();
processEngine.getTaskService().complete(pauseTask.getId());
final HistoricProcessInstance historicProcessInstance = processEngine.getHistoryService().createHistoricProcessInstanceQuery()
.processInstanceId(processInstance.getProcessInstanceId())
.singleResult();
assertThat(historicProcessInstance.getEndActivityId()).isEqualTo("failEnd");
}
@Configuration
public static class MailErrorTestConfiguration implements EngineConfigurationConfigurer<SpringProcessEngineConfiguration> {
@Override
public void configure(final SpringProcessEngineConfiguration engineConfiguration) {
engineConfiguration.setActivityBehaviorFactory(new CustomActivityBehaviorFactory());
}
}
}
CustomActivityBehaviorFactory
также почти как по умолчанию, с той лишь разницей, что я возвращаю MailActivityBehaviour
вместо значения по умолчанию:
public class CustomActivityBehaviorFactory extends DefaultActivityBehaviorFactory {
@Override
protected MailActivityBehavior createMailActivityBehavior(final String taskId, final List<FieldExtension> fields) {
final List<FieldDeclaration> fieldDeclarations = createFieldDeclarations(fields);
return (MailBpmnThrowingBehaviour) ClassDelegate.defaultInstantiateDelegate(MailBpmnThrowingBehaviour.class, fieldDeclarations);
}
}
Первый тест работает, как и ожидалось, когда почтовый сервер работает, процесс завершается, как и ожидалось. Тем не менее, второй тест не работает, как я ожидал, BpmnError
граничное событие не перехватывается, исключение выдается до конца и тест не пройден.
Может кто-нибудь помочь мне понять, что я делаю не так? Почему граничное событие не ловит BpmnError
? Есть ли более чистое решение для перехвата исключений MailTask?