From 830929a693720453e28acd362ea205345152b68d Mon Sep 17 00:00:00 2001 From: Julian Stirling Date: Thu, 30 Oct 2025 10:28:12 +0000 Subject: [PATCH] Split up the action button methods for monitoring and starting a task Previously the start task method of action button handled awaiting polling and resetting variables when the task completes. If an ongoing task was found polling was started so that logs could be communicated but no clean up happened when the task finished. This has been split up and the checks for ongoing tasks improved so they also clean up after ongoing tasks finish. Closes #442 --- .../labThingsComponents/actionButton.vue | 83 ++++++++++++------- 1 file changed, 55 insertions(+), 28 deletions(-) diff --git a/webapp/src/components/labThingsComponents/actionButton.vue b/webapp/src/components/labThingsComponents/actionButton.vue index cc78550f..b37abc89 100644 --- a/webapp/src/components/labThingsComponents/actionButton.vue +++ b/webapp/src/components/labThingsComponents/actionButton.vue @@ -227,16 +227,39 @@ export default { } }, - checkExistingTasks: function() { - axios.get(this.submitUrl).then(response => { - for (const task of response.data) { - if (task.status == "pending" || task.status == "running") { - this.taskStarted = true; - this.$emit("taskStarted"); - this.startPolling(task.id, task.links.find(t => t.rel == "self").href); - } + /* Check if an existing task had already started when this mounts. + * + * This is called on mounted. + * + * It will emit taskStarted if it finds an ongoing task to allow parent components + * to act as expected if the task is started. It will then poll the action. + * + */ + async checkExistingTasks() { + let response; + try { + response = await axios.get(this.submitUrl); + } catch (error) { + console.warn("checkExistingTasks: request failed", error); + return; + } + // Check for a task that is ongoing. + // We can't handle multiple tasks ongoing, so this picks the first. + const ongoingTask = response.data.find(t => ["pending", "running"].includes(t.status)); + if (ongoingTask) { + // There is a started task + this.taskStarted = true; + this.$emit("taskStarted"); + // Find its URL + const taskUrl = ongoingTask.links.find(t => t.rel == "self").href; + try { + await this.pollOngoingTask(ongoingTask.id, taskUrl); + } catch (error) { + this.$emit("error", error); + } finally { + this.onTaskEnd(); } - }); + } }, bootstrapTask: function() { @@ -266,29 +289,33 @@ export default { if (this.modalProgress) { UIkit.modal(this.$refs.statusModal).show(); } - // Start the store polling TaskId for success - response = await this.startPolling(response.data.id, response.data.href); - if (response.status == "completed") { - this.$emit("response", response); - this.$emit("completed", response.output); - } else if (response.status == "cancelled") { - this.$emit("cancelled", response); - this.modalNotify(`The action '${this.submitLabel}' was cancelled.`); - } + await this.pollOngoingTask(response.data.id, response.data.href); } catch (error) { this.$emit("error", error); } finally { - // Reset taskRunning and taskId - this.taskRunning = false; - this.taskStarted = false; - this.$emit("finished"); - // Update the form data if we're self-updating - if (this.selfUpdate) { - this.getFormData(); - } + this.onTaskEnd(); } }, + async pollOngoingTask(taskId, taskUrl) { + // Start the store polling TaskId for success + const response = await this.startPolling(taskId, taskUrl); + if (response.status == "completed") { + this.$emit("response", response); + this.$emit("completed", response.output); + } else if (response.status == "cancelled") { + this.$emit("cancelled", response); + this.modalNotify(`The action '${this.submitLabel}' was cancelled.`); + } + }, + + onTaskEnd: function() { + // Reset taskRunning and taskId + this.taskRunning = false; + this.taskStarted = false; + this.$emit("finished"); + }, + startPolling: function(taskId, taskUrl) { if (this.taskRunning != true) { // Starts polling an existing Action task @@ -330,7 +357,7 @@ export default { } // As LabThings Actions add the message from any raised exception to the log, the // last message in the log is the message from the Exception. - //If the Exception was raised with no message, use a default. + // If the Exception was raised with no message, use a default. else { message = response.data.log.from_index(-1).message || @@ -340,7 +367,7 @@ export default { reject(new Error(message)); } // If task ends without reporting an error - // (NB this includes cancellation) + // (Note: this includes cancellation) else { resolve(response.data); }