Skip to content

Commit d284ad3

Browse files
committed
chore(history): populate incident treepath
related to #431
1 parent c5aae1e commit d284ad3

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
@@ -39,7 +39,6 @@ public void execute(HistoricIncident entity, Builder builder) {
3939
.errorType(null) // TODO: does error type exist in C7?
4040
.errorMessage(entity.getIncidentMessage())
4141
.creationDate(convertDate(entity.getCreateTime()))
42-
.treePath(null)
4342
.errorMessageHash(null)
4443
.partitionId(C7_HISTORY_PARTITION_ID)
4544
.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
@@ -9,11 +9,18 @@
99

1010
import static io.camunda.migration.data.constants.MigratorConstants.C8_DEFAULT_TENANT;
1111
import static io.camunda.migration.data.impl.util.ConverterUtil.prefixDefinitionId;
12+
import static io.camunda.search.entities.FlowNodeInstanceEntity.FlowNodeType.END_EVENT;
13+
import static io.camunda.search.entities.FlowNodeInstanceEntity.FlowNodeType.START_EVENT;
14+
import static io.camunda.search.entities.FlowNodeInstanceEntity.FlowNodeType.USER_TASK;
1215
import static org.assertj.core.api.Assertions.assertThat;
1316

17+
import io.camunda.db.rdbms.write.domain.FlowNodeInstanceDbModel;
18+
import io.camunda.db.rdbms.write.domain.IncidentDbModel;
1419
import io.camunda.migration.data.MigratorMode;
1520
import io.camunda.migration.data.qa.history.HistoryMigrationAbstractTest;
21+
import io.camunda.search.entities.FlowNodeInstanceEntity;
1622
import io.camunda.search.entities.IncidentEntity;
23+
import io.camunda.search.entities.ProcessInstanceEntity;
1724
import java.util.List;
1825
import org.camunda.bpm.engine.history.HistoricIncident;
1926
import org.camunda.bpm.engine.runtime.Job;
@@ -259,6 +266,39 @@ public void shouldMigrateIncidentBasicFieldsForServiceTask() {
259266
assertThat(c8Incident.flowNodeInstanceKey()).isNull(); // service task's flow node hasn't been migrated so it doesn't have a key
260267
}
261268

269+
@Test
270+
public void shouldGenerateTreePathForIncidents() {
271+
// given
272+
deployer.deployCamunda7Process("userTaskProcessAsyncAfter.bpmn");
273+
ProcessInstance c7ProcessInstance = runtimeService.startProcessInstanceByKey("userTaskProcessId");
274+
275+
createIncident("userTaskId");
276+
String userTaskId = taskService.createTaskQuery().taskDefinitionKey("userTaskId").singleResult().getId();
277+
taskService.complete(userTaskId);
278+
279+
HistoricIncident c7Incident = historyService.createHistoricIncidentQuery()
280+
.processInstanceId(c7ProcessInstance.getId())
281+
.singleResult();
282+
assertThat(c7Incident).isNotNull();
283+
284+
// when
285+
historyMigrator.migrate();
286+
287+
// then
288+
List<ProcessInstanceEntity> processInstances = searchHistoricProcessInstances("userTaskProcessId");
289+
assertThat(processInstances).hasSize(1);
290+
Long processInstanceKey = processInstances.getFirst().processInstanceKey();
291+
List<FlowNodeInstanceDbModel> flowNodes = searchFlowNodeInstancesByName("UserTaskName");
292+
assertThat(flowNodes).hasSize(1);
293+
Long flownodeInstanceKey = flowNodes.getFirst().flowNodeInstanceKey();
294+
295+
List<IncidentDbModel> incidents = searchIncidentsByProcessInstanceKeyAndReturnAsDbModel(processInstanceKey);
296+
assertThat(incidents).singleElement()
297+
.extracting(IncidentDbModel::treePath)
298+
.isNotNull()
299+
.isEqualTo("PI_" + processInstanceKey + "/FNI_" + flownodeInstanceKey);
300+
}
301+
262302
protected void assertOnIncidentBasicFields(IncidentEntity c8Incident, HistoricIncident c7Incident, ProcessInstance c7ChildInstance, ProcessInstance c7ParentInstance) {
263303
// specific values
264304
assertThat(c8Incident.tenantId()).isEqualTo(C8_DEFAULT_TENANT);

0 commit comments

Comments
 (0)