From 317cc02d77bc490fe43a998e33abc4765228a5ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Mathieu?= Date: Tue, 14 Jan 2025 12:14:05 +0100 Subject: [PATCH] feat(webserver, ui): avoid cancelled SSE connection from following exec Send a fake "start" event from the Execution following endpoint so that the UI didn't cancell it. I'm not sure when the UI would cancel the SSE connection but it can ocurs if any of the view that opens an SSE connection are left but no event are received yet. Sending a fake event immediatly lower the risk of occuring. --- ui/src/components/executions/ExecutionRoot.vue | 5 ++++- ui/src/components/executions/Topology.vue | 5 ++++- ui/src/components/logs/TaskRunDetails.vue | 5 ++++- .../webserver/controllers/api/ExecutionController.java | 5 ++++- 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/ui/src/components/executions/ExecutionRoot.vue b/ui/src/components/executions/ExecutionRoot.vue index 1928cec1a4b..d2a37d6bedf 100644 --- a/ui/src/components/executions/ExecutionRoot.vue +++ b/ui/src/components/executions/ExecutionRoot.vue @@ -92,7 +92,10 @@ if (isEnd) { this.closeSSE(); } - this.throttledExecutionUpdate(executionEvent); + // we are receiving a first "fake" event to force initializing the connection: ignoring it + if (executionEvent.lastEventId !== "start") { + this.throttledExecutionUpdate(executionEvent); + } if (isEnd) { this.throttledExecutionUpdate.flush(); } diff --git a/ui/src/components/executions/Topology.vue b/ui/src/components/executions/Topology.vue index 195edbe0758..3aac6c9cff9 100644 --- a/ui/src/components/executions/Topology.vue +++ b/ui/src/components/executions/Topology.vue @@ -225,7 +225,10 @@ if (isEnd) { this.closeSubExecutionSSE(subflow); } - this.throttledExecutionUpdate(subflow, executionEvent); + // we are receiving a first "fake" event to force initializing the connection: ignoring it + if (executionEvent.lastEventId !== "start") { + this.throttledExecutionUpdate(subflow, executionEvent); + } if (isEnd) { this.throttledExecutionUpdate.flush(); } diff --git a/ui/src/components/logs/TaskRunDetails.vue b/ui/src/components/logs/TaskRunDetails.vue index 479c5bb51e6..9bb3d88cf5f 100644 --- a/ui/src/components/logs/TaskRunDetails.vue +++ b/ui/src/components/logs/TaskRunDetails.vue @@ -477,7 +477,10 @@ if (isEnd) { this.closeExecutionSSE(); } - this.throttledExecutionUpdate(executionEvent); + // we are receiving a first "fake" event to force initializing the connection: ignoring it + if (executionEvent.lastEventId !== "start") { + this.throttledExecutionUpdate(executionEvent); + } if (isEnd) { this.throttledExecutionUpdate.flush(); } diff --git a/webserver/src/main/java/io/kestra/webserver/controllers/api/ExecutionController.java b/webserver/src/main/java/io/kestra/webserver/controllers/api/ExecutionController.java index 36abc8849c6..f13b5bae3cf 100644 --- a/webserver/src/main/java/io/kestra/webserver/controllers/api/ExecutionController.java +++ b/webserver/src/main/java/io/kestra/webserver/controllers/api/ExecutionController.java @@ -1472,8 +1472,11 @@ public Flux> follow( return Flux .>create(emitter -> { + // send a first "empty" event so the SSE is correctly initialized in the frontend in case there are no logs + emitter.next(Event.of(Execution.builder().id(executionId).build()).id("start")); + // already finished execution - Execution execution = null; + Execution execution; try { execution = Await.until( () -> executionRepository.findById(tenantService.resolveTenant(), executionId).orElse(null),