Good Afernoon,
I tried to reproduce this behavior with the sample project I attached to this issue. The process is like this:
You will see that tskServiceTask has asyncBefore = true, because I don’t want it to continue if there is a technical error, in this case I want it to avoid retries (R0/PT5M) and stop it at the beginning of tskServiceTask until I decide to resolve the incident I created.
Inside you’ll find a SimpleTestCase and MyTaskDelegate. Inside this delegate I simulate a non-business error (i.e. a technical error) and then I catch it and create an incident. I’ve tried two ways to create it:
1.- creating an IncidentContext and creating it…
IncidentContext context = new IncidentContext();
context.setActivityId(execution.getCurrentActivityId());
context.setExecutionId(execution.getProcessInstanceId());
context.setProcessDefinitionId(execution.getProcessDefinitionId());
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
IncidentEntity newIncident
= IncidentEntity.createAndInsertIncident(
IncidentEntity.FAILED_JOB_HANDLER_TYPE,
context,
sw.toString()
);
This leads to the following error (I trimmed it since it’s too long):
INFO: ENGINE-14018 JobExecutor[org.camunda.bpm.engine.impl.jobexecutor.DefaultJobExecutor] starting to acquire jobs
oct 31, 2018 5:24:34 PM org.slf4j.impl.JCLLoggerAdapter error
SEVERE: ENGINE-16004 Exception while closing command context: ENGINE-03083 Exception while executing Batch Database Operations with message ’
Error flushing statements. Cause: org.apache.ibatis.executor.BatchExecutorException: org.camunda.bpm.engine.impl.persistence.entity.HistoricIncidentEntity.insertHistoricIncidentEvent (batch index #2) failed. 1 prior sub executor(s) completed successfully, but will be rolled back. Cause: org.h2.jdbc.JdbcBatchUpdateException: Value too long for column “INCIDENT_MSG_ VARCHAR(4000)”: “STRINGDECODE('java.lang.ArithmeticException: / by zero\r\n\tat org.camunda.bpm.unittest.MyTaskDelegate.execute(MyTaskDelegate.ja… (11070)”; SQL statement:
insert into ACT_HI_INCIDENT (
ID_,
PROC_DEF_KEY_,
PROC_DEF_ID_,
…
2.- This single line to create an incident:
Incident incident = ProcessEngineTests.runtimeService().createIncident(“foo”, execution.getProcessInstanceId(), “tskServiceTask”, e.getMessage());
In this case I get the following error:
org.camunda.bpm.engine.BadUserRequestException: Execution must be related to an activity: activity is null
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
at java.lang.reflect.Constructor.newInstance(Constructor.java:526)
How can I get the issue created the right way, without these two additional errors, and at the same time get the process flow stuck at the beginning of tskServiceTask until I decide to resolve that incident?
At the incident I’d like to appear as stacktrace just the error that caused it (/ by zero).
Thanks in advance,
Best regards
Alfonso.testProcess.bpmn (5.8 KB)
MyTaskDelegate.java
@Named(“myTaskDelegate”)
public class MyTaskDelegate implements JavaDelegate {
@Override
public void execute(DelegateExecution execution)
throws Exception {
try {
// simulate technical error
int i = 1 / 0;
} catch (Exception e) {
boolean createIncidentTheSimpleWay = true;
if (createIncidentTheSimpleWay) {
Incident incident = ProcessEngineTests.runtimeService().createIncident("foo", execution.getProcessInstanceId(), "tskServiceTask", e.getMessage());
int n = 0; // Just to stop breakpoint and inspect incident
} else {
IncidentContext context = new IncidentContext();
context.setActivityId(execution.getCurrentActivityId());
context.setExecutionId(execution.getProcessInstanceId());
context.setProcessDefinitionId(execution.getProcessDefinitionId());
StringWriter sw = new StringWriter();
e.printStackTrace(new PrintWriter(sw));
IncidentEntity newIncident
= IncidentEntity.createAndInsertIncident(
IncidentEntity.FAILED_JOB_HANDLER_TYPE,
context,
sw.toString()
);
}
}
}
}
SimpleTestCase.java
public class SimpleTestCase {
@Rule
public ProcessEngineRule rule = new ProcessEngineRule();
// @InjectMocks
// private final MyTaskDelegate myTaskDelegate = new MyTaskDelegate();
@Mock(name = "execution")
private DelegateExecution execution;
@Test
@Deployment(resources = {"testProcess.bpmn"})
public void shouldExecuteProcess()
throws Exception {
MockitoAnnotations.initMocks(this);
// Mockito.when(execution.getCurrentActivityId()).thenReturn("tskServiceTask");
MyTaskDelegate myTaskDelegate1 = new MyTaskDelegate();
Mocks.register("myTaskDelegate", myTaskDelegate1);
// Given we create a new process instance
ProcessInstance processInstance = runtimeService().startProcessInstanceByKey("testProcess");
/*
Incident incident = runtimeService().createIncident("foo", processInstance.getId(), "userTask1", "bar");
// when
runtimeService().resolveIncident(incident.getId());
*/
// then
Incident incident2 = runtimeService().createIncidentQuery().executionId(processInstance.getId()).singleResult();
assertNull(incident2);
// Then it should be active
assertThat(processInstance).isActive();
// And it should be the only instance
assertThat(processInstanceQuery().count()).isEqualTo(1);
// And there should exist just a single task within that process instance
// assertThat(task(processInstance)).isNotNull();
// When we complete that task
//complete(task(processInstance));
// Then the process instance should be ended
//assertThat(processInstance).isEnded();
}
}