From 9898730cc58e31ae59972b2930eede17cba81c1e Mon Sep 17 00:00:00 2001 From: Yeuoly Date: Wed, 10 Sep 2025 17:22:09 +0800 Subject: [PATCH] feat: add webhook node limit validation (max 5 per workflow) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add MAX_WEBHOOK_NODES_PER_WORKFLOW constant set to 5 - Validate webhook node count in sync_webhook_relationships method - Raise ValueError when workflow exceeds webhook node limit - Block workflow save when limit is exceeded to ensure data integrity - Provide clear error message indicating current count and maximum allowed 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- api/controllers/console/app/workflow_trigger.py | 2 +- .../event_handlers/sync_webhook_when_app_created.py | 5 ++++- api/services/webhook_service.py | 11 +++++++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/api/controllers/console/app/workflow_trigger.py b/api/controllers/console/app/workflow_trigger.py index c303e2defa..abfe882b67 100644 --- a/api/controllers/console/app/workflow_trigger.py +++ b/api/controllers/console/app/workflow_trigger.py @@ -167,7 +167,7 @@ class AppTriggersApi(Resource): """Get app triggers list""" assert isinstance(current_user, Account) assert current_user.current_tenant_id is not None - + with Session(db.engine) as session: # Get all triggers for this app using select API triggers = ( diff --git a/api/events/event_handlers/sync_webhook_when_app_created.py b/api/events/event_handlers/sync_webhook_when_app_created.py index f5e1d1e925..6a5ef2c654 100644 --- a/api/events/event_handlers/sync_webhook_when_app_created.py +++ b/api/events/event_handlers/sync_webhook_when_app_created.py @@ -1,8 +1,12 @@ +import logging + from events.app_event import app_draft_workflow_was_synced from models.model import App, AppMode from models.workflow import Workflow from services.webhook_service import WebhookService +logger = logging.getLogger(__name__) + @app_draft_workflow_was_synced.connect def handle(sender, synced_draft_workflow: Workflow, **kwargs): @@ -15,5 +19,4 @@ def handle(sender, synced_draft_workflow: Workflow, **kwargs): # only handle workflow app, chatflow is not supported yet return - # sync webhook relationships in DB WebhookService.sync_webhook_relationships(app, synced_draft_workflow) diff --git a/api/services/webhook_service.py b/api/services/webhook_service.py index 5b35b36ad1..e0f09993d3 100644 --- a/api/services/webhook_service.py +++ b/api/services/webhook_service.py @@ -33,6 +33,7 @@ class WebhookService: """Service for handling webhook operations.""" __WEBHOOK_NODE_CACHE_KEY__ = "webhook_nodes" + MAX_WEBHOOK_NODES_PER_WORKFLOW = 5 # Maximum allowed webhook nodes per workflow @classmethod def get_webhook_trigger_and_workflow( @@ -611,6 +612,9 @@ class WebhookService: Approach: Frequent DB operations may cause performance issues, using Redis to cache it instead. If any record exists, cache it. + + Limits: + - Maximum 5 webhook nodes per workflow """ class Cache(BaseModel): @@ -624,6 +628,13 @@ class WebhookService: nodes_id_in_graph = [node_id for node_id, _ in workflow.walk_nodes(NodeType.TRIGGER_WEBHOOK)] + # Check webhook node limit + if len(nodes_id_in_graph) > cls.MAX_WEBHOOK_NODES_PER_WORKFLOW: + raise ValueError( + f"Workflow exceeds maximum webhook node limit. " + f"Found {len(nodes_id_in_graph)} webhook nodes, maximum allowed is {cls.MAX_WEBHOOK_NODES_PER_WORKFLOW}" + ) + not_found_in_cache: list[str] = [] for node_id in nodes_id_in_graph: # firstly check if the node exists in cache