Skip to content

Commit

Permalink
feat(core): mass kill, restart & delete on executions (#901)
Browse files Browse the repository at this point in the history
close #335

Co-authored-by: Ludovic DEHON <[email protected]>
  • Loading branch information
Skraye and tchiotludo authored Jan 20, 2023
1 parent 6faac93 commit 6f30e6b
Show file tree
Hide file tree
Showing 12 changed files with 582 additions and 25 deletions.
9 changes: 4 additions & 5 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@ RUN apt-get update -y && \
if [ -n "${APT_PACKAGES}" ]; then apt-get install -y --no-install-recommends ${APT_PACKAGES}; fi && \
apt-get clean && \
rm -rf /var/lib/apt/lists/* /var/tmp/* /tmp/* && \
if [ -n "${KESTRA_PLUGINS}" ]; then /app/kestra plugins install ${KESTRA_PLUGINS} && rm -rf /tmp/*; fi

RUN groupadd kestra && \
useradd -m -g kestra kestra && \
chown -R kestra:kestra /app
if [ -n "${KESTRA_PLUGINS}" ]; then /app/kestra plugins install ${KESTRA_PLUGINS} && rm -rf /tmp/*; fi && \
groupadd kestra && \
useradd -m -g kestra kestra && \
chown -R kestra:kestra /app

USER kestra

Expand Down
6 changes: 6 additions & 0 deletions core/src/main/java/io/kestra/core/models/flows/State.java
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,12 @@ public boolean isFailed() {
return this.current.isFailed();
}

@JsonIgnore
public boolean isRestartable() {
return this.current.isFailed();
}


@Introspected
public enum Type {
CREATED,
Expand Down
1 change: 0 additions & 1 deletion core/src/test/java/io/kestra/core/Helpers.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import java.net.URISyntaxException;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand Down
130 changes: 127 additions & 3 deletions ui/src/components/executions/Executions.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,10 @@
fixed
@row-dblclick="onRowDoubleClick"
@sort-change="onSort"
@selection-change="handleSelectionChange"
>
<el-table-column type="selection" />

<el-table-column prop="id" v-if="!hidden.includes('id')" sortable="custom" :sort-orders="['ascending', 'descending']" :label="$t('id')">
<template #default="scope">
<id :value="scope.row.id" :shrink="true" />
Expand Down Expand Up @@ -110,9 +113,37 @@
</el-table>
</template>
</data-table>

<bottom-line v-if="executionsSelection.length !== 0">
<ul>
<bottom-line-counter v-model="queryBulkAction" :selections="executionsSelection" :total="total" />
<li>
<el-button :icon="Restart" type="success" class="bulk-button" @click="this.restartExecutions()">
{{ $t('restart') }}
</el-button>
</li>
<li>
<el-button :icon="StopCircleOutline" type="warning" class="bulk-button" @click="this.killExecutions()">
{{ $t('kill') }}
</el-button>
</li>
<li>
<el-button :icon="Delete" type="danger" class="bulk-button" @click="this.deleteExecutions()">
{{ $t('delete') }}
</el-button>
</li>
<li class="spacer" />
</ul>
</bottom-line>
</div>
</template>

<script setup>
import Restart from "vue-material-design-icons/Restart.vue";
import Delete from "vue-material-design-icons/Delete.vue";
import StopCircleOutline from "vue-material-design-icons/StopCircleOutline.vue";
</script>

<script>
import {mapState} from "vuex";
import DataTable from "../layout/DataTable.vue";
Expand All @@ -133,6 +164,8 @@
import State from "../../utils/state";
import Id from "../Id.vue";
import _merge from "lodash/merge";
import BottomLine from "../layout/BottomLine.vue";
import BottomLineCounter from "../layout/BottomLineCounter.vue";
export default {
mixins: [RouteContext, RestoreUrl, DataTableActions],
Expand All @@ -149,7 +182,9 @@
TriggerAvatar,
DateAgo,
Kicon,
Id
Id,
BottomLine,
BottomLineCounter
},
props: {
embed: {
Expand All @@ -170,7 +205,9 @@
isDefaultNamespaceAllow: true,
dailyReady: false,
dblClickRouteName: "executions/update",
flowTriggerDetails: undefined
flowTriggerDetails: undefined,
executionsSelection: [],
queryBulkAction: false
};
},
computed: {
Expand All @@ -191,6 +228,12 @@
}
},
methods: {
handleSelectionChange(val) {
if (val.length === 0) {
this.queryBulkAction = false
}
this.executionsSelection = val.map(x => x.id);
},
isRunning(item){
return State.isRunning(item.state.current);
},
Expand Down Expand Up @@ -236,6 +279,87 @@
durationFrom(item) {
return (+new Date() - new Date(item.state.startDate).getTime()) / 1000
},
restartExecutions() {
this.$toast().confirm(
this.$t("bulk restart", {"executionCount": this.queryBulkAction ? this.total : this.executionsSelection.length}),
() => {
if (this.queryBulkAction) {
return this.$store
.dispatch("execution/queryRestartExecution", this.loadQuery({
sort: this.$route.query.sort || "state.startDate:desc",
state: this.$route.query.state ? [this.$route.query.state] : this.statuses
}, false))
.then(r => {
this.$toast().success(this.$t("executions restarted", {executionCount: r.data.count}));
this.loadData();
})
} else {
return this.$store
.dispatch("execution/bulkRestartExecution", {executionsId: this.executionsSelection})
.then(r => {
this.$toast().success(this.$t("executions restarted", {executionCount: r.data.count}));
this.loadData();
}).catch(e => this.$toast().error(e.invalids.map(exec => {
return {message: this.$t(exec.message, {executionId: exec.invalidValue})}
}), this.$t(e.message)))
}
}
)
},
deleteExecutions() {
this.$toast().confirm(
this.$t("bulk delete", {"executionCount": this.queryBulkAction ? this.total : this.executionsSelection.length}),
() => {
if (this.queryBulkAction) {
return this.$store
.dispatch("execution/queryDeleteExecution", this.loadQuery({
sort: this.$route.query.sort || "state.startDate:desc",
state: this.$route.query.state ? [this.$route.query.state] : this.statuses
}, false))
.then(r => {
this.$toast().success(this.$t("executions deleted", {executionCount: r.data.count}));
this.loadData();
})
} else {
return this.$store
.dispatch("execution/bulkDeleteExecution", {executionsId: this.executionsSelection})
.then(r => {
this.$toast().success(this.$t("executions deleted", {executionCount: r.data.count}));
this.loadData();
}).catch(e => this.$toast().error(e.invalids.map(exec => {
return {message: this.$t(exec.message, {executionId: exec.invalidValue})}
}), this.$t(e.message)))
}
}
)
},
killExecutions() {
this.$toast().confirm(
this.$t("bulk kill", {"executionCount": this.queryBulkAction ? this.total : this.executionsSelection.length}),
() => {
if (this.queryBulkAction) {
return this.$store
.dispatch("execution/queryKill", this.loadQuery({
sort: this.$route.query.sort || "state.startDate:desc",
state: this.$route.query.state ? [this.$route.query.state] : this.statuses
}, false))
.then(r => {
this.$toast().success(this.$t("executions killed", {executionCount: r.data.count}));
this.loadData();
})
} else {
return this.$store
.dispatch("execution/bulkKill", {executionsId: this.executionsSelection})
.then(r => {
this.$toast().success(this.$t("executions killed", {executionCount: r.data.count}));
this.loadData();
}).catch(e => this.$toast().error(e.invalids.map(exec => {
return {message: this.$t(exec.message, {executionId: exec.invalidValue})}
}), this.$t(e.message)))
}
}
)
},
}
};
</script>
</script>
25 changes: 25 additions & 0 deletions ui/src/components/layout/BottomLine.vue
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
background-color: var(--bs-white);
padding: 0.5rem 1rem;
text-align: right;
transition: margin-left ease 0.2s;
html.dark & {
background-color: var(--bs-gray-100-darken-3);
Expand All @@ -38,6 +39,30 @@
flex-wrap: nowrap;
padding: 0;
justify-content: flex-end;
li.spacer {
flex-grow: 2;
}
li.left {
margin-left: 0;
}
li {
p {
padding: 8px 15px;
font-size: var(--font-size-sm);
line-height: var(--font-size-sm);
margin-bottom: 0;
}
}
}
.menu-collapsed & {
margin-left: var(--menu-collapsed-width);
}
.menu-not-collapsed & {
margin-left: var(--menu-width);
}
}
</style>
40 changes: 40 additions & 0 deletions ui/src/components/layout/BottomLineCounter.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<template>
<li class="left">
<p>
<span
class="counter"
v-html="$t('selection.selected', {count: modelValue ? total : selections.length})">
</span>

<el-link
type="info"
v-if="selections.length<total && !modelValue"
@click="all()"
>
{{ $t('selection.all', {count: total}) }}
</el-link>
</p>
</li>
</template>
<script>
export default {
props: {
total: {type: Number, required: true},
selections: {type: Array, required: true},
modelValue: {type: Boolean, required: true},
},
emits: ["update:modelValue"],
methods: {
all() {
this.$emit("update:modelValue", true);
}
}
}
</script>
<style lang="scss" scoped>
span.counter {
border-left: 6px solid var(--el-color-warning);
padding-left: 0.5rem;
margin-right: 5px;
}
</style>
25 changes: 25 additions & 0 deletions ui/src/stores/executions.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,19 @@ export default {
}
})
},
bulkRestartExecution(_, options) {
return this.$http.post(
`/api/v1/executions/restart/by-ids`,
options.executionsId
)
},
queryRestartExecution(_, options) {
return this.$http.post(
`/api/v1/executions/restart/query`,
{},
{params: options}
)
},
replayExecution(_, options) {
return this.$http.post(
`/api/v1/executions/${options.executionId}/replay`,
Expand All @@ -47,6 +60,12 @@ export default {
kill(_, options) {
return this.$http.delete(`/api/v1/executions/${options.id}/kill`);
},
bulkKill(_, options) {
return this.$http.delete(`/api/v1/executions/kill/by-ids`, {data: options.executionsId});
},
queryKill(_, options) {
return this.$http.delete(`/api/v1/executions/kill/query`, {params: options});
},
loadExecution({commit}, options) {
return this.$http.get(`/api/v1/executions/${options.id}`).then(response => {
commit("setExecution", response.data)
Expand All @@ -73,6 +92,12 @@ export default {
commit("setExecution", null)
})
},
bulkDeleteExecution({commit}, options) {
return this.$http.delete(`/api/v1/executions/by-ids`, {data: options.executionsId})
},
queryDeleteExecution({commit}, options) {
return this.$http.delete(`/api/v1/executions/query`, {params: options})
},
followExecution(_, options) {
return new EventSource(`${this.$http.defaults.baseURL}api/v1/executions/${options.id}/follow`);
},
Expand Down
4 changes: 4 additions & 0 deletions ui/src/styles/layout/root.scss
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,14 @@
--el-box-shadow-dark: $box-shadow-lg;

--el-button-hover-bg-color: var(--bs-gray-200);

--el-transition-duration: 0.2s;
--el-transition-duration-fast: 0.2s;
}

:root {
#{--menu-width}: $menu-width;
#{--menu-collapsed-width}: 50px;
#{--spacer}: $spacer;

#{--font-size-xs}: $font-size-xs;
Expand Down
Loading

0 comments on commit 6f30e6b

Please sign in to comment.