-
Notifications
You must be signed in to change notification settings - Fork 2.2k
feat(governance): add id-based workflow instance states endpoint with optional task-transition filter #30164
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -18,9 +18,12 @@ | |
| import jakarta.ws.rs.core.Context; | ||
| import jakarta.ws.rs.core.MediaType; | ||
| import jakarta.ws.rs.core.SecurityContext; | ||
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.UUID; | ||
| import lombok.NonNull; | ||
| import lombok.extern.slf4j.Slf4j; | ||
| import org.openmetadata.schema.governance.workflows.Stage; | ||
| import org.openmetadata.schema.governance.workflows.WorkflowInstanceState; | ||
| import org.openmetadata.schema.type.MetadataOperation; | ||
| import org.openmetadata.schema.utils.ResultList; | ||
|
|
@@ -176,6 +179,66 @@ public ResultList<WorkflowInstanceState> listForStateId( | |
| workflowDefinitionName, workflowInstanceId, offset, startTs, endTs, limitParam, latest); | ||
| } | ||
|
|
||
| @GET | ||
| @Path("/workflowInstanceId/{workflowInstanceId}") | ||
| @Operation( | ||
| operationId = "getWorkflowInstanceStatesByWorkflowInstanceId", | ||
| summary = "Get all Workflow Instance States for a Workflow Instance id", | ||
| description = | ||
| "Get Workflow Instance States for a Workflow Instance id, ordered by timestamp " | ||
| + "ascending. Id-based lookup is stable across WorkflowDefinition renames because " | ||
| + "the underlying query filters on the workflowInstanceId column directly instead " | ||
| + "of an FQN-hash derived from the definition name. By default every stage the " | ||
| + "workflow entered is returned, including internal automation stages (policy " | ||
| + "enforcement, attribute updates, start/end events). Pass " | ||
| + "onlyTaskTransitions=true to narrow the response to stages driven by a " | ||
| + "task transition, identified generically by the presence of a " | ||
| + "<stageName>_transitionId entry in the stage's variables map, which is written " | ||
| + "only by user-task nodes when a user resolves the task. Generic across any " | ||
| + "workflow that has task nodes.", | ||
| responses = { | ||
| @ApiResponse( | ||
| responseCode = "200", | ||
| description = "The Workflow Instance States", | ||
| content = | ||
| @Content( | ||
| mediaType = "application/json", | ||
| schema = @Schema(implementation = WorkflowInstanceStateResultList.class))) | ||
| }) | ||
| public ResultList<WorkflowInstanceState> listByWorkflowInstanceId( | ||
| @Context SecurityContext securityContext, | ||
| @Parameter(description = "Workflow Instance ID", schema = @Schema(type = "UUID")) | ||
| @PathParam("workflowInstanceId") | ||
| UUID workflowInstanceId, | ||
| @Parameter( | ||
| description = | ||
| "When true, return only stages driven by a task transition — i.e. rows whose " | ||
| + "variables map contains a <stageName>_transitionId entry. Defaults to " | ||
| + "false, which returns every stage the workflow entered.", | ||
| schema = @Schema(type = "boolean")) | ||
| @DefaultValue("false") | ||
| @QueryParam("onlyTaskTransitions") | ||
| boolean onlyTaskTransitions) { | ||
| OperationContext operationContext = | ||
| new OperationContext(Entity.WORKFLOW_DEFINITION, MetadataOperation.VIEW_ALL); | ||
| ResourceContextInterface resourceContext = ReportDataContext.builder().build(); | ||
| authorizer.authorize(securityContext, operationContext, resourceContext); | ||
| List<WorkflowInstanceState> states = repository.listAllStatesForInstance(workflowInstanceId); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This endpoint loads and serializes every state for the instance without a limit or time range. A long-running or looping workflow can accumulate enough rows to create a slow response and significant service memory pressure; retain the existing endpoint's pagination or timestamp bounds for this ID-based lookup. Context Used: CLAUDE.md (source) |
||
| if (onlyTaskTransitions) { | ||
| states = states.stream().filter(WorkflowInstanceStateResource::isTaskTransition).toList(); | ||
| } | ||
| return new ResultList<>(states, null, null, states.size()); | ||
| } | ||
|
|
||
| private static boolean isTaskTransition(WorkflowInstanceState state) { | ||
| Stage stage = state == null ? null : state.getStage(); | ||
| if (stage == null || stage.getName() == null) { | ||
| return false; | ||
| } | ||
| Map<String, Object> variables = stage.getVariables(); | ||
| return variables != null && variables.containsKey(stage.getName() + "_transitionId"); | ||
| } | ||
|
|
||
| @GET | ||
| @Path("/{id}") | ||
| @Operation( | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The test queries the filtered history while
approvalTaskis still open. Its_transitionIdis persisted only when the task is resolved and the stage ends, so the filter removes the only task stage andfilteredDatais empty. Resolve the task before this request, or expect no task transitions while it remains open.Context Used: CLAUDE.md (source)