Skip to content

Commit

Permalink
Lighter-weight invocation view for polling from list.
Browse files Browse the repository at this point in the history
  • Loading branch information
jmchilton authored and ahmedhamidawan committed Nov 7, 2024
1 parent 776daa1 commit bb96e84
Show file tree
Hide file tree
Showing 8 changed files with 132 additions and 41 deletions.
1 change: 1 addition & 0 deletions client/src/api/invocations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { type components } 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 type InvocationMessage = components["schemas"]["InvocationMessageResponseUnion"];
Expand Down
110 changes: 79 additions & 31 deletions client/src/api/schema/schema.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12161,7 +12161,7 @@ export interface components {
* InvocationSerializationView
* @enum {string}
*/
InvocationSerializationView: "element" | "collection";
InvocationSerializationView: "element" | "collection" | "step_states";
/**
* InvocationSortByEnum
* @enum {string}
Expand All @@ -12179,10 +12179,7 @@ export interface components {
| "cancelled"
| "cancelling"
| "failed";
/**
* InvocationStep
* @description Information about workflow invocation step
*/
/** InvocationStep */
InvocationStep: {
/**
* Action
Expand All @@ -12199,8 +12196,6 @@ export interface components {
* @description The implicit collection job ID associated with the workflow invocation step.
*/
implicit_collection_jobs_id?: string | null;
/** Job Id */
job_id: string | null;
/**
* Jobs
* @description Jobs associated with the workflow invocation step.
Expand Down Expand Up @@ -13125,18 +13120,24 @@ export interface components {
* @example 0123456789ABCDEF
*/
id: string;
/**
* Implicit Collection Jobs ID
* @description The implicit collection job ID associated with the workflow invocation step.
*/
implicit_collection_jobs_id?: string | null;
/** Job Id */
job_id: string | null;
/**
* Jobs
* @description Jobs associated with the workflow invocation step.
* @default []
*/
jobs?: components["schemas"]["JobBaseModel"][];
jobs: components["schemas"]["JobBaseModel"][];
/**
* Model class
* @description The name of the database model class.
* @constant
* @enum {string}
*/
model_class: "WorkflowInvocationStep";
/**
Expand All @@ -13149,16 +13150,16 @@ export interface components {
* @description The dataset collection outputs of the workflow invocation step.
* @default {}
*/
output_collections?: {
[key: string]: components["schemas"]["InvocationStepCollectionOutput"] | undefined;
output_collections: {
[key: string]: components["schemas"]["InvocationStepCollectionOutput"];
};
/**
* Outputs
* @description The outputs of the workflow invocation step.
* @default {}
*/
outputs?: {
[key: string]: components["schemas"]["InvocationStepOutput"] | undefined;
outputs: {
[key: string]: components["schemas"]["InvocationStepOutput"];
};
/**
* State of the invocation step
Expand Down Expand Up @@ -13241,44 +13242,33 @@ export interface components {
* @description Input step parameters of the workflow invocation.
*/
input_step_parameters: {
[key: string]: components["schemas"]["InvocationInputParameter"] | undefined;
[key: string]: components["schemas"]["InvocationInputParameter"];
};
/**
* Inputs
* @description Input datasets/dataset collections of the workflow invocation.
*/
inputs: {
[key: string]: components["schemas"]["InvocationInput"] | undefined;
[key: string]: components["schemas"]["InvocationInput"];
};
/**
* Messages
* @description A list of messages about why the invocation did not succeed.
*/
messages: (
| components["schemas"]["InvocationCancellationReviewFailedResponse"]
| components["schemas"]["InvocationCancellationHistoryDeletedResponse"]
| components["schemas"]["InvocationCancellationUserRequestResponse"]
| components["schemas"]["InvocationFailureDatasetFailedResponse"]
| components["schemas"]["InvocationFailureCollectionFailedResponse"]
| components["schemas"]["InvocationFailureJobFailedResponse"]
| components["schemas"]["InvocationFailureOutputNotFoundResponse"]
| components["schemas"]["InvocationFailureExpressionEvaluationFailedResponse"]
| components["schemas"]["InvocationFailureWhenNotBooleanResponse"]
| components["schemas"]["InvocationUnexpectedFailureResponse"]
| components["schemas"]["InvocationEvaluationWarningWorkflowOutputNotFoundResponse"]
)[];
messages: components["schemas"]["InvocationMessageResponseUnion"][];
/**
* Model class
* @description The name of the database model class.
* @constant
* @enum {string}
*/
model_class: "WorkflowInvocation";
/**
* Output collections
* @description Output dataset collections of the workflow invocation.
*/
output_collections: {
[key: string]: components["schemas"]["InvocationOutputCollection"] | undefined;
[key: string]: components["schemas"]["InvocationOutputCollection"];
};
/**
* Output values
Expand All @@ -13290,7 +13280,7 @@ export interface components {
* @description Output datasets of the workflow invocation.
*/
outputs: {
[key: string]: components["schemas"]["InvocationOutput"] | undefined;
[key: string]: components["schemas"]["InvocationOutput"];
};
/**
* Invocation state
Expand All @@ -13312,7 +13302,7 @@ export interface components {
* UUID
* @description Universal unique identifier of the workflow invocation.
*/
uuid?: string | string | null;
uuid?: string | null;
/**
* Workflow ID
* @description The encoded Workflow ID associated with the invocation.
Expand Down Expand Up @@ -18498,7 +18488,8 @@ export interface components {
WorkflowInvocationResponse:
| components["schemas"]["WorkflowInvocationElementView"]
| components["schemas"]["LegacyWorkflowInvocationElementView"]
| components["schemas"]["WorkflowInvocationCollectionView"];
| components["schemas"]["WorkflowInvocationCollectionView"]
| components["schemas"]["WorkflowInvocationStepStatesView"];
/** WorkflowInvocationStateSummary */
WorkflowInvocationStateSummary: {
/**
Expand All @@ -18525,6 +18516,61 @@ export interface components {
[key: string]: number;
};
};
/** WorkflowInvocationStepStatesView */
WorkflowInvocationStepStatesView: {
/**
* Create Time
* Format: date-time
* @description The time and date this item was created.
*/
create_time: string;
/**
* History ID
* @description The encoded ID of the history associated with the invocation.
* @example 0123456789ABCDEF
*/
history_id: string;
/**
* ID
* @description The encoded ID of the workflow invocation.
* @example 0123456789ABCDEF
*/
id: string;
/**
* Model class
* @description The name of the database model class.
* @constant
* @enum {string}
*/
model_class: "WorkflowInvocation";
/**
* Invocation state
* @description State of workflow invocation.
*/
state: components["schemas"]["InvocationState"];
/**
* Steps
* @description Steps of the workflow invocation.
*/
steps: components["schemas"]["InvocationStep"][];
/**
* Update Time
* Format: date-time
* @description The last time and date this item was updated.
*/
update_time: string;
/**
* UUID
* @description Universal unique identifier of the workflow invocation.
*/
uuid?: string | null;
/**
* Workflow ID
* @description The encoded Workflow ID associated with the invocation.
* @example 0123456789ABCDEF
*/
workflow_id: string;
};
/**
* WorkflowJobMetric
* @example {
Expand Down Expand Up @@ -27127,6 +27173,8 @@ export interface operations {
show_invocation_api_invocations__invocation_id__get: {
parameters: {
query?: {
/** @description View to be passed to the serializer */
view?: string | null;
/** @description Include details for individual invocation steps and populate a steps attribute in the resulting dictionary. */
step_details?: boolean;
/** @description Populate the invocation step state with the job state instead of the invocation step state.
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 @@ -23,7 +23,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 @@ -7,11 +7,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 @@ -47,7 +51,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
22 changes: 21 additions & 1 deletion client/src/stores/invocationStore.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
import { defineStore } from "pinia";

import { GalaxyApi } from "@/api";
import { type InvocationJobsSummary, type InvocationStep, type WorkflowInvocation } from "@/api/invocations";
import {
type InvocationJobsSummary,
type InvocationStep,
type WorkflowInvocation,
type WorkflowInvocationStepStatesView,
} from "@/api/invocations";
import { type FetchParams, useKeyedCache } from "@/composables/keyedCache";
import { rethrowSimple } from "@/utils/simple-error";

Expand Down Expand Up @@ -36,9 +41,22 @@ export const useInvocationStore = defineStore("invocationStore", () => {
return data;
}

async function fetchInvocationStepStateDetails(params: FetchParams): Promise<WorkflowInvocationStepStatesView> {
const { data, error } = await GalaxyApi().GET("/api/invocations/{invocation_id}", {
params: { path: { invocation_id: params.id }, view: "step_states" },
});
if (error) {
rethrowSimple(error);
}
return data;
}

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 @@ -52,5 +70,7 @@ export const useInvocationStore = defineStore("invocationStore", () => {
fetchInvocationJobsSummaryForId,
getInvocationStepById,
fetchInvocationStepById,
getInvocationWithStepStatesById,
fetchInvocationWithStepStatesForId,
};
});
7 changes: 4 additions & 3 deletions lib/galaxy/model/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -9020,11 +9020,12 @@ 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
if view == "element":
if view in ["element", "step_states"]:
steps = []
for step in self.steps:
if step_details:
Expand All @@ -9046,7 +9047,7 @@ def to_dict(self, view="collection", value_mapper=None, step_details=False, lega
v["implicit_collection_jobs_id"] = step.implicit_collection_jobs_id
steps.append(v)
rval["steps"] = steps

if view == "element":
inputs = {}
for input_item_association in self.input_datasets + self.input_dataset_collections:
if input_item_association.history_content_type == "dataset":
Expand Down
14 changes: 13 additions & 1 deletion lib/galaxy/schema/invocation.py
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,10 @@ class WorkflowInvocationCollectionView(Model, WithModelClass):
model_class: INVOCATION_MODEL_CLASS = ModelClassField(INVOCATION_MODEL_CLASS)


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


class BaseWorkflowInvocationElementView(WorkflowInvocationCollectionView):
inputs: Dict[str, InvocationInput] = Field(
default=..., title="Inputs", description="Input datasets/dataset collections of the workflow invocation."
Expand Down Expand Up @@ -615,7 +619,12 @@ class WorkflowInvocationElementView(BaseWorkflowInvocationElementView):

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

Expand All @@ -626,6 +635,8 @@ def from_dict(as_dict: Dict[str, Any], view: "InvocationSerializationView", lega
# performant, and will likely yield clearer error messages.
if view == InvocationSerializationView.collection:
root = WorkflowInvocationCollectionView(**as_dict)
elif view == InvocationSerializationView.step_states:
root = WorkflowInvocationStepStatesView(**as_dict)
elif legacy_job_state:
root = LegacyWorkflowInvocationElementView(**as_dict)
else:
Expand Down Expand Up @@ -722,6 +733,7 @@ class CreateInvocationFromStore(StoreContentSource):
class InvocationSerializationView(str, Enum):
element = "element"
collection = "collection"
step_states = "step_states" # collection + steps - for monitoring, lighter than element


class InvocationSerializationParams(BaseModel):
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 @@ -1445,11 +1445,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 bb96e84

Please sign in to comment.