Skip to content

Commit

Permalink
poll if invocation state is not terminal again
Browse files Browse the repository at this point in the history
Also, account for `deleting` state in `useInvocationGraph` when getting the state for a graph step.
  • Loading branch information
ahmedhamidawan committed Dec 4, 2024
1 parent 98236e1 commit 69ae867
Show file tree
Hide file tree
Showing 6 changed files with 36 additions and 33 deletions.
15 changes: 0 additions & 15 deletions client/src/api/invocations.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import { rethrowSimple } from "@/utils/simple-error";

import { GalaxyApi } from "./client";
import { type components } from "./schema";

export type WorkflowInvocationElementView = components["schemas"]["WorkflowInvocationElementView"];
Expand All @@ -15,15 +12,3 @@ export type StepJobSummary =
| components["schemas"]["InvocationStepJobsResponseCollectionJobsModel"];

export type WorkflowInvocation = components["schemas"]["WorkflowInvocationResponse"];

export async function cancelWorkflowScheduling(invocationId: string) {
const { data, error } = await GalaxyApi().DELETE("/api/invocations/{invocation_id}", {
params: {
path: { invocation_id: invocationId },
},
});
if (error) {
rethrowSimple(error);
}
return data;
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@ interface Props {
workflow: Workflow;
/** Whether the invocation is terminal */
isTerminal: boolean;
/** Whether the invocation is scheduled */
isScheduled: boolean;
/** The zoom level for the graph */
zoom?: number;
/** Whether to show the minimap */
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import InvocationMessage from "@/components/WorkflowInvocationState/InvocationMe
interface Props {
invocation: WorkflowInvocationElementView;
invocationAndJobTerminal: boolean;
invocationSchedulingTerminal: boolean;
isFullPage?: boolean;
isSubworkflow?: boolean;
}
Expand Down Expand Up @@ -62,7 +61,6 @@ const uniqueMessages = computed(() => {
:invocation="invocation"
:workflow="workflow"
:is-terminal="invocationAndJobTerminal"
:is-scheduled="invocationSchedulingTerminal"
:is-full-page="isFullPage"
:show-minimap="isFullPage" />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { BAlert, BBadge, BButton, BTab, BTabs } from "bootstrap-vue";
import { computed, onUnmounted, ref, watch } from "vue";
import { type InvocationJobsSummary, type InvocationStep, type WorkflowInvocationElementView } from "@/api/invocations";
import { cancelWorkflowScheduling } from "@/api/invocations";
import { useAnimationFrameResizeObserver } from "@/composables/sensors/animationFrameResizeObserver";
import { useInvocationStore } from "@/stores/invocationStore";
import { useWorkflowStore } from "@/stores/workflowStore";
Expand Down Expand Up @@ -200,6 +199,16 @@ watch(
const storeId = computed(() => (invocation.value ? `invocation-${invocation.value.id}` : undefined));
watch(
() => invocationSchedulingTerminal.value,
async (newVal, oldVal) => {
if (oldVal && !newVal) {
// If the invocation was terminal and now is not, start polling again
await pollStepStatesUntilTerminal();
}
}
);
onUnmounted(() => {
clearTimeout(stepStatesInterval.value);
clearTimeout(jobStatesInterval.value);
Expand All @@ -223,18 +232,12 @@ function onError(e: any) {
async function onCancel() {
try {
cancellingInvocation.value = true;
await cancelWorkflowScheduling(props.invocationId);
await invocationStore.cancelWorkflowScheduling(props.invocationId);
} catch (e) {
onError(e);
} finally {
emit("invocation-cancelled");
// Update the invocation state to reflect the cancellation
setTimeout(async () => {
await invocationStore.fetchInvocationForId({ id: props.invocationId });
await invocationStore.fetchInvocationJobsSummaryForId({ id: props.invocationId });
cancellingInvocation.value = false;
}, 3000);
cancellingInvocation.value = false;
}
}
</script>
Expand All @@ -255,7 +258,7 @@ async function onCancel() {
size="sm"
class="text-decoration-none"
variant="link"
:disabled="cancellingInvocation"
:disabled="cancellingInvocation || invocationState == 'cancelling'"
@click="onCancel">
<FontAwesomeIcon :icon="faSquare" fixed-width />
Cancel
Expand Down Expand Up @@ -314,7 +317,6 @@ async function onCancel() {
:invocation="invocation"
:is-full-page="props.isFullPage"
:invocation-and-job-terminal="invocationAndJobTerminal"
:invocation-scheduling-terminal="invocationSchedulingTerminal"
:is-subworkflow="isSubworkflow" />
</BTab>
<BTab v-if="!isSubworkflow" title="Steps" lazy>
Expand Down
5 changes: 4 additions & 1 deletion client/src/composables/useInvocationGraph.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export const statePlaceholders: Record<string, string> = {
};

/** Only one job needs to be in one of these states for the graph step to be in that state */
const SINGLE_INSTANCE_STATES = ["error", "running", "paused"];
const SINGLE_INSTANCE_STATES = ["error", "running", "paused", "deleting"];
/** All jobs need to be in one of these states for the graph step to be in that state */
const ALL_INSTANCES_STATES = ["deleted", "skipped", "new", "queued"];

Expand Down Expand Up @@ -293,6 +293,9 @@ export function useInvocationGraph(
function getStepStateFromJobStates(jobStates: string[]): GraphStep["state"] | undefined {
for (const state of SINGLE_INSTANCE_STATES) {
if (jobStates.includes(state)) {
if (state === "deleting") {
return "deleted";
}
return state as GraphStep["state"];
}
}
Expand Down
21 changes: 19 additions & 2 deletions client/src/stores/invocationStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,24 @@ export const useInvocationStore = defineStore("invocationStore", () => {
return data;
}

const { getItemById: getInvocationById, fetchItemById: fetchInvocationForId } =
useKeyedCache<WorkflowInvocation>(fetchInvocationDetails);
async function cancelWorkflowScheduling(invocationId: string) {
const { data, error } = await GalaxyApi().DELETE("/api/invocations/{invocation_id}", {
params: {
path: { invocation_id: invocationId },
},
});
if (error) {
rethrowSimple(error);
}
storedInvocations.value[invocationId] = data;
return data;
}

const {
getItemById: getInvocationById,
fetchItemById: fetchInvocationForId,
storedItems: storedInvocations,
} = useKeyedCache<WorkflowInvocation>(fetchInvocationDetails);

const { getItemById: getInvocationJobsSummaryById, fetchItemById: fetchInvocationJobsSummaryForId } =
useKeyedCache<InvocationJobsSummary>(fetchInvocationJobsSummary);
Expand All @@ -58,6 +74,7 @@ export const useInvocationStore = defineStore("invocationStore", () => {
fetchInvocationJobsSummaryForId,
getInvocationStepById,
fetchInvocationStepById,
cancelWorkflowScheduling,
graphStepsByStoreId,
};
});

0 comments on commit 69ae867

Please sign in to comment.