feat: add webhook node limit validation (max 5 per workflow)

- 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 <noreply@anthropic.com>
This commit is contained in:
Yeuoly 2025-09-10 17:22:09 +08:00
parent b0f1e55a87
commit 9898730cc5
3 changed files with 16 additions and 2 deletions

View File

@ -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 = (

View File

@ -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)

View File

@ -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