Skip to content

Commit 32631ed

Browse files
committed
chore(history): populate incident treepath
related to #431
1 parent 84ff0b6 commit 32631ed

File tree

4 files changed

+99
-25
lines changed

4 files changed

+99
-25
lines changed

data-migrator/core/src/main/java/io/camunda/migration/data/impl/history/migrator/IncidentMigrator.java

Lines changed: 37 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -81,18 +81,19 @@ public Long migrateTransactionally(HistoricIncident c7Incident) {
8181
if (shouldMigrate(c7IncidentId, HISTORY_INCIDENT)) {
8282
HistoryMigratorLogs.migratingHistoricIncident(c7IncidentId);
8383
var c7ProcessInstance = findProcessInstanceByC7Id(c7Incident.getProcessInstanceId());
84+
Long processInstanceKey = null;
85+
Long flowNodeInstanceKey = null;
8486

8587
var builder = new Builder();
8688
var processDefinitionKey = findProcessDefinitionKey(c7Incident.getProcessDefinitionId());
8789
builder.processDefinitionKey(processDefinitionKey);
8890
if (c7ProcessInstance != null) {
89-
var processInstanceKey = c7ProcessInstance.processInstanceKey();
91+
processInstanceKey = c7ProcessInstance.processInstanceKey();
9092
builder.processInstanceKey(processInstanceKey);
9193
if (processInstanceKey != null) {
92-
var flowNodeInstanceKey = findFlowNodeInstanceKey(c7Incident.getActivityId(), c7Incident.getProcessInstanceId());
94+
flowNodeInstanceKey = findFlowNodeInstanceKey(c7Incident.getActivityId(), c7Incident.getProcessInstanceId());
9395
builder.flowNodeInstanceKey(flowNodeInstanceKey);
94-
// .jobKey(jobDefinitionKey) // TODO when jobs are migrated
95-
96+
// .jobKey(jobDefinitionKey) // TODO when jobs are migrated
9697

9798
String c7RootProcessInstanceId = c7Incident.getRootProcessInstanceId();
9899
if (c7RootProcessInstanceId != null && isMigrated(c7RootProcessInstanceId, HISTORY_PROCESS_INSTANCE)) {
@@ -101,32 +102,34 @@ public Long migrateTransactionally(HistoricIncident c7Incident) {
101102
builder.rootProcessInstanceKey(rootProcessInstance.processInstanceKey());
102103
}
103104
}
105+
builder.treePath(generateTreePath(processInstanceKey, flowNodeInstanceKey));
104106
}
105107
}
106108

107109
IncidentDbModel dbModel = convert(C7Entity.of(c7Incident), builder);
108110

109-
if (dbModel.processDefinitionKey() == null) {
110-
throw new EntitySkippedException(c7Incident, SKIP_REASON_MISSING_PROCESS_DEFINITION);
111-
}
111+
if (dbModel.processDefinitionKey() == null) {
112+
throw new EntitySkippedException(c7Incident, SKIP_REASON_MISSING_PROCESS_DEFINITION);
113+
}
112114

113-
if (dbModel.processInstanceKey() == null) {
115+
if (dbModel.processInstanceKey() == null) {
114116
throw new EntitySkippedException(c7Incident, SKIP_REASON_MISSING_PROCESS_INSTANCE);
115-
}
117+
}
116118

117-
if (dbModel.rootProcessInstanceKey() == null) {
118-
throw new EntitySkippedException(c7Incident, SKIP_REASON_MISSING_ROOT_PROCESS_INSTANCE);
119-
}
119+
if (dbModel.rootProcessInstanceKey() == null) {
120+
throw new EntitySkippedException(c7Incident, SKIP_REASON_MISSING_ROOT_PROCESS_INSTANCE);
121+
}
120122

121-
if (dbModel.flowNodeInstanceKey() == null) {
122-
if (!c7Client.hasWaitingExecution(c7Incident.getProcessInstanceId(), c7Incident.getActivityId())) { // Activities on async before waiting state will not have a flow node instance key, but should not be skipped
123-
throw new EntitySkippedException(c7Incident, SKIP_REASON_MISSING_FLOW_NODE);
123+
if (dbModel.flowNodeInstanceKey() == null) {
124+
if (!c7Client.hasWaitingExecution(c7Incident.getProcessInstanceId(), c7Incident.getActivityId())) {
125+
// Activities on async before waiting state will not have a flow node instance key, but should not be skipped
126+
throw new EntitySkippedException(c7Incident, SKIP_REASON_MISSING_FLOW_NODE);
127+
}
124128
}
125-
}
126129

127-
if (dbModel.jobKey() == null) {
128-
// throw new EntitySkippedException(c7Incident, SKIP_REASON_MISSING_JOB_REFERENCE); // TODO when jobs are migrated
129-
}
130+
if (dbModel.jobKey() == null) {
131+
// throw new EntitySkippedException(c7Incident, SKIP_REASON_MISSING_JOB_REFERENCE); // TODO when jobs are migrated
132+
}
130133
c8Client.insertIncident(dbModel);
131134

132135
return dbModel.incidentKey();
@@ -141,11 +144,9 @@ protected Long findFlowNodeInstanceKey(String activityId, String processInstance
141144
return null;
142145
}
143146

144-
List<FlowNodeInstanceDbModel> flowNodes = c8Client.searchFlowNodeInstances(
145-
FlowNodeInstanceDbQuery.of(builder -> builder.filter(
146-
FlowNodeInstanceFilter.of(filter -> filter.flowNodeIds(activityId).processInstanceKeys(processInstanceKey))
147-
))
148-
);
147+
List<FlowNodeInstanceDbModel> flowNodes = c8Client.searchFlowNodeInstances(FlowNodeInstanceDbQuery.of(
148+
builder -> builder.filter(FlowNodeInstanceFilter.of(
149+
filter -> filter.flowNodeIds(activityId).processInstanceKeys(processInstanceKey)))));
149150

150151
if (!flowNodes.isEmpty()) {
151152
return flowNodes.getFirst().flowNodeInstanceKey();
@@ -154,5 +155,17 @@ protected Long findFlowNodeInstanceKey(String activityId, String processInstance
154155
}
155156
}
156157

158+
/**
159+
* Generates a tree path for incidents in the format: processInstanceKey/elementInstanceKey (if exists)
160+
*
161+
* @param processInstanceKey the process instance key
162+
* @param elementInstanceKey the flow node instance key
163+
* @return the tree path string
164+
*/
165+
public static String generateTreePath(Long processInstanceKey, Long elementInstanceKey) {
166+
return elementInstanceKey == null ?
167+
"PI_" + processInstanceKey.toString() :
168+
"PI_" + processInstanceKey + "/FNI_" + elementInstanceKey;
169+
}
157170
}
158171

data-migrator/core/src/main/java/io/camunda/migration/data/impl/interceptor/history/entity/IncidentTransformer.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ public void execute(HistoricIncident entity, Builder builder) {
4747
.errorType(determineErrorType(entity))
4848
.errorMessage(entity.getIncidentMessage())
4949
.creationDate(convertDate(entity.getCreateTime()))
50-
.treePath(null)
5150
.errorMessageHash(null)
5251
.partitionId(C7_HISTORY_PARTITION_ID)
5352
.jobKey(null)

data-migrator/qa/integration-tests/src/test/java/io/camunda/migration/data/qa/history/HistoryMigrationAbstractTest.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import io.camunda.db.rdbms.sql.FlowNodeInstanceMapper;
2222
import io.camunda.db.rdbms.sql.PurgeMapper;
2323
import io.camunda.db.rdbms.write.domain.FlowNodeInstanceDbModel;
24+
import io.camunda.db.rdbms.write.domain.IncidentDbModel;
2425
import io.camunda.db.rdbms.write.service.RdbmsPurger;
2526
import io.camunda.migration.data.HistoryMigrator;
2627
import io.camunda.migration.data.MigratorMode;
@@ -29,6 +30,7 @@
2930
import io.camunda.migration.data.impl.clients.DbClient;
3031
import io.camunda.migration.data.impl.util.ConverterUtil;
3132
import io.camunda.migration.data.qa.AbstractMigratorTest;
33+
import io.camunda.migration.data.qa.extension.RdbmsQueryExtension;
3234
import io.camunda.migration.data.qa.util.WithSpringProfile;
3335
import io.camunda.search.entities.AuditLogEntity;
3436
import io.camunda.search.entities.DecisionDefinitionEntity;
@@ -64,6 +66,7 @@
6466
import org.camunda.bpm.engine.impl.util.ClockUtil;
6567
import org.camunda.bpm.engine.task.Task;
6668
import org.junit.jupiter.api.AfterEach;
69+
import org.junit.jupiter.api.extension.RegisterExtension;
6770
import org.springframework.beans.factory.annotation.Autowired;
6871
import org.springframework.context.annotation.Bean;
6972
import org.springframework.context.annotation.Conditional;
@@ -93,6 +96,10 @@ public abstract class HistoryMigrationAbstractTest extends AbstractMigratorTest
9396
@Autowired
9497
protected FlowNodeInstanceMapper flowNodeInstanceMapper;
9598

99+
@RegisterExtension
100+
@Autowired
101+
protected RdbmsQueryExtension rdbmsQuery = new RdbmsQueryExtension();
102+
96103
// C7 ---------------------------------------
97104

98105
@Autowired
@@ -232,6 +239,21 @@ public List<IncidentEntity> searchHistoricIncidents(String processDefinitionId)
232239
.items();
233240
}
234241

242+
// TODO
243+
public List<IncidentDbModel> searchIncidentsByProcessInstanceKeyAndReturnAsDbModel(Long processInstanceKey) {
244+
String sql = "SELECT INCIDENT_KEY, TREE_PATH, PROCESS_INSTANCE_KEY, FLOW_NODE_INSTANCE_KEY " +
245+
"FROM INCIDENT WHERE PROCESS_INSTANCE_KEY = ?";
246+
247+
return rdbmsQuery.query(sql, (rs, rowNum) -> {
248+
IncidentDbModel.Builder builder = new IncidentDbModel.Builder();
249+
builder.incidentKey(rs.getLong("INCIDENT_KEY"));
250+
builder.treePath(rs.getString("TREE_PATH"));
251+
builder.processInstanceKey(rs.getLong("PROCESS_INSTANCE_KEY"));
252+
builder.flowNodeInstanceKey(rs.getLong("FLOW_NODE_INSTANCE_KEY"));
253+
return builder.build();
254+
}, processInstanceKey);
255+
}
256+
235257
public List<VariableEntity> searchHistoricVariables(String varName) {
236258
return rdbmsService.getVariableReader()
237259
.search(VariableQuery.of(queryBuilder ->

data-migrator/qa/integration-tests/src/test/java/io/camunda/migration/data/qa/history/entity/HistoryIncidentTest.java

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,19 @@
1616
import static io.camunda.search.entities.IncidentEntity.ErrorType.RESOURCE_NOT_FOUND;
1717
import static io.camunda.search.entities.IncidentEntity.ErrorType.UNHANDLED_ERROR_EVENT;
1818
import static io.camunda.search.entities.IncidentEntity.ErrorType.UNKNOWN;
19+
import static io.camunda.search.entities.FlowNodeInstanceEntity.FlowNodeType.END_EVENT;
20+
import static io.camunda.search.entities.FlowNodeInstanceEntity.FlowNodeType.START_EVENT;
21+
import static io.camunda.search.entities.FlowNodeInstanceEntity.FlowNodeType.USER_TASK;
1922
import static org.assertj.core.api.Assertions.assertThat;
2023

24+
import io.camunda.db.rdbms.write.domain.FlowNodeInstanceDbModel;
25+
import io.camunda.db.rdbms.write.domain.IncidentDbModel;
2126
import io.camunda.migration.data.MigratorMode;
2227
import io.camunda.migration.data.qa.history.HistoryMigrationAbstractTest;
28+
import io.camunda.search.entities.FlowNodeInstanceEntity;
2329
import io.camunda.search.entities.IncidentEntity;
2430
import java.util.Collections;
31+
import io.camunda.search.entities.ProcessInstanceEntity;
2532
import java.util.List;
2633
import org.camunda.bpm.engine.history.HistoricIncident;
2734
import org.camunda.bpm.engine.impl.cfg.ProcessEngineConfigurationImpl;
@@ -368,6 +375,39 @@ public void shouldMigrateIncidentWithNoJobRetriesErrorType() {
368375
assertOnIncidentBasicFields(c8Incident, c7Incident, c7ProcessInstance, null, JOB_NO_RETRIES, true);
369376
}
370377

378+
@Test
379+
public void shouldGenerateTreePathForIncidents() {
380+
// given
381+
deployer.deployCamunda7Process("userTaskProcessAsyncAfter.bpmn");
382+
ProcessInstance c7ProcessInstance = runtimeService.startProcessInstanceByKey("userTaskProcessId");
383+
384+
createIncident("userTaskId");
385+
String userTaskId = taskService.createTaskQuery().taskDefinitionKey("userTaskId").singleResult().getId();
386+
taskService.complete(userTaskId);
387+
388+
HistoricIncident c7Incident = historyService.createHistoricIncidentQuery()
389+
.processInstanceId(c7ProcessInstance.getId())
390+
.singleResult();
391+
assertThat(c7Incident).isNotNull();
392+
393+
// when
394+
historyMigrator.migrate();
395+
396+
// then
397+
List<ProcessInstanceEntity> processInstances = searchHistoricProcessInstances("userTaskProcessId");
398+
assertThat(processInstances).hasSize(1);
399+
Long processInstanceKey = processInstances.getFirst().processInstanceKey();
400+
List<FlowNodeInstanceDbModel> flowNodes = searchFlowNodeInstancesByName("UserTaskName");
401+
assertThat(flowNodes).hasSize(1);
402+
Long flownodeInstanceKey = flowNodes.getFirst().flowNodeInstanceKey();
403+
404+
List<IncidentDbModel> incidents = searchIncidentsByProcessInstanceKeyAndReturnAsDbModel(processInstanceKey);
405+
assertThat(incidents).singleElement()
406+
.extracting(IncidentDbModel::treePath)
407+
.isNotNull()
408+
.isEqualTo("PI_" + processInstanceKey + "/FNI_" + flownodeInstanceKey);
409+
}
410+
371411
protected void assertOnIncidentBasicFields(IncidentEntity c8Incident, HistoricIncident c7Incident, ProcessInstance c7ChildInstance, ProcessInstance c7ParentInstance) {
372412
assertOnIncidentBasicFields(c8Incident, c7Incident, c7ChildInstance, c7ParentInstance, UNKNOWN, false);
373413
}

0 commit comments

Comments
 (0)