Skip to content

Conversation

@QuantumGhost
Copy link
Collaborator

@QuantumGhost QuantumGhost commented Nov 13, 2025

Summary

This PR:

  1. Convert pause_reason to pause_reasons in GraphExecution and relevant classes. Change the field from a scalar value to a list that can contain multiple PauseReason objects, ensuring all pause events are properly captured.
  2. Introduce a new pause_metadata field to the WorkflowPause model to store structured information about specific pause events.

Resolves #28195

Screenshots

N/A

Checklist

  • This change requires a documentation update, included: Dify Document
  • I understand that this PR may be closed in case there was no previous discussion or issues. (This doesn't apply to typos!)
  • I've added a test for each change that was introduced, and I tried as much as possible to make a single atomic change.
  • I've updated the documentation accordingly.
  • I ran dev/reformat(backend) and cd web && npx lint-staged(frontend) to appease the lint gods

@QuantumGhost QuantumGhost changed the title Feat/adjust pause reason and model Enhanced GraphEngine Pause Handling Nov 13, 2025
@QuantumGhost QuantumGhost marked this pull request as ready for review November 13, 2025 16:12
Copilot AI review requested due to automatic review settings November 13, 2025 16:12
@dosubot dosubot bot added size:L This PR changes 100-499 lines, ignoring generated files. 🌊 feat:workflow Workflow related stuff. labels Nov 13, 2025
Copilot finished reviewing on behalf of QuantumGhost November 13, 2025 16:17
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR enhances the GraphEngine pause handling system by converting the scalar pause_reason field to a list-based pause_reasons field and introducing a new pause_metadata database field to store structured information about pause events.

Key Changes:

  • Converted pause_reason (scalar) to pause_reasons (list) in GraphExecution and related classes to support multiple pause events
  • Added PauseMetadata model with pause_metadata database field to WorkflowPause for storing pause details
  • Simplified discriminator patterns in PauseReason union type
  • Updated all tests to use list-based pause reasons

Reviewed Changes

Copilot reviewed 12 out of 12 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
api/core/workflow/entities/pause_reason.py Simplified discriminator approach for PauseReason union type using Pydantic's Field(discriminator="TYPE")
api/core/workflow/entities/workflow_pause.py Added PauseDetail, PauseType, and HumanInputPause/SchedulingPause models; added get_pause_details() method to WorkflowPauseEntity
api/core/workflow/graph_engine/domain/graph_execution.py Changed pause_reason field to pause_reasons list; updated pause() method to append reasons
api/core/workflow/graph_engine/graph_engine.py Updated pause handling logic to work with pause_reasons list; clears list on resume
api/core/workflow/runtime/graph_runtime_state.py Added is_paused and pause_reasons to GraphExecutionProtocol
api/core/workflow/graph_events/graph.py Changed GraphRunPausedEvent.reason to reasons list field
api/core/workflow/graph_engine/event_management/event_manager.py Moved _notify_layers call outside critical section to reduce lock contention
api/models/workflow.py Added PauseMetadata model and pause_metadata field to WorkflowPause table
api/repositories/sqlalchemy_api_workflow_run_repository.py Implemented get_pause_details() method in _PrivateWorkflowPauseEntity
api/tests/unit_tests/core/workflow/graph_engine/test_command_system.py Updated tests to use reasons list instead of scalar reason
api/tests/unit_tests/core/app/layers/test_pause_state_persist_layer.py Updated test data factory to create events with reasons list
api/tests/test_containers_integration_tests/core/app/layers/test_pause_state_persist_layer.py Updated all test cases to use reasons list in pause events

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@QuantumGhost QuantumGhost force-pushed the feat/adjust-pause-reason-and-model branch from 351d419 to 1372cf4 Compare November 14, 2025 03:33
@laipz8200
Copy link
Member

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request significantly enhances the GraphEngine's pause handling by transitioning pause_reason from a single scalar value to a list of pause_reasons, and by introducing a new pause_metadata field to the WorkflowPause model. These changes allow for the capture of multiple pause events and structured metadata, greatly improving the granularity and flexibility of workflow pausing. The refactoring of Pydantic models for PauseReason is a good modernization, and the updates are consistently applied across the graph engine, persistence layer, and associated tests. The migration script correctly adds the new pause_metadata column with a sensible default. Overall, the changes are well-implemented and address the stated objectives.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces significant enhancements to the graph engine's pause handling. The transition from a single pause_reason to a list of pause_reasons is a great improvement for capturing multiple pause events. The introduction of pause_metadata with a structured Pydantic model is also a solid design choice for storing detailed pause information. The refactoring of PauseReason to use Pydantic's built-in discriminator is a nice cleanup.

I've found one minor issue related to the new HumanInputPause model and its usage in tests, where extra fields are being passed during instantiation but are not defined in the model. My suggestion aims to align the model with its intended usage.

Overall, this is a well-executed enhancement that improves the robustness and extensibility of the workflow pause mechanism.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request effectively enhances the graph engine's pause handling capabilities. The conversion of pause_reason to a list of pause_reasons is a logical improvement for capturing multiple pause events, and the changes have been applied consistently across the codebase. The introduction of the pause_metadata field with its own structured Pydantic models is a solid addition for storing detailed pause information. The refactoring of pause_reason.py to use Pydantic's built-in discriminator is a nice touch for code simplification and maintainability. The integration and unit tests have been updated thoroughly to cover the new functionality. I have one minor suggestion in a test file to improve clarity.

@QuantumGhost
Copy link
Collaborator Author

/gemini review

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This PR enhances pause handling by converting pause_reason to a list pause_reasons to support multiple pause events, and introduces a new WorkflowPauseReason model and table to store structured details about each pause. The changes are extensive and touch many parts of the graph engine and repository layers.

While the overall direction is good, the implementation is incomplete. The logic to retrieve and reconstruct pause reasons (get_pause_reasons) is missing, and there's data loss when storing SchedulingPause reasons as the message field is not persisted. Additionally, the node_id is not being saved for pause reasons. These issues should be addressed to make the feature fully functional. I've left specific comments on the relevant files.

Comment on lines +376 to +393
for reason in pause_reasons:
if isinstance(reason, HumanInputRequired):
# TODO(QuantumGhost): record node_id for `WorkflowPauseReason`
pause_reason_model = WorkflowPauseReason(
pause_id=pause_model.id,
type_=reason.TYPE,
form_id=reason.form_id,
)
elif isinstance(reason, SchedulingPause):
pause_reason_model = WorkflowPauseReason(
pause_id=pause_model.id,
type_=reason.TYPE,
)
else:
raise AssertionError(f"unkown reason type: {type(reason)}")

pause_reason_models.append(pause_reason_model)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

There are a couple of issues in this loop that will lead to data loss or incorrect data being stored:

  1. For SchedulingPause, the message field is not being saved. The WorkflowPauseReason database model is missing a column for it. This should be added to the model and the migration, and then saved here.
  2. For all pause reasons, the node_id is not being recorded, as noted by the TODO. The node_id of the node that triggered the pause should be passed and saved here. The database column is non-nullable.

Comment on lines +889 to +896
def get_pause_reasons(self) -> Sequence[PauseReason]:
# TODO(QuantumGhost): rebuild PauseReason from models
return []
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

This method is not fully implemented and returns an empty list. This prevents consumers of WorkflowPauseEntity from accessing the pause reasons, which is a core goal of this pull request. This method should be implemented to reconstruct the PauseReason objects from the _reason_models data stored in the entity.

Comment on lines +1738 to +1731
# `puase_id` represents the identifier of the pause,
# correspond to the `id` field of `WorkflowPause`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is a typo in the comment. It should be pause_id instead of puase_id.

Suggested change
# `puase_id` represents the identifier of the pause,
# correspond to the `id` field of `WorkflowPause`.
# `pause_id` represents the identifier of the pause,
# correspond to the `id` field of `WorkflowPause`.

QuantumGhost and others added 7 commits November 20, 2025 20:58
To avoid losing pause reason dataa while multiple nodes yielded
`PauseRequestedEvent`.
add a linting rule to disallow import core.workflow.runtime from
core.workflow.entities
- Split `pause_metadata` into a dedicated table `WorkflowPauseReason`.
- Save `pause_reasons` directly in the `APIWorkflowRunRepository`.
@QuantumGhost QuantumGhost force-pushed the feat/adjust-pause-reason-and-model branch from f6b0153 to 8858fda Compare November 20, 2025 13:19
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

🌊 feat:workflow Workflow related stuff. size:L This PR changes 100-499 lines, ignoring generated files.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Enhanced GraphEngine Pause Handling

2 participants