Skip to content

Commit

Permalink
Optimize client invocation list polling query
Browse files Browse the repository at this point in the history
  • Loading branch information
jmchilton committed Mar 13, 2024
1 parent a410c8d commit 824255c
Show file tree
Hide file tree
Showing 8 changed files with 47 additions and 13 deletions.
15 changes: 14 additions & 1 deletion client/src/api/invocations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@ import { ApiResponse, components, fetcher } from "./schema";

export type WorkflowInvocationElementView = components["schemas"]["WorkflowInvocationElementView"];
export type WorkflowInvocationCollectionView = components["schemas"]["WorkflowInvocationCollectionView"];
export type WorkflowInvocationStepStatesView = components["schemas"]["WorkflowInvocationStepStatesView"];
export type InvocationJobsSummary = components["schemas"]["InvocationJobsResponse"];
export type InvocationStep = components["schemas"]["InvocationStep"];

export const invocationsFetcher = fetcher.path("/api/invocations").method("get").create();

export type WorkflowInvocation = WorkflowInvocationElementView | WorkflowInvocationCollectionView;
export type WorkflowInvocation =
| WorkflowInvocationElementView
| WorkflowInvocationCollectionView
| WorkflowInvocationStepStatesView;

export interface WorkflowInvocationStep {
id: string;
Expand All @@ -34,6 +38,15 @@ export async function fetchInvocationDetails(params: { id: string }): Promise<Ap
} as ApiResponse<WorkflowInvocation>;
}

export async function fetchInvocationStepStateDetails(params: {
id: string;
}): Promise<ApiResponse<WorkflowInvocationStepStatesView>> {
const { data } = await axios.get(`${getAppRoot()}api/invocations/${params.id}?view=step_states`);
return {
data,
} as ApiResponse<WorkflowInvocationStepStatesView>;
}

export async function fetchInvocationJobsSummary(params: { id: string }): Promise<ApiResponse<InvocationJobsSummary>> {
const { data } = await axios.get(`${getAppRoot()}api/invocations/${params.id}/jobs_summary`);
return {
Expand Down
6 changes: 3 additions & 3 deletions client/src/api/schema/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12452,7 +12452,7 @@ export interface components {
| components["schemas"]["WorkflowInvocationElementView"]
| components["schemas"]["LegacyWorkflowInvocationElementView"]
| components["schemas"]["WorkflowInvocationCollectionView"]
| components["schemas"]["WorkflowInvocationStepStateView"];
| components["schemas"]["WorkflowInvocationStepStatesView"];
/** WorkflowInvocationStateSummary */
WorkflowInvocationStateSummary: {
/**
Expand Down Expand Up @@ -12480,8 +12480,8 @@ export interface components {
[key: string]: number | undefined;
};
};
/** WorkflowInvocationStepStateView */
WorkflowInvocationStepStateView: {
/** WorkflowInvocationStepStatesView */
WorkflowInvocationStepStatesView: {
/**
* Create Time
* Format: date-time
Expand Down
2 changes: 1 addition & 1 deletion client/src/components/Workflow/InvocationsListState.vue
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ const {
jobStatesSummary,
monitorState,
clearStateMonitor,
} = useInvocationState(toRef(props, "invocationId"));
} = useInvocationState(toRef(props, "invocationId"), true);
onMounted(monitorState);
onBeforeUnmount(clearStateMonitor);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ import { isTerminal, jobCount } from "./util";

type OptionalInterval = ReturnType<typeof setInterval> | null;

export function useInvocationState(invocationId: Ref<string>) {
export function useInvocationState(invocationId: Ref<string>, fetchMinimal: boolean = false) {
const invocationStore = useInvocationStore();

const invocation = computed(() => {
return invocationStore.getInvocationById(invocationId.value);
if (fetchMinimal) {
return invocationStore.getInvocationWithStepStatesById(invocationId.value);
} else {
return invocationStore.getInvocationById(invocationId.value);
}
});

let stepStatesInterval: OptionalInterval = null;
Expand Down Expand Up @@ -48,7 +52,11 @@ export function useInvocationState(invocationId: Ref<string>) {

async function pollStepStatesUntilTerminal() {
if (!invocation.value || !invocationSchedulingTerminal.value) {
await invocationStore.fetchInvocationForId({ id: invocationId.value });
if (fetchMinimal) {
await invocationStore.fetchInvocationWithStepStatesForId({ id: invocationId.value });
} else {
await invocationStore.fetchInvocationForId({ id: invocationId.value });
}
stepStatesInterval = setTimeout(pollStepStatesUntilTerminal, 3000);
}
}
Expand Down
6 changes: 6 additions & 0 deletions client/src/stores/invocationStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { defineStore } from "pinia";

import {
fetchInvocationDetails,
fetchInvocationStepStateDetails,
fetchInvocationJobsSummary,
fetchInvocationStep,
type WorkflowInvocation,
Expand All @@ -14,6 +15,9 @@ export const useInvocationStore = defineStore("invocationStore", () => {
const { getItemById: getInvocationById, fetchItemById: fetchInvocationForId } =
useKeyedCache<WorkflowInvocation>(fetchInvocationDetails);

const { getItemById: getInvocationWithStepStatesById, fetchItemById: fetchInvocationWithStepStatesForId } =
useKeyedCache<WorkflowInvocation>(fetchInvocationStepStateDetails);

const { getItemById: getInvocationJobsSummaryById, fetchItemById: fetchInvocationJobsSummaryForId } =
useKeyedCache<InvocationJobsSummary>(fetchInvocationJobsSummary);

Expand All @@ -27,5 +31,7 @@ export const useInvocationStore = defineStore("invocationStore", () => {
fetchInvocationJobsSummaryForId,
getInvocationStepById,
fetchInvocationStepById,
getInvocationWithStepStatesById,
fetchInvocationWithStepStatesForId,
};
});
3 changes: 2 additions & 1 deletion lib/galaxy/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8646,7 +8646,8 @@ def _serialize(self, id_encoder, serialization_options):
return invocation_attrs

def to_dict(self, view="collection", value_mapper=None, step_details=False, legacy_job_state=False):
rval = super().to_dict(view=view, value_mapper=value_mapper)
base_view = view if view != "step_states" else "collection"
rval = super().to_dict(view=base_view, value_mapper=value_mapper)
if rval["state"] is None:
# bugs could result in no state being set
rval["state"] = self.states.FAILED
Expand Down
11 changes: 8 additions & 3 deletions lib/galaxy/schema/invocation.py
Original file line number Diff line number Diff line change
Expand Up @@ -566,7 +566,7 @@ class WorkflowInvocationCollectionView(Model, WithModelClass):
model_class: INVOCATION_MODEL_CLASS = ModelClassField(INVOCATION_MODEL_CLASS)


class WorkflowInvocationStepStateView(WorkflowInvocationCollectionView):
class WorkflowInvocationStepStatesView(WorkflowInvocationCollectionView):
steps: List[InvocationStep] = Field(default=..., title="Steps", description="Steps of the workflow invocation.")


Expand Down Expand Up @@ -607,7 +607,12 @@ class WorkflowInvocationElementView(BaseWorkflowInvocationElementView):

class WorkflowInvocationResponse(RootModel):
root: Annotated[
Union[WorkflowInvocationElementView, LegacyWorkflowInvocationElementView, WorkflowInvocationCollectionView, WorkflowInvocationStepStateView],
Union[
WorkflowInvocationElementView,
LegacyWorkflowInvocationElementView,
WorkflowInvocationCollectionView,
WorkflowInvocationStepStatesView,
],
Field(union_mode="left_to_right"),
]

Expand All @@ -619,7 +624,7 @@ def from_dict(as_dict: Dict[str, Any], view: "InvocationSerializationView", lega
if view == InvocationSerializationView.collection:
root = WorkflowInvocationCollectionView(**as_dict)
elif view == InvocationSerializationView.step_states:
root = WorkflowInvocationStepStateView(**as_dict)
root = WorkflowInvocationStepStatesView(**as_dict)
elif legacy_job_state:
root = LegacyWorkflowInvocationElementView(**as_dict)
else:
Expand Down
3 changes: 2 additions & 1 deletion lib/galaxy/webapps/galaxy/api/workflows.py
Original file line number Diff line number Diff line change
Expand Up @@ -1405,11 +1405,12 @@ def show_invocation(
self,
invocation_id: InvocationIDPathParam,
trans: ProvidesUserContext = DependsOnTrans,
view: SerializationViewQueryParam = None,
step_details: StepDetailQueryParam = False,
legacy_job_state: LegacyJobStateQueryParam = False,
) -> WorkflowInvocationResponse:
serialization_params = InvocationSerializationParams(
step_details=step_details, legacy_job_state=legacy_job_state
view=view, step_details=step_details, legacy_job_state=legacy_job_state
)
return self.invocations_service.show(trans, invocation_id, serialization_params, eager=True)

Expand Down

0 comments on commit 824255c

Please sign in to comment.