Skip to content

Commit dacd457

Browse files
laipz8200zxhlyh
andauthored
feat: add workflow parallel depth limit configuration (#11460)
Signed-off-by: -LAN- <[email protected]> Co-authored-by: zxhlyh <[email protected]>
1 parent 7b03a03 commit dacd457

File tree

10 files changed

+52
-5
lines changed

10 files changed

+52
-5
lines changed

api/.env.example

+1
Original file line numberDiff line numberDiff line change
@@ -399,6 +399,7 @@ INDEXING_MAX_SEGMENTATION_TOKENS_LENGTH=4000
399399
WORKFLOW_MAX_EXECUTION_STEPS=500
400400
WORKFLOW_MAX_EXECUTION_TIME=1200
401401
WORKFLOW_CALL_MAX_DEPTH=5
402+
WORKFLOW_PARALLEL_DEPTH_LIMIT=3
402403
MAX_VARIABLE_SIZE=204800
403404

404405
# App configuration

api/configs/feature/__init__.py

+5
Original file line numberDiff line numberDiff line change
@@ -433,6 +433,11 @@ class WorkflowConfig(BaseSettings):
433433
default=5,
434434
)
435435

436+
WORKFLOW_PARALLEL_DEPTH_LIMIT: PositiveInt = Field(
437+
description="Maximum allowed depth for nested parallel executions",
438+
default=3,
439+
)
440+
436441
MAX_VARIABLE_SIZE: PositiveInt = Field(
437442
description="Maximum size in bytes for a single variable in workflows. Default to 200 KB.",
438443
default=200 * 1024,

api/controllers/console/app/workflow.py

+15
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
from werkzeug.exceptions import Forbidden, InternalServerError, NotFound
77

88
import services
9+
from configs import dify_config
910
from controllers.console import api
1011
from controllers.console.app.error import ConversationCompletedError, DraftWorkflowNotExist, DraftWorkflowNotSync
1112
from controllers.console.app.wraps import get_app_model
@@ -426,7 +427,21 @@ def post(self, app_model: App):
426427
}
427428

428429

430+
class WorkflowConfigApi(Resource):
431+
"""Resource for workflow configuration."""
432+
433+
@setup_required
434+
@login_required
435+
@account_initialization_required
436+
@get_app_model(mode=[AppMode.ADVANCED_CHAT, AppMode.WORKFLOW])
437+
def get(self, app_model: App):
438+
return {
439+
"parallel_depth_limit": dify_config.WORKFLOW_PARALLEL_DEPTH_LIMIT,
440+
}
441+
442+
429443
api.add_resource(DraftWorkflowApi, "/apps/<uuid:app_id>/workflows/draft")
444+
api.add_resource(WorkflowConfigApi, "/apps/<uuid:app_id>/workflows/draft/config")
430445
api.add_resource(AdvancedChatDraftWorkflowRunApi, "/apps/<uuid:app_id>/advanced-chat/workflows/draft/run")
431446
api.add_resource(DraftWorkflowRunApi, "/apps/<uuid:app_id>/workflows/draft/run")
432447
api.add_resource(WorkflowTaskStopApi, "/apps/<uuid:app_id>/workflow-runs/tasks/<string:task_id>/stop")

api/core/workflow/graph_engine/entities/graph.py

+4-1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
from pydantic import BaseModel, Field
66

7+
from configs import dify_config
78
from core.workflow.graph_engine.entities.run_condition import RunCondition
89
from core.workflow.nodes import NodeType
910
from core.workflow.nodes.answer.answer_stream_generate_router import AnswerStreamGeneratorRouter
@@ -170,7 +171,9 @@ def init(cls, graph_config: Mapping[str, Any], root_node_id: Optional[str] = Non
170171
for parallel in parallel_mapping.values():
171172
if parallel.parent_parallel_id:
172173
cls._check_exceed_parallel_limit(
173-
parallel_mapping=parallel_mapping, level_limit=3, parent_parallel_id=parallel.parent_parallel_id
174+
parallel_mapping=parallel_mapping,
175+
level_limit=dify_config.WORKFLOW_PARALLEL_DEPTH_LIMIT,
176+
parent_parallel_id=parallel.parent_parallel_id,
174177
)
175178

176179
# init answer stream generate routes

api/tests/unit_tests/configs/test_dify_config.py

+2
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ def test_dify_config(example_env_file):
5959
# annotated field with configured value
6060
assert config.HTTP_REQUEST_MAX_WRITE_TIMEOUT == 30
6161

62+
assert config.WORKFLOW_PARALLEL_DEPTH_LIMIT == 3
63+
6264

6365
# NOTE: If there is a `.env` file in your Workspace, this test might not succeed as expected.
6466
# This is due to `pymilvus` loading all the variables from the `.env` file into `os.environ`.

docker/.env.example

+1
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,7 @@ WORKFLOW_MAX_EXECUTION_STEPS=500
699699
WORKFLOW_MAX_EXECUTION_TIME=1200
700700
WORKFLOW_CALL_MAX_DEPTH=5
701701
MAX_VARIABLE_SIZE=204800
702+
WORKFLOW_PARALLEL_DEPTH_LIMIT=3
702703
WORKFLOW_FILE_UPLOAD_LIMIT=10
703704

704705
# HTTP request node in workflow configuration

docker/docker-compose.yaml

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ x-shared-env: &shared-api-worker-env
1818
LOG_DATEFORMAT: ${LOG_DATEFORMAT:-"%Y-%m-%d %H:%M:%S"}
1919
LOG_TZ: ${LOG_TZ:-UTC}
2020
DEBUG: ${DEBUG:-false}
21-
SENTRY_DSN: ${SENTRY_DSN:-}
2221
FLASK_DEBUG: ${FLASK_DEBUG:-false}
2322
SECRET_KEY: ${SECRET_KEY:-sk-9f73s3ljTXVcMT3Blb3ljTqtsKiGHXVcMT3BlbkFJLK7U}
2423
INIT_PASSWORD: ${INIT_PASSWORD:-}
@@ -260,6 +259,7 @@ x-shared-env: &shared-api-worker-env
260259
UPLOAD_IMAGE_FILE_SIZE_LIMIT: ${UPLOAD_IMAGE_FILE_SIZE_LIMIT:-10}
261260
UPLOAD_VIDEO_FILE_SIZE_LIMIT: ${UPLOAD_VIDEO_FILE_SIZE_LIMIT:-100}
262261
UPLOAD_AUDIO_FILE_SIZE_LIMIT: ${UPLOAD_AUDIO_FILE_SIZE_LIMIT:-50}
262+
SENTRY_DSN: ${SENTRY_DSN:-}
263263
API_SENTRY_DSN: ${API_SENTRY_DSN:-}
264264
API_SENTRY_TRACES_SAMPLE_RATE: ${API_SENTRY_TRACES_SAMPLE_RATE:-1.0}
265265
API_SENTRY_PROFILES_SAMPLE_RATE: ${API_SENTRY_PROFILES_SAMPLE_RATE:-1.0}
@@ -299,6 +299,7 @@ x-shared-env: &shared-api-worker-env
299299
WORKFLOW_MAX_EXECUTION_TIME: ${WORKFLOW_MAX_EXECUTION_TIME:-1200}
300300
WORKFLOW_CALL_MAX_DEPTH: ${WORKFLOW_CALL_MAX_DEPTH:-5}
301301
MAX_VARIABLE_SIZE: ${MAX_VARIABLE_SIZE:-204800}
302+
WORKFLOW_PARALLEL_DEPTH_LIMIT: ${WORKFLOW_PARALLEL_DEPTH_LIMIT:-3}
302303
WORKFLOW_FILE_UPLOAD_LIMIT: ${WORKFLOW_FILE_UPLOAD_LIMIT:-10}
303304
HTTP_REQUEST_NODE_MAX_BINARY_SIZE: ${HTTP_REQUEST_NODE_MAX_BINARY_SIZE:-10485760}
304305
HTTP_REQUEST_NODE_MAX_TEXT_SIZE: ${HTTP_REQUEST_NODE_MAX_TEXT_SIZE:-1048576}

web/app/components/workflow/hooks/use-workflow.ts

+6-3
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import {
5757
import I18n from '@/context/i18n'
5858
import { CollectionType } from '@/app/components/tools/types'
5959
import { CUSTOM_ITERATION_START_NODE } from '@/app/components/workflow/nodes/iteration-start/constants'
60+
import { useWorkflowConfig } from '@/service/use-workflow'
6061

6162
export const useIsChatMode = () => {
6263
const appDetail = useAppStore(s => s.appDetail)
@@ -69,7 +70,9 @@ export const useWorkflow = () => {
6970
const { locale } = useContext(I18n)
7071
const store = useStoreApi()
7172
const workflowStore = useWorkflowStore()
73+
const appId = useStore(s => s.appId)
7274
const nodesExtraData = useNodesExtraData()
75+
const { data: workflowConfig } = useWorkflowConfig(appId)
7376
const setPanelWidth = useCallback((width: number) => {
7477
localStorage.setItem('workflow-node-panel-width', `${width}`)
7578
workflowStore.setState({ panelWidth: width })
@@ -336,15 +339,15 @@ export const useWorkflow = () => {
336339
for (let i = 0; i < parallelList.length; i++) {
337340
const parallel = parallelList[i]
338341

339-
if (parallel.depth > PARALLEL_DEPTH_LIMIT) {
342+
if (parallel.depth > (workflowConfig?.parallel_depth_limit || PARALLEL_DEPTH_LIMIT)) {
340343
const { setShowTips } = workflowStore.getState()
341-
setShowTips(t('workflow.common.parallelTip.depthLimit', { num: PARALLEL_DEPTH_LIMIT }))
344+
setShowTips(t('workflow.common.parallelTip.depthLimit', { num: (workflowConfig?.parallel_depth_limit || PARALLEL_DEPTH_LIMIT) }))
342345
return false
343346
}
344347
}
345348

346349
return true
347-
}, [t, workflowStore])
350+
}, [t, workflowStore, workflowConfig?.parallel_depth_limit])
348351

349352
const isValidConnection = useCallback(({ source, sourceHandle, target }: Connection) => {
350353
const {

web/service/use-workflow.ts

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { useQuery } from '@tanstack/react-query'
2+
import { get } from './base'
3+
import type { WorkflowConfigResponse } from '@/types/workflow'
4+
5+
const NAME_SPACE = 'workflow'
6+
7+
export const useWorkflowConfig = (appId: string) => {
8+
return useQuery({
9+
queryKey: [NAME_SPACE, 'config', appId],
10+
queryFn: () => get<WorkflowConfigResponse>(`/apps/${appId}/workflows/draft/config`),
11+
})
12+
}

web/types/workflow.ts

+4
Original file line numberDiff line numberDiff line change
@@ -333,3 +333,7 @@ export type ConversationVariableResponse = {
333333
}
334334

335335
export type IterationDurationMap = Record<string, number>
336+
337+
export type WorkflowConfigResponse = {
338+
parallel_depth_limit: number
339+
}

0 commit comments

Comments
 (0)