Code node execution time is very long. #22167

Open
opened 2026-02-21 20:16:01 -05:00 by yindo · 6 comments
Owner

Originally created by @gongshaojie12 on GitHub (Feb 9, 2026).

Self Checks

  • I have read the Contributing Guide and Language Policy.
  • This is only for bug report, if you would like to ask a question, please head to Discussions.
  • I have searched for existing issues search for existing issues, including closed ones.
  • I confirm that I am using English to submit this report, otherwise it will be closed.
  • 【中文用户 & Non English User】请使用英语提交,否则会被关闭 :)
  • Please do not modify this template :) and fill in all the required fields.

Dify version

1.12.1

Cloud or Self Hosted

Self Hosted (Docker)

Steps to reproduce

I built an application using a workflow that generates images with Google Vertex AI. The main nodes consist of calling the API to generate images and uploading the generated images to Dify storage to produce accessible URLs. However, both the image generation node and the image storage node are currently executing very slowly. The specific workflow diagram is as follows:

Image

The specific code for the image generation node is as follows:

import time

import json
# import logging
from typing import Optional, Tuple

import requests
from requests import Response, RequestException

GEMINI_URL = ""

def build_payload(system_prompt:str,prompt:str,aspectRatio:str,imageSize:str) -> dict:
    return {
    "contents": [
        {
            "role": "user",
            "parts": [
                {
                    "text": prompt
                }
            ]
        }
    ],
    "systemInstruction":{
        "parts":[
        {
        "text":system_prompt
        }
        ]
        }
    , "generationConfig": {
        "temperature": 1
        ,"maxOutputTokens": 32768
        ,"responseModalities": ["IMAGE"]
        ,"topP": 0.95
        ,"imageConfig": {
            "aspectRatio": aspectRatio
            ,"imageSize": imageSize
            ,"imageOutputOptions": {
                "mimeType": "image/png"
            }
            ,"personGeneration": "ALLOW_ALL"
        }
    },
    "safetySettings": [
        {
            "category": "HARM_CATEGORY_HATE_SPEECH",
            "threshold": "OFF"
        },
        {
            "category": "HARM_CATEGORY_DANGEROUS_CONTENT",
            "threshold": "OFF"
        },
        {
            "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT",
            "threshold": "OFF"
        },
        {
            "category": "HARM_CATEGORY_HARASSMENT",
            "threshold": "OFF"
        }
    ]
    }


def extract_inline_image(data: dict) -> Optional[str]:
    """
    防御式解析 inlineData
    返回 base64 字符串,找不到则返回 None
    """
    try:
        candidates = data.get("candidates", [])
        for candidate in candidates:
            content = candidate.get("content", {})
            parts = content.get("parts", [])
            for part in parts:
                inline_data = part.get("inlineData")
                if inline_data and inline_data.get("data"):
                    return inline_data["data"]
    except Exception:
        # 任何解析异常都视为失败,触发重试
        return None

    return None


def generate_image_with_retry(
        system_prompt:str,
        prompt: str,
        aspectRatio: str,
        imageSize: str,
        API_KEY: str,
        max_retries: int = 10,
        timeout: int = 600,
        base_delay: float = 1.5,
):
    """
    返回 inlineData.base64
    如果最终失败,直接抛异常
    """

    headers = {
        "Content-Type": "application/json",
    }

    payload = build_payload(system_prompt,prompt,aspectRatio,imageSize)

    for attempt in range(1, max_retries + 1):
        try:
            resp: Response = requests.post(
                GEMINI_URL,
                params={"key": API_KEY},
                headers=headers,
                json=payload,
                timeout=timeout,
            )

            # 情况一:HTTP status ≠ 200
            if resp.status_code != 200:
                
                raise RuntimeError(f"Non-200 status: {resp.status_code}")

            # 尝试解析 JSON
            try:
                data = resp.json()
            except json.JSONDecodeError:
                
                raise RuntimeError("Invalid JSON response")

            # 情况二:status=200,但 inlineData 为空
            image_base64 = extract_inline_image(data)
            if not image_base64:
                # logging.warning(
                #     "inlineData is empty or missing, retrying..."
                # )
                raise RuntimeError("inlineData empty")

            return data, attempt

        except (RequestException, RuntimeError) as e:
            if attempt >= max_retries:
                # logging.error(" Exhausted retries, giving up")
                raise

            sleep_time = base_delay * (2 ** (attempt - 1))
            # logging.info(f"Retrying in {sleep_time:.1f}s, reason: {e}")
            time.sleep(sleep_time)

    # 理论上不会走到这里
    raise RuntimeError("Unexpected failure")

def main(system_prompt: str, prompt: str, aspectRatio: str, imageSize: str, API_KEY):
    image_data, attempt = generate_image_with_retry(system_prompt,prompt,aspectRatio,imageSize,API_KEY)
    image_data_str = json.dumps(image_data, ensure_ascii=False)
    return {
        "status_code":200,
        "attempt":attempt,
        "body": image_data_str,
    }

The output variables of the image generation node are as follows:

Image

The specific code for the image storage node is as follows,The value of upload_url is: http://ip/v1/files/upload, which is the file upload API endpoint for this workflow.

import json
import base64
import uuid
import time
import requests
from typing import Optional
from typing import (
    List,
    Union,
    Optional,
    Dict,
    Any,
    Tuple,
)
# from dify.api.core.tools.tool_file_manager import ToolFileManager

def _upload_to_dify_direct(
    image_data: Union[List[dict], Any],
    user_id: str,
    api_base: str,
    api_key: str,
    mime_type: str = None,
    max_retries: int = 3,
    initial_delay: float = 1.0,
) -> Union[List[dict], dict]:
    """
    [同步 + 自动重试版本]
    将图片或文件上传到 Dify。支持失败重试机制。
    """
    import base64
    import json
    import mimetypes
    import time
    import uuid
    import requests

    upload_url = api_base
    headers = {"Authorization": f"Bearer {api_key}"}

    # === 内部函数:带重试逻辑的单文件上传 ===
    def _upload_single_file_with_retry(session, current_data, current_mime):
        # 1. 数据预处理(只做一次)
        try:
            if isinstance(current_data, bytes):
                file_content = current_data
            else:
                img_str = str(current_data)
                if "base64," in img_str:
                    img_str = img_str.split("base64,")[1]
                try:
                    file_content = base64.b64decode(img_str)
                except Exception:
                    file_content = img_str.encode("utf-8")
        except Exception as e:
            print(f"[Dify] Data decode error, skipping: {e}")
            raise

        # === 文件后缀生成逻辑(保持你原来的优化) ===
        ext = "bin"
        if current_mime:
            guess_ext = mimetypes.guess_extension(current_mime)
            if guess_ext:
                ext = guess_ext.lstrip(".")
            else:
                ext = current_mime.split("/")[-1]

        print(
            f"current_mime==================================>{current_mime}. "
            f"ext====================================>{ext}"
        )

        filename = f"dify_upload_{uuid.uuid4().hex[:8]}.{ext}"

        last_exception = None

        # 2. 重试循环
        for attempt in range(max_retries + 1):
            try:
                files = {
                    "file": (
                        filename,
                        file_content,
                        current_mime,
                    )
                }
                data = {"user": user_id}

                response = session.post(
                    upload_url,
                    headers=headers,
                    files=files,
                    data=data,
                    timeout=60,
                )

                if response.status_code in (200, 201):
                    result = response.json()
                    source_url = result.get("source_url","")

                    return {
                        "source_url": source_url
                    }

                elif 400 <= response.status_code < 500 and response.status_code != 429:
                    raise ValueError(
                        f"Dify Error {response.status_code}: {response.text}"
                    )
                else:
                    raise requests.HTTPError(
                        f"HTTP {response.status_code} - {response.text}"
                    )

            except (requests.RequestException, ValueError) as e:
                last_exception = e
                if isinstance(e, ValueError):
                    raise

                if attempt < max_retries:
                    sleep_time = initial_delay * (2 ** attempt)
                    print(
                        f"[Dify Upload] Attempt {attempt + 1}/{max_retries} failed: {e}. "
                        f"Retrying in {sleep_time}s..."
                    )
                    time.sleep(sleep_time)
                else:
                    print(f"[Dify Upload] All {max_retries + 1} attempts failed.")

        if last_exception:
            raise last_exception
        raise Exception("Unknown upload failure")

    # === 主逻辑 ===
    with requests.Session() as session:
        # 场景 1:列表
        if isinstance(image_data, list):
            results = []
            for item in image_data:
                inline = item.get("inline_data", {})
                img_content = inline.get("data")
                img_mime = inline.get("mime_type")
                if img_content:
                    results.append(
                        _upload_single_file_with_retry(
                            session, img_content, img_mime
                        )
                    )
            return results

        # 场景 2:单文件
        else:
            if not mime_type:
                mime_type = "image/png"
            return _upload_single_file_with_retry(
                session, image_data, mime_type
            )


def upload_base64_image(
    UPLOAD_URL: str,
    API_KEY: str,
    base64_str: str,
    filename: str = "gemini.jpg",
    mime_type: str = "image/jpeg",
    user: str = "nano-banana",
    max_retries: int = 3,
    timeout: int = 10,
) -> Optional[str]:
    """
    上传 base64 图片到 Dify files API(带重试)

    :param base64_str: 纯 base64 字符串(不包含 data:image/...)
    :param filename: 文件名
    :param mime_type: MIME 类型
    :param user: user 字段
    :param max_retries: 最大重试次数
    :param timeout: 请求超时时间(秒)
    :return: 成功返回 JSON,失败返回 None
    """

    # 1. base64 解码
    file_bytes = base64.b64decode(base64_str)

    headers = {
        "Authorization": f"Bearer {API_KEY}",
    }

    files = {
        "file": (filename, file_bytes, mime_type),
    }

    data = {
        "user": user,
    }

    for attempt in range(1, max_retries + 1):
        try:
            resp = requests.post(
                UPLOAD_URL,
                headers=headers,
                files=files,
                data=data,
                timeout=timeout,
            )

            if resp.status_code == 200:
                return resp.json().get("source_url","")

            print(
                f"[Attempt {attempt}] Upload failed, "
                f"status={resp.status_code}, body={resp.text}"
            )

        except requests.RequestException as e:
            print(f"[Attempt {attempt}] Request error: {e}")

        if attempt < max_retries:
            time.sleep(2 ** attempt)  # 指数退避

    return None

def main(body: str, status_code: float, UPLOAD_URL: str, DIFY_API_KEY: str):

    all_images_urls = []
    image_parts: List[Dict[str, Any]] = []
    image_url = None
    if status_code==200:
        response = json.loads(body)
        candidates = response.get("candidates",[])
        candidate = candidates[0] if len(candidates)>0 else {}

        # Process content parts - use new streamlined approach
        parts = candidate.get("content",{}).get("parts",None)
        if parts:
            for part in parts:
                inline_data = part.get("inlineData",None)
                if inline_data:
                    # Fallback: return as base64 data URL if no request/user context
                    mime_type = inline_data.get("mimeType",None)
                    image_data = inline_data.get("data",None)
                    image_parts.append({"inline_data": {"mime_type": mime_type, "data": image_data}})
    upload_results = _upload_to_dify_direct(image_data=image_parts,user_id="dify-self",api_base=UPLOAD_URL,api_key=DIFY_API_KEY)

    if len(upload_results)>0:
        for ur in upload_results:
            all_images_urls.append(ur["source_url"])
        image_url = "![]({})".format(all_images_urls[0])
    
    return {
        "all_images_urls": all_images_urls,
        "image_url":image_url
    }

The output variables of the image storage node are as follows:

Image

The execution time for parts of the workflow is as follows:

Image Image Image

However, sometimes the entire workflow executes normally, as shown below:

Image Image Image

No error logs were generated in the backend. What could be causing the code nodes to execute so slowly?

✔️ Expected Behavior

The code execution time is within a reasonable range.

Actual Behavior

The code execution time is excessively long and abnormal.

Originally created by @gongshaojie12 on GitHub (Feb 9, 2026). ### Self Checks - [x] I have read the [Contributing Guide](https://github.com/langgenius/dify/blob/main/CONTRIBUTING.md) and [Language Policy](https://github.com/langgenius/dify/issues/1542). - [x] This is only for bug report, if you would like to ask a question, please head to [Discussions](https://github.com/langgenius/dify/discussions/categories/general). - [x] I have searched for existing issues [search for existing issues](https://github.com/langgenius/dify/issues), including closed ones. - [x] I confirm that I am using English to submit this report, otherwise it will be closed. - [x] 【中文用户 & Non English User】请使用英语提交,否则会被关闭 :) - [x] Please do not modify this template :) and fill in all the required fields. ### Dify version 1.12.1 ### Cloud or Self Hosted Self Hosted (Docker) ### Steps to reproduce I built an application using a workflow that generates images with Google Vertex AI. The main nodes consist of calling the API to generate images and uploading the generated images to Dify storage to produce accessible URLs. However, both the image generation node and the image storage node are currently executing very slowly. The specific workflow diagram is as follows: <img width="1528" height="280" alt="Image" src="https://github.com/user-attachments/assets/888ec137-a6d3-400f-9cb8-c50512dc087f" /> The specific code for the image generation node is as follows: ``` import time import json # import logging from typing import Optional, Tuple import requests from requests import Response, RequestException GEMINI_URL = "" def build_payload(system_prompt:str,prompt:str,aspectRatio:str,imageSize:str) -> dict: return { "contents": [ { "role": "user", "parts": [ { "text": prompt } ] } ], "systemInstruction":{ "parts":[ { "text":system_prompt } ] } , "generationConfig": { "temperature": 1 ,"maxOutputTokens": 32768 ,"responseModalities": ["IMAGE"] ,"topP": 0.95 ,"imageConfig": { "aspectRatio": aspectRatio ,"imageSize": imageSize ,"imageOutputOptions": { "mimeType": "image/png" } ,"personGeneration": "ALLOW_ALL" } }, "safetySettings": [ { "category": "HARM_CATEGORY_HATE_SPEECH", "threshold": "OFF" }, { "category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "OFF" }, { "category": "HARM_CATEGORY_SEXUALLY_EXPLICIT", "threshold": "OFF" }, { "category": "HARM_CATEGORY_HARASSMENT", "threshold": "OFF" } ] } def extract_inline_image(data: dict) -> Optional[str]: """ 防御式解析 inlineData 返回 base64 字符串,找不到则返回 None """ try: candidates = data.get("candidates", []) for candidate in candidates: content = candidate.get("content", {}) parts = content.get("parts", []) for part in parts: inline_data = part.get("inlineData") if inline_data and inline_data.get("data"): return inline_data["data"] except Exception: # 任何解析异常都视为失败,触发重试 return None return None def generate_image_with_retry( system_prompt:str, prompt: str, aspectRatio: str, imageSize: str, API_KEY: str, max_retries: int = 10, timeout: int = 600, base_delay: float = 1.5, ): """ 返回 inlineData.base64 如果最终失败,直接抛异常 """ headers = { "Content-Type": "application/json", } payload = build_payload(system_prompt,prompt,aspectRatio,imageSize) for attempt in range(1, max_retries + 1): try: resp: Response = requests.post( GEMINI_URL, params={"key": API_KEY}, headers=headers, json=payload, timeout=timeout, ) # 情况一:HTTP status ≠ 200 if resp.status_code != 200: raise RuntimeError(f"Non-200 status: {resp.status_code}") # 尝试解析 JSON try: data = resp.json() except json.JSONDecodeError: raise RuntimeError("Invalid JSON response") # 情况二:status=200,但 inlineData 为空 image_base64 = extract_inline_image(data) if not image_base64: # logging.warning( # "inlineData is empty or missing, retrying..." # ) raise RuntimeError("inlineData empty") return data, attempt except (RequestException, RuntimeError) as e: if attempt >= max_retries: # logging.error(" Exhausted retries, giving up") raise sleep_time = base_delay * (2 ** (attempt - 1)) # logging.info(f"Retrying in {sleep_time:.1f}s, reason: {e}") time.sleep(sleep_time) # 理论上不会走到这里 raise RuntimeError("Unexpected failure") def main(system_prompt: str, prompt: str, aspectRatio: str, imageSize: str, API_KEY): image_data, attempt = generate_image_with_retry(system_prompt,prompt,aspectRatio,imageSize,API_KEY) image_data_str = json.dumps(image_data, ensure_ascii=False) return { "status_code":200, "attempt":attempt, "body": image_data_str, } ``` The output variables of the image generation node are as follows: <img width="450" height="211" alt="Image" src="https://github.com/user-attachments/assets/bc9d0e9a-b671-46bc-9c04-5c0e60b45861" /> The specific code for the image storage node is as follows,The value of `upload_url` is: `http://ip/v1/files/upload`, which is the file upload API endpoint for this workflow. ``` import json import base64 import uuid import time import requests from typing import Optional from typing import ( List, Union, Optional, Dict, Any, Tuple, ) # from dify.api.core.tools.tool_file_manager import ToolFileManager def _upload_to_dify_direct( image_data: Union[List[dict], Any], user_id: str, api_base: str, api_key: str, mime_type: str = None, max_retries: int = 3, initial_delay: float = 1.0, ) -> Union[List[dict], dict]: """ [同步 + 自动重试版本] 将图片或文件上传到 Dify。支持失败重试机制。 """ import base64 import json import mimetypes import time import uuid import requests upload_url = api_base headers = {"Authorization": f"Bearer {api_key}"} # === 内部函数:带重试逻辑的单文件上传 === def _upload_single_file_with_retry(session, current_data, current_mime): # 1. 数据预处理(只做一次) try: if isinstance(current_data, bytes): file_content = current_data else: img_str = str(current_data) if "base64," in img_str: img_str = img_str.split("base64,")[1] try: file_content = base64.b64decode(img_str) except Exception: file_content = img_str.encode("utf-8") except Exception as e: print(f"[Dify] Data decode error, skipping: {e}") raise # === 文件后缀生成逻辑(保持你原来的优化) === ext = "bin" if current_mime: guess_ext = mimetypes.guess_extension(current_mime) if guess_ext: ext = guess_ext.lstrip(".") else: ext = current_mime.split("/")[-1] print( f"current_mime==================================>{current_mime}. " f"ext====================================>{ext}" ) filename = f"dify_upload_{uuid.uuid4().hex[:8]}.{ext}" last_exception = None # 2. 重试循环 for attempt in range(max_retries + 1): try: files = { "file": ( filename, file_content, current_mime, ) } data = {"user": user_id} response = session.post( upload_url, headers=headers, files=files, data=data, timeout=60, ) if response.status_code in (200, 201): result = response.json() source_url = result.get("source_url","") return { "source_url": source_url } elif 400 <= response.status_code < 500 and response.status_code != 429: raise ValueError( f"Dify Error {response.status_code}: {response.text}" ) else: raise requests.HTTPError( f"HTTP {response.status_code} - {response.text}" ) except (requests.RequestException, ValueError) as e: last_exception = e if isinstance(e, ValueError): raise if attempt < max_retries: sleep_time = initial_delay * (2 ** attempt) print( f"[Dify Upload] Attempt {attempt + 1}/{max_retries} failed: {e}. " f"Retrying in {sleep_time}s..." ) time.sleep(sleep_time) else: print(f"[Dify Upload] All {max_retries + 1} attempts failed.") if last_exception: raise last_exception raise Exception("Unknown upload failure") # === 主逻辑 === with requests.Session() as session: # 场景 1:列表 if isinstance(image_data, list): results = [] for item in image_data: inline = item.get("inline_data", {}) img_content = inline.get("data") img_mime = inline.get("mime_type") if img_content: results.append( _upload_single_file_with_retry( session, img_content, img_mime ) ) return results # 场景 2:单文件 else: if not mime_type: mime_type = "image/png" return _upload_single_file_with_retry( session, image_data, mime_type ) def upload_base64_image( UPLOAD_URL: str, API_KEY: str, base64_str: str, filename: str = "gemini.jpg", mime_type: str = "image/jpeg", user: str = "nano-banana", max_retries: int = 3, timeout: int = 10, ) -> Optional[str]: """ 上传 base64 图片到 Dify files API(带重试) :param base64_str: 纯 base64 字符串(不包含 data:image/...) :param filename: 文件名 :param mime_type: MIME 类型 :param user: user 字段 :param max_retries: 最大重试次数 :param timeout: 请求超时时间(秒) :return: 成功返回 JSON,失败返回 None """ # 1. base64 解码 file_bytes = base64.b64decode(base64_str) headers = { "Authorization": f"Bearer {API_KEY}", } files = { "file": (filename, file_bytes, mime_type), } data = { "user": user, } for attempt in range(1, max_retries + 1): try: resp = requests.post( UPLOAD_URL, headers=headers, files=files, data=data, timeout=timeout, ) if resp.status_code == 200: return resp.json().get("source_url","") print( f"[Attempt {attempt}] Upload failed, " f"status={resp.status_code}, body={resp.text}" ) except requests.RequestException as e: print(f"[Attempt {attempt}] Request error: {e}") if attempt < max_retries: time.sleep(2 ** attempt) # 指数退避 return None def main(body: str, status_code: float, UPLOAD_URL: str, DIFY_API_KEY: str): all_images_urls = [] image_parts: List[Dict[str, Any]] = [] image_url = None if status_code==200: response = json.loads(body) candidates = response.get("candidates",[]) candidate = candidates[0] if len(candidates)>0 else {} # Process content parts - use new streamlined approach parts = candidate.get("content",{}).get("parts",None) if parts: for part in parts: inline_data = part.get("inlineData",None) if inline_data: # Fallback: return as base64 data URL if no request/user context mime_type = inline_data.get("mimeType",None) image_data = inline_data.get("data",None) image_parts.append({"inline_data": {"mime_type": mime_type, "data": image_data}}) upload_results = _upload_to_dify_direct(image_data=image_parts,user_id="dify-self",api_base=UPLOAD_URL,api_key=DIFY_API_KEY) if len(upload_results)>0: for ur in upload_results: all_images_urls.append(ur["source_url"]) image_url = "![]({})".format(all_images_urls[0]) return { "all_images_urls": all_images_urls, "image_url":image_url } ``` The output variables of the image storage node are as follows: <img width="457" height="167" alt="Image" src="https://github.com/user-attachments/assets/0a4edcab-3b32-4770-b60a-01a6dac39016" /> The execution time for parts of the workflow is as follows: <img width="657" height="369" alt="Image" src="https://github.com/user-attachments/assets/19f87b3d-78ba-427e-bd97-714dd70e109a" /> <img width="644" height="334" alt="Image" src="https://github.com/user-attachments/assets/5b48e8dd-2fad-41d5-9a82-ed19eece079e" /> <img width="669" height="351" alt="Image" src="https://github.com/user-attachments/assets/c80bfdad-5857-4ddc-8b70-d8fa38423c61" /> However, sometimes the entire workflow executes normally, as shown below: <img width="645" height="332" alt="Image" src="https://github.com/user-attachments/assets/caedd3d9-9e76-4d56-8dd1-ec123d6b9657" /> <img width="655" height="322" alt="Image" src="https://github.com/user-attachments/assets/aa7efacc-adb4-4d20-964f-0fe7c83d4bdd" /> <img width="644" height="331" alt="Image" src="https://github.com/user-attachments/assets/9c3e24e8-5f12-47c6-a94c-e6cd0ec3ba18" /> No error logs were generated in the backend. What could be causing the code nodes to execute so slowly? ### ✔️ Expected Behavior The code execution time is within a reasonable range. ### ❌ Actual Behavior The code execution time is excessively long and abnormal.
yindo added the 🐞 bug label 2026-02-21 20:16:01 -05:00
Author
Owner

@gongshaojie12 commented on GitHub (Feb 9, 2026):

Additionally, this workflow is called as a tool by other workflows, with a parallelism setting of 6 during invocation.

Image
@gongshaojie12 commented on GitHub (Feb 9, 2026): Additionally, this workflow is called as a tool by other workflows, with a parallelism setting of 6 during invocation. <img width="1098" height="664" alt="Image" src="https://github.com/user-attachments/assets/13b3bd4c-82de-45c7-8dd5-2269813017f1" />
Author
Owner

@dosubot[bot] commented on GitHub (Feb 9, 2026):

Thanks for the additional context — the parallelism of 6 is very likely contributing to your issue.

Key problem: The default GraphEngine max workers is 5, so with parallelism=6 calling nested workflows, you're creating queuing delays. Additionally, users have reported 7+ minute delays for simple code nodes when running parallel iterations — this is a known regression in v1.9.x+.

Recommended fixes:

  1. Configure GraphEngine workers in your .env:

    GRAPH_ENGINE_MIN_WORKERS=3
    GRAPH_ENGINE_MAX_WORKERS=10
    

    Without this, parallel iterations may execute sequentially.

  2. Reduce parallelism to 4-5 — staying under the default max workers helps avoid queuing

  3. Increase connection pool settings to handle nested workflow calls:

    SQLALCHEMY_POOL_SIZE=20
    SQLALCHEMY_MAX_OVERFLOW=10
    

    Parallel iterations can exhaust database connections, especially with nested workflow-as-tool calls.

  4. Increase Celery workers as mentioned earlier — each parallel branch adds to the queue load

The combination of parallelism=6 + nested workflow calls + default single Celery worker is a recipe for the variable delays you're experiencing.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

@dosubot[bot] commented on GitHub (Feb 9, 2026): <!-- Answer --> Thanks for the additional context — the parallelism of 6 is very likely contributing to your issue. **Key problem:** The [default GraphEngine max workers is 5](https://github.com/langgenius/dify/blob/1a050c9f8601c69d2bb626338fe8b985c5a46cf1/api/core/workflow/graph_engine/config.py), so with parallelism=6 calling nested workflows, you're creating queuing delays. Additionally, [users have reported 7+ minute delays for simple code nodes when running parallel iterations](https://github.com/langgenius/dify/issues/27821) — this is a known regression in v1.9.x+. **Recommended fixes:** 1. **Configure GraphEngine workers** in your `.env`: ``` GRAPH_ENGINE_MIN_WORKERS=3 GRAPH_ENGINE_MAX_WORKERS=10 ``` Without this, [parallel iterations may execute sequentially](https://github.com/langgenius/dify/discussions/26166). 2. **Reduce parallelism to 4-5** — staying under the default max workers helps avoid queuing 3. **Increase connection pool settings** to handle nested workflow calls: ``` SQLALCHEMY_POOL_SIZE=20 SQLALCHEMY_MAX_OVERFLOW=10 ``` [Parallel iterations can exhaust database connections](https://github.com/langgenius/dify/issues/27657), especially with nested workflow-as-tool calls. 4. **Increase Celery workers** as mentioned earlier — each parallel branch adds to the queue load The combination of parallelism=6 + nested workflow calls + default single Celery worker is a recipe for the variable delays you're experiencing. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/232b084c-8aee-4297-9f19-1c2253e183d1?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/232b084c-8aee-4297-9f19-1c2253e183d1?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/232b084c-8aee-4297-9f19-1c2253e183d1?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/232b084c-8aee-4297-9f19-1c2253e183d1?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/232b084c-8aee-4297-9f19-1c2253e183d1?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/232b084c-8aee-4297-9f19-1c2253e183d1?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/232b084c-8aee-4297-9f19-1c2253e183d1?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/6088a4f4-073a-43f3-b3d4-4f06fb0c05a0/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=Thanks%20for%20the%20additional%20context%20%E2%80%94%20the%20parallelism%20of%206%20is%20very%20likely%20contributing%20to%20your%20issue.%0A%0A%2A%2AKey%20problem%3A%2A%2A%20The%20%5Bdefault%20GraphEngine%20max%20workers%20is%205%5D%28https%3A//github.com/langgenius/dify/blob/1a050c9f8601c69d2bb626338fe8b985c5a46cf1/api/core/workflow/graph_engine/config.py%29%2C%20so%20with%20parallelism%3D6%20calling%20nested%20workflows%2C%20you%27re%20creating%20queuing%20delays.%20Additionally%2C%20%5Busers%20have%20reported%207%2B%20minute%20delays%20for%20simple%20code%20nodes%20when%20running%20parallel%20iterations%5D%28https%3A//github.com/langgenius/dify/issues/27821%29%20%E2%80%94%20this%20is%20a%20known%20regression%20in%20v1.9.x%2B.%0A%0A%2A%2ARecommended%20fixes%3A%2A%2A%0A%0A1.%20%2A%2AConfigure%20GraphEngine%20workers%2A%2A%20in%20your%20%60.env%60%3A%0A%20%20%20%60%60%60%0A%20%20%20GRAPH_ENGINE_MIN_WORKERS%3D3%0A%20%20%20GRAPH_ENGINE_MAX_WORKERS%3D10%0A%20%20%20%60%60%60%0A%20%20%20Without%20this%2C%20%5Bparallel%20iterations%20may%20execute%20sequentially%5D%28https%3A//github.com/langgenius/dify/discussions/26166%29.%0A%0A2.%20%2A%2AReduce%20parallelism%20to%204-5%2A%2A%20%E2%80%94%20staying%20under%20the%20default%20max%20workers%20helps%20avoid%20queuing%0A%0A3.%20%2A%2AIncrease%20connection%20pool%20settings%2A%2A%20to%20handle%20nested%20workflow%20calls%3A%0A%20%20%20%60%60%60%0A%20%20%20SQLALCHEMY_POOL_SIZE%3D20%0A%20%20%20SQLALCHEMY_MAX_OVERFLOW%3D10%0A%20%20%20%60%60%60%0A%20%20%20%5BParallel%20iterations%20can%20exhaust%20database%20connections%5D%28https%3A//github.com/langgenius/dify/issues/27657%29%2C%20especially%20with%20nested%20workflow-as-tool%20calls.%0A%0A4.%20%2A%2AIncrease%20Celery%20workers%2A%2A%20as%20mentioned%20earlier%20%E2%80%94%20each%20parallel%20branch%20adds%20to%20the%20queue%20load%0A%0AThe%20combination%20of%20parallelism%3D6%20%2B%20nested%20workflow%20calls%20%2B%20default%20single%20Celery%20worker%20is%20a%20recipe%20for%20the%20variable%20delays%20you%27re%20experiencing.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/langgenius/dify/issues/32171)
Author
Owner

@gongshaojie12 commented on GitHub (Feb 9, 2026):

Currently, the value of SQLALCHEMY_POOL_SIZE is set to 100. Should the value of SQLALCHEMY_MAX_OVERFLOW be increased accordingly?

@gongshaojie12 commented on GitHub (Feb 9, 2026): Currently, the value of `SQLALCHEMY_POOL_SIZE` is set to 100. Should the value of `SQLALCHEMY_MAX_OVERFLOW` be increased accordingly?
Author
Owner

@dosubot[bot] commented on GitHub (Feb 9, 2026):

Yes, with SQLALCHEMY_POOL_SIZE=100, you should increase SQLALCHEMY_MAX_OVERFLOW.

Dify's defaults are POOL_SIZE=30 and MAX_OVERFLOW=10 (3:1 ratio). For your setup, consider:

Important: Total max connections = POOL_SIZE + MAX_OVERFLOW. With 100+100, a single instance could use up to 200 connections. Make sure POSTGRES_MAX_CONNECTIONS is set high enough — if it's still at the default of 100, you'll hit "too many clients" errors. For your configuration, POSTGRES_MAX_CONNECTIONS=500-1000 would be safer, especially if you have multiple Dify instances or services sharing the database.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

@dosubot[bot] commented on GitHub (Feb 9, 2026): <!-- Answer --> Yes, with `SQLALCHEMY_POOL_SIZE=100`, you should increase `SQLALCHEMY_MAX_OVERFLOW`. [Dify's defaults are POOL_SIZE=30 and MAX_OVERFLOW=10](https://github.com/langgenius/dify/blob/1a050c9f8601c69d2bb626338fe8b985c5a46cf1/api/configs/middleware/__init__.py) (3:1 ratio). For your setup, consider: - **Conservative**: `SQLALCHEMY_MAX_OVERFLOW=30-50` (keeps the ~3:1 ratio) - **Aggressive**: `SQLALCHEMY_MAX_OVERFLOW=100` ([high-concurrency deployments use 1:1 ratios](https://github.com/langgenius/dify/issues/30915)) **Important**: Total max connections = POOL_SIZE + MAX_OVERFLOW. With 100+100, a single instance could use up to 200 connections. Make sure `POSTGRES_MAX_CONNECTIONS` is set high enough — if it's still at the default of 100, you'll hit "too many clients" errors. For your configuration, `POSTGRES_MAX_CONNECTIONS=500-1000` would be safer, especially if you have multiple Dify instances or services sharing the database. <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/6dd0f4b0-c6cd-4885-8b80-9ba8627037ed?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/6dd0f4b0-c6cd-4885-8b80-9ba8627037ed?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/6dd0f4b0-c6cd-4885-8b80-9ba8627037ed?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/6dd0f4b0-c6cd-4885-8b80-9ba8627037ed?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/6dd0f4b0-c6cd-4885-8b80-9ba8627037ed?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/6dd0f4b0-c6cd-4885-8b80-9ba8627037ed?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/6dd0f4b0-c6cd-4885-8b80-9ba8627037ed?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/6088a4f4-073a-43f3-b3d4-4f06fb0c05a0/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=Yes%2C%20with%20%60SQLALCHEMY_POOL_SIZE%3D100%60%2C%20you%20should%20increase%20%60SQLALCHEMY_MAX_OVERFLOW%60.%0A%0A%5BDify%27s%20defaults%20are%20POOL_SIZE%3D30%20and%20MAX_OVERFLOW%3D10%5D%28https%3A//github.com/langgenius/dify/blob/1a050c9f8601c69d2bb626338fe8b985c5a46cf1/api/configs/middleware/__init__.py%29%20%283%3A1%20ratio%29.%20For%20your%20setup%2C%20consider%3A%0A%0A-%20%2A%2AConservative%2A%2A%3A%20%60SQLALCHEMY_MAX_OVERFLOW%3D30-50%60%20%28keeps%20the%20~3%3A1%20ratio%29%0A-%20%2A%2AAggressive%2A%2A%3A%20%60SQLALCHEMY_MAX_OVERFLOW%3D100%60%20%28%5Bhigh-concurrency%20deployments%20use%201%3A1%20ratios%5D%28https%3A//github.com/langgenius/dify/issues/30915%29%29%0A%0A%2A%2AImportant%2A%2A%3A%20Total%20max%20connections%20%3D%20POOL_SIZE%20%2B%20MAX_OVERFLOW.%20With%20100%2B100%2C%20a%20single%20instance%20could%20use%20up%20to%20200%20connections.%20Make%20sure%20%60POSTGRES_MAX_CONNECTIONS%60%20is%20set%20high%20enough%20%E2%80%94%20if%20it%27s%20still%20at%20the%20default%20of%20100%2C%20you%27ll%20hit%20%22too%20many%20clients%22%20errors.%20For%20your%20configuration%2C%20%60POSTGRES_MAX_CONNECTIONS%3D500-1000%60%20would%20be%20safer%2C%20especially%20if%20you%20have%20multiple%20Dify%20instances%20or%20services%20sharing%20the%20database.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/langgenius/dify/issues/32171)
Author
Owner

@gongshaojie12 commented on GitHub (Feb 9, 2026):

CPU cores: 8, memory: 64 GB. Are these settings appropriate — SQLALCHEMY_POOL_SIZE=100, SQLALCHEMY_MAX_OVERFLOW=50, and POSTGRES_MAX_CONNECTIONS=500?

@gongshaojie12 commented on GitHub (Feb 9, 2026): CPU cores: 8, memory: 64 GB. Are these settings appropriate — `SQLALCHEMY_POOL_SIZE=100`, `SQLALCHEMY_MAX_OVERFLOW=50`, and `POSTGRES_MAX_CONNECTIONS=500`?
Author
Owner

@ArthurME2095 commented on GitHub (Feb 9, 2026):

Suggention: Performance-related configurations should be exposed in the GUI settings:

It would be highly beneficial if Dify could expose performance-related configurations directly in the GUI settings panel.

At the moment, tuning these parameters is time-consuming and unintuitive. More importantly, even after repeated adjustments, it does not effectively resolve the issue where the sandbox process freezes, leading to extremely slow code execution.

Making these performance options configurable via the GUI would significantly improve usability, reduce trial-and-error during deployment, and help users better diagnose and mitigate sandbox-related performance bottlenecks.

@ArthurME2095 commented on GitHub (Feb 9, 2026): Suggention: Performance-related configurations should be exposed in the GUI settings: It would be highly beneficial if Dify could expose performance-related configurations directly in the GUI settings panel. At the moment, tuning these parameters is time-consuming and unintuitive. More importantly, even after repeated adjustments, it does not effectively resolve the issue where the sandbox process freezes, leading to extremely slow code execution. Making these performance options configurable via the GUI would significantly improve usability, reduce trial-and-error during deployment, and help users better diagnose and mitigate sandbox-related performance bottlenecks.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify#22167