From 049855e92b47a266e72066ad701e29c0a4a5fd85 Mon Sep 17 00:00:00 2001 From: Ludovic DEHON Date: Thu, 2 Mar 2023 21:28:45 +0100 Subject: [PATCH] feat(core): add an originalId that will be the same in case of replay --- .../core/models/executions/Execution.java | 23 ++++++++++++++++++ .../io/kestra/core/runners/RunContext.java | 1 + .../core/models/executions/ExecutionTest.java | 24 +++++++++++++++++++ ui/src/components/executions/Overview.vue | 12 ++++++++++ ui/src/translations.json | 2 ++ 5 files changed, 62 insertions(+) diff --git a/core/src/main/java/io/kestra/core/models/executions/Execution.java b/core/src/main/java/io/kestra/core/models/executions/Execution.java index f1238d5e222..961ad0a5fe0 100644 --- a/core/src/main/java/io/kestra/core/models/executions/Execution.java +++ b/core/src/main/java/io/kestra/core/models/executions/Execution.java @@ -58,6 +58,8 @@ public class Execution implements DeletedInterface { String parentId; + String originalId; + @With ExecutionTrigger trigger; @@ -65,6 +67,24 @@ public class Execution implements DeletedInterface { @Builder.Default boolean deleted = false; + public static class ExecutionBuilder { + void prebuild() { + this.originalId = this.id; + } + } + + public static ExecutionBuilder builder() { + return new CustomExecutionBuilder(); + } + + private static class CustomExecutionBuilder extends ExecutionBuilder { + @Override + public Execution build() { + this.prebuild(); + return super.build(); + } + } + public Execution withState(State.Type state) { return new Execution( this.id, @@ -76,6 +96,7 @@ public Execution withState(State.Type state) { this.variables, this.state.withState(state), this.parentId, + this.originalId, this.trigger, this.deleted ); @@ -104,6 +125,7 @@ public Execution withTaskRun(TaskRun taskRun) throws InternalException { this.variables, this.state, this.parentId, + this.originalId, this.trigger, this.deleted ); @@ -120,6 +142,7 @@ public Execution childExecution(String childExecutionId, List taskRunLi this.variables, state, childExecutionId != null ? this.getId() : null, + this.originalId, this.trigger, this.deleted ); diff --git a/core/src/main/java/io/kestra/core/runners/RunContext.java b/core/src/main/java/io/kestra/core/runners/RunContext.java index 37d1c818390..69550cfbb57 100644 --- a/core/src/main/java/io/kestra/core/runners/RunContext.java +++ b/core/src/main/java/io/kestra/core/runners/RunContext.java @@ -226,6 +226,7 @@ protected Map variables(Flow flow, Task task, Execution executio builder .put("execution", ImmutableMap.of( "id", execution.getId(), + "originalId", execution.getOriginalId(), "startDate", execution.getState().getStartDate() )); diff --git a/core/src/test/java/io/kestra/core/models/executions/ExecutionTest.java b/core/src/test/java/io/kestra/core/models/executions/ExecutionTest.java index a121b4f71af..6e00a59da54 100644 --- a/core/src/test/java/io/kestra/core/models/executions/ExecutionTest.java +++ b/core/src/test/java/io/kestra/core/models/executions/ExecutionTest.java @@ -1,5 +1,6 @@ package io.kestra.core.models.executions; +import io.kestra.core.utils.IdUtils; import org.junit.jupiter.api.Test; import io.kestra.core.models.flows.State; @@ -124,4 +125,27 @@ void hasTaskRunJoinableAfterRestart() { .build() ), is(true)); } + + @Test + void originalId() { + Execution execution = Execution.builder() + .id(IdUtils.create()) + .state(new State()) + .build(); + assertThat(execution.getOriginalId(), is(execution.getId())); + + Execution restart1 = execution.childExecution( + IdUtils.create(), + execution.getTaskRunList(), + execution.withState(State.Type.RESTARTED).getState() + ); + assertThat(restart1.getOriginalId(), is(execution.getId())); + + Execution restart2 = restart1.childExecution( + IdUtils.create(), + restart1.getTaskRunList(), + restart1.withState(State.Type.PAUSED).getState() + ); + assertThat(restart2.getOriginalId(), is(execution.getId())); + } } diff --git a/ui/src/components/executions/Overview.vue b/ui/src/components/executions/Overview.vue index 9bf41a79743..a51fc19f5e9 100644 --- a/ui/src/components/executions/Overview.vue +++ b/ui/src/components/executions/Overview.vue @@ -137,6 +137,18 @@ }); } + if (this.execution.originalId !== this.execution.id) { + ret.push({ + key: this.$t("original execution"), + value: this.execution.originalId, + link: { + flowId: this.execution.flowId, + id: this.execution.originalId, + namespace: this.execution.namespace + } + }); + } + return ret; }, inputs() { diff --git a/ui/src/translations.json b/ui/src/translations.json index 62689daaadb..a5c0db70a7a 100644 --- a/ui/src/translations.json +++ b/ui/src/translations.json @@ -152,6 +152,7 @@ "key": "Key", "value": "Value", "parent execution": "Parent execution", + "original execution": "Original execution", "automatic refresh": "Automatic refresh", "toggle periodic refresh each 10 seconds": "Toggle periodic refresh each 10 seconds", "trigger refresh": "Trigger refresh", @@ -527,6 +528,7 @@ "key": "Clé", "value": "Valeur", "parent execution": "Execution parente", + "original execution": "Execution d'origine", "automatic refresh": "rafraîchissement automatique", "toggle periodic refresh each 10 seconds": "Activer le rafraîchissement toutes les 10 secondes", "trigger refresh": "Déclencher le rafraîchissement",