Skip to content
Snippets Groups Projects
Verified Commit a7f4538f authored by Daniel Göbel's avatar Daniel Göbel
Browse files

Use exponential backoff when polling running executions

#85
parent e078e13b
No related branches found
No related tags found
2 merge requests!84Remove development branch,!81Resolve "Use exponential backoff when polling running workflow executions"
Pipeline #40305 passed
abstract class BackoffStrategy {
protected currentVal: number;
protected iteration: number;
protected reachedMax: boolean;
protected maxValue: number;
constructor(maxValue?: number) {
this.currentVal = 0;
this.iteration = 0;
this.reachedMax = false;
this.maxValue = maxValue ?? 300;
}
protected abstract computeNextValue(): number;
public reset() {
this.iteration = 0;
this.currentVal = 0;
this.reachedMax = false;
}
public *generator(): Generator<number> {
while (true) {
this.iteration++;
if (this.reachedMax) {
yield this.maxValue;
} else {
this.currentVal = this.computeNextValue();
if (0 < this.maxValue && this.maxValue < this.currentVal) {
this.reachedMax = true;
yield this.maxValue;
} else {
yield this.currentVal;
}
}
}
}
}
export class ExponentialBackoff extends BackoffStrategy {
protected computeNextValue(): number {
return 2 << (this.iteration - 1);
}
}
export class NoBackoff extends BackoffStrategy {
private readonly constantValue: number;
constructor(constantValue?: number) {
super();
this.constantValue = constantValue ?? 30;
}
protected computeNextValue(): number {
return this.constantValue;
}
}
export class LinearBackoff extends BackoffStrategy {
private readonly backoff: number;
constructor(backoff?: number) {
super();
this.backoff = backoff ?? 5;
}
protected computeNextValue(): number {
return this.currentVal + this.backoff;
}
}
......@@ -8,12 +8,14 @@ import DeleteModal from "@/components/modals/DeleteModal.vue";
import { useWorkflowStore } from "@/stores/workflows";
import { useWorkflowExecutionStore } from "@/stores/workflowExecutions";
import ParameterModal from "@/components/workflows/modals/ParameterModal.vue";
import { ExponentialBackoff } from "@/utils/BackoffStrategy";
const workflowRepository = useWorkflowStore();
const executionRepository = useWorkflowExecutionStore();
const backoff = new ExponentialBackoff();
let refreshTimeout: NodeJS.Timeout | undefined = undefined;
let intervalId: NodeJS.Timer | undefined = undefined;
let pollingTimeout: NodeJS.Timeout | undefined = undefined;
const executionsState = reactive<{
loading: boolean;
......@@ -80,9 +82,17 @@ const deleteModalString = computed<string>(() => {
// Functions
// -----------------------------------------------------------------------------
function updateExecutions() {
executionRepository.fetchExecutions(() => {
executionsState.loading = false;
});
backoff.reset();
clearTimeout(pollingTimeout);
executionRepository
.fetchExecutions(() => {
executionsState.loading = false;
})
.then(() => {
if (runningExecutions.value.length > 0) {
refreshRunningWorkflowExecutionTimer();
}
});
}
function refreshExecutions() {
......@@ -106,25 +116,37 @@ function cancelWorkflowExecution(executionId: string) {
executionRepository.cancelExecution(executionId);
}
const runningExecutions = computed<WorkflowExecutionOut[]>(() =>
executionRepository.executions.filter((execution) =>
workflowExecutionCancelable(execution),
),
);
function refreshRunningWorkflowExecution() {
Promise.all(
executionRepository.executions
.filter((execution) => workflowExecutionCancelable(execution))
.map((execution) =>
executionRepository.fetchExecution(execution.execution_id),
),
runningExecutions.value.map((execution) =>
executionRepository.fetchExecution(execution.execution_id),
),
);
}
async function refreshRunningWorkflowExecutionTimer() {
for (const sleep of backoff.generator()) {
await new Promise((resolve) => {
pollingTimeout = setTimeout(resolve, sleep * 1000);
});
refreshRunningWorkflowExecution();
}
}
onMounted(() => {
updateExecutions();
workflowRepository.fetchWorkflows();
intervalId = setInterval(refreshRunningWorkflowExecution, 5000);
new Tooltip("#refreshExecutionsButton");
});
onUnmounted(() => {
clearInterval(intervalId);
clearTimeout(pollingTimeout);
});
</script>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment