Celery worker ignores SQLALCHEMY_POOL_SIZE - uses default pool_size=5 despite env var configuration #21430

Closed
opened 2026-02-21 20:12:32 -05:00 by yindo · 2 comments
Owner

Originally created by @ataraxiaone on GitHub (Jan 4, 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.11.1

Cloud or Self Hosted

Self Hosted (Source)

Steps to reproduce

When running Dify 1.11.1 with the Celery worker using gevent pool (-P gevent), the SQLAlchemy connection pool ignores the configured SQLALCHEMY_POOL_SIZE environment variable and uses Flask-SQLAlchemy's default pool_size=5.

This causes Knowledge Base batch uploads to fail with connection pool exhaustion:

QueuePool limit of size 5 overflow 3 reached, connection timed out, timeout 30.00

Environment

  • Dify Version: 1.11.1
  • Deployment: AWS ECS Fargate (Docker)
  • Database: PostgreSQL RDS 16.8
  • Worker Command: celery -A app.celery worker -P gevent -c 1 --loglevel=INFO

Configuration

Environment variables set in task definition (verified via AWS CLI):

SQLALCHEMY_POOL_SIZE=10
SQLALCHEMY_MAX_OVERFLOW=5
SQLALCHEMY_POOL_RECYCLE=3600
PGVECTOR_MIN_CONNECTION=2
PGVECTOR_MAX_CONNECTION=10

Root Cause Analysis

The Celery worker with gevent appears to initialize Flask-SQLAlchemy's connection pool before the full Dify config (SQLALCHEMY_ENGINE_OPTIONS) is applied.

Evidence:

  • size 5 matches Flask-SQLAlchemy's default pool_size
  • Single file uploads work (less pool pressure)
  • Batch uploads fail (concurrent embedding tasks exhaust the small pool)
  • The PGVECTOR pool uses psycopg2.SimpleConnectionPool (different error format), so this is specifically the SQLAlchemy QueuePool issue

Workaround

Using the Dify Knowledge Base API to upload documents sequentially (one at a time) bypasses the issue by avoiding concurrent embedding tasks.

Suggested Fix

The fix would involve ensuring Flask-SQLAlchemy's engine is created after Dify's config is fully loaded, or explicitly disposing and recreating the engine pool after config is applied. This likely requires changes to how the Celery app is initialized in relation to Flask-SQLAlchemy.

Related Issues

  • #21437 - QueuePool limit reached
  • #8840 - pgvector min/max connections feature
  • #17366 - Connection pool exhaustion with PostgreSQL

✔️ Expected Behavior

Error should show QueuePool limit of size 10 overflow 5 (matching our config)

Actual Behavior

Error shows QueuePool limit of size 5 overflow 3 - matching Flask-SQLAlchemy defaults, not our configuration.

Originally created by @ataraxiaone on GitHub (Jan 4, 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.11.1 ### Cloud or Self Hosted Self Hosted (Source) ### Steps to reproduce When running Dify 1.11.1 with the Celery worker using gevent pool (`-P gevent`), the SQLAlchemy connection pool ignores the configured `SQLALCHEMY_POOL_SIZE` environment variable and uses Flask-SQLAlchemy's default `pool_size=5`. This causes Knowledge Base batch uploads to fail with connection pool exhaustion: QueuePool limit of size 5 overflow 3 reached, connection timed out, timeout 30.00 ## Environment - **Dify Version**: 1.11.1 - **Deployment**: AWS ECS Fargate (Docker) - **Database**: PostgreSQL RDS 16.8 - **Worker Command**: `celery -A app.celery worker -P gevent -c 1 --loglevel=INFO` ## Configuration Environment variables set in task definition (verified via AWS CLI): SQLALCHEMY_POOL_SIZE=10 SQLALCHEMY_MAX_OVERFLOW=5 SQLALCHEMY_POOL_RECYCLE=3600 PGVECTOR_MIN_CONNECTION=2 PGVECTOR_MAX_CONNECTION=10 ## Root Cause Analysis The Celery worker with gevent appears to initialize Flask-SQLAlchemy's connection pool **before** the full Dify config (`SQLALCHEMY_ENGINE_OPTIONS`) is applied. Evidence: - `size 5` matches Flask-SQLAlchemy's default `pool_size` - Single file uploads work (less pool pressure) - Batch uploads fail (concurrent embedding tasks exhaust the small pool) - The PGVECTOR pool uses psycopg2.SimpleConnectionPool (different error format), so this is specifically the SQLAlchemy QueuePool issue ## Workaround Using the Dify Knowledge Base API to upload documents sequentially (one at a time) bypasses the issue by avoiding concurrent embedding tasks. ## Suggested Fix The fix would involve ensuring Flask-SQLAlchemy's engine is created **after** Dify's config is fully loaded, or explicitly disposing and recreating the engine pool after config is applied. This likely requires changes to how the Celery app is initialized in relation to Flask-SQLAlchemy. ## Related Issues - #21437 - QueuePool limit reached - #8840 - pgvector min/max connections feature - #17366 - Connection pool exhaustion with PostgreSQL ### ✔️ Expected Behavior Error should show `QueuePool limit of size 10 overflow 5` (matching our config) ### ❌ Actual Behavior Error shows `QueuePool limit of size 5 overflow 3` - matching Flask-SQLAlchemy defaults, not our configuration.
yindo added the 🐞 bug label 2026-02-21 20:12:32 -05:00
yindo closed this issue 2026-02-21 20:12:32 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Jan 4, 2026):

Hi @ataraxiaone! I'm Dosu and I’m helping the dify team.

This is a confirmed bug: when running Celery workers with gevent, the SQLAlchemy connection pool uses the default pool size of 5 instead of your configured value. This happens because the Flask-SQLAlchemy engine is initialized before the full config (including SQLALCHEMY_POOL_SIZE) is applied, so the environment variable is ignored. The initialization order in the codebase means there’s no later opportunity for the worker to pick up the correct pool size—this is why you see pool exhaustion during batch uploads, and why single uploads work fine. Recent changes have made pool timeout and max overflow configurable, but they do not address this root cause or provide a fix for the pool size issue with Celery workers and gevent. There’s no merged patch or workaround in the codebase yet, other than uploading sequentially to avoid exhausting the pool.
See code details

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 (Jan 4, 2026): <!-- Greeting --> Hi @ataraxiaone! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the dify team. <!-- Answer --> This is a confirmed bug: when running Celery workers with gevent, the SQLAlchemy connection pool uses the default pool size of 5 instead of your configured value. This happens because the Flask-SQLAlchemy engine is initialized before the full config (including SQLALCHEMY_POOL_SIZE) is applied, so the environment variable is ignored. The initialization order in the codebase means there’s no later opportunity for the worker to pick up the correct pool size—this is why you see pool exhaustion during batch uploads, and why single uploads work fine. Recent changes have made pool timeout and max overflow configurable, but they do not address this root cause or provide a fix for the pool size issue with Celery workers and gevent. There’s no merged patch or workaround in the codebase yet, other than uploading sequentially to avoid exhausting the pool. [See code details](https://github.com/langgenius/dify/blob/c58a093fd1545347e3f137497dc48fd1037f855b/api/app_factory.py#L18-L144) <!-- 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/388abae3-dc26-4e4f-841e-f28c8229df98?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/388abae3-dc26-4e4f-841e-f28c8229df98?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/388abae3-dc26-4e4f-841e-f28c8229df98?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/388abae3-dc26-4e4f-841e-f28c8229df98?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/388abae3-dc26-4e4f-841e-f28c8229df98?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/388abae3-dc26-4e4f-841e-f28c8229df98?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/388abae3-dc26-4e4f-841e-f28c8229df98?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=This%20is%20a%20confirmed%20bug%3A%20when%20running%20Celery%20workers%20with%20gevent%2C%20the%20SQLAlchemy%20connection%20pool%20uses%20the%20default%20pool%20size%20of%205%20instead%20of%20your%20configured%20value.%20This%20happens%20because%20the%20Flask-SQLAlchemy%20engine%20is%20initialized%20before%20the%20full%20config%20%28including%20SQLALCHEMY_POOL_SIZE%29%20is%20applied%2C%20so%20the%20environment%20variable%20is%20ignored.%20The%20initialization%20order%20in%20the%20codebase%20means%20there%E2%80%99s%20no%20later%20opportunity%20for%20the%20worker%20to%20pick%20up%20the%20correct%20pool%20size%E2%80%94this%20is%20why%20you%20see%20pool%20exhaustion%20during%20batch%20uploads%2C%20and%20why%20single%20uploads%20work%20fine.%20Recent%20changes%20have%20made%20pool%20timeout%20and%20max%20overflow%20configurable%2C%20but%20they%20do%20not%20address%20this%20root%20cause%20or%20provide%20a%20fix%20for%20the%20pool%20size%20issue%20with%20Celery%20workers%20and%20gevent.%20There%E2%80%99s%20no%20merged%20patch%20or%20workaround%20in%20the%20codebase%20yet%2C%20other%20than%20uploading%20sequentially%20to%20avoid%20exhausting%20the%20pool.%20%20%0A%5BSee%20code%20details%5D%28https%3A//github.com/langgenius/dify/blob/c58a093fd1545347e3f137497dc48fd1037f855b/api/app_factory.py%23L18-L144%29)&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/30536)
Author
Owner

@fatelei commented on GitHub (Jan 4, 2026):

Hi @ataraxiaone! I'm Dosu and I’m helping the dify team.

This is a confirmed bug: when running Celery workers with gevent, the SQLAlchemy connection pool uses the default pool size of 5 instead of your configured value. This happens because the Flask-SQLAlchemy engine is initialized before the full config (including SQLALCHEMY_POOL_SIZE) is applied, so the environment variable is ignored. The initialization order in the codebase means there’s no later opportunity for the worker to pick up the correct pool size—this is why you see pool exhaustion during batch uploads, and why single uploads work fine. Recent changes have made pool timeout and max overflow configurable, but they do not address this root cause or provide a fix for the pool size issue with Celery workers and gevent. There’s no merged patch or workaround in the codebase yet, other than uploading sequentially to avoid exhausting the pool. See code details

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

you are wrong,config apply always before db init

@fatelei commented on GitHub (Jan 4, 2026): > Hi [@ataraxiaone](https://github.com/ataraxiaone)! I'm [Dosu](https://go.dosu.dev/dosubot) and I’m helping the dify team. > > This is a confirmed bug: when running Celery workers with gevent, the SQLAlchemy connection pool uses the default pool size of 5 instead of your configured value. This happens because the Flask-SQLAlchemy engine is initialized before the full config (including SQLALCHEMY_POOL_SIZE) is applied, so the environment variable is ignored. The initialization order in the codebase means there’s no later opportunity for the worker to pick up the correct pool size—this is why you see pool exhaustion during batch uploads, and why single uploads work fine. Recent changes have made pool timeout and max overflow configurable, but they do not address this root cause or provide a fix for the pool size issue with Celery workers and gevent. There’s no merged patch or workaround in the codebase yet, other than uploading sequentially to avoid exhausting the pool. [See code details](https://github.com/langgenius/dify/blob/c58a093fd1545347e3f137497dc48fd1037f855b/api/app_factory.py#L18-L144) > > _To reply, just mention [@dosu](https://go.dosu.dev/dosubot)._ > > How did I do? [Good](https://app.dosu.dev/response-feedback/388abae3-dc26-4e4f-841e-f28c8229df98?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/388abae3-dc26-4e4f-841e-f28c8229df98?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/388abae3-dc26-4e4f-841e-f28c8229df98?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/388abae3-dc26-4e4f-841e-f28c8229df98?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/388abae3-dc26-4e4f-841e-f28c8229df98?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/388abae3-dc26-4e4f-841e-f28c8229df98?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/388abae3-dc26-4e4f-841e-f28c8229df98?feedback_type=other) > > [![Chat with Dosu](https://camo.githubusercontent.com/7c571478962a6b8a5d47cac74b6824c75e4f6731bba52377e6007f9150462923/68747470733a2f2f646f73752e6465762f646f73752d636861742d62616467652e737667)](https://app.dosu.dev/6088a4f4-073a-43f3-b3d4-4f06fb0c05a0/ask?utm_source=github) [![Open in Cursor](https://camo.githubusercontent.com/bdf7dbded65ee585887f47e5fd6fa099ea0933088b4b03d02e83b4def50154d4/68747470733a2f2f646f73752e6465762f646f73752d696e2d637572736f722e737667)](https://cursor.com/link/prompt?text=This%20is%20a%20confirmed%20bug%3A%20when%20running%20Celery%20workers%20with%20gevent%2C%20the%20SQLAlchemy%20connection%20pool%20uses%20the%20default%20pool%20size%20of%205%20instead%20of%20your%20configured%20value.%20This%20happens%20because%20the%20Flask-SQLAlchemy%20engine%20is%20initialized%20before%20the%20full%20config%20%28including%20SQLALCHEMY_POOL_SIZE%29%20is%20applied%2C%20so%20the%20environment%20variable%20is%20ignored.%20The%20initialization%20order%20in%20the%20codebase%20means%20there%E2%80%99s%20no%20later%20opportunity%20for%20the%20worker%20to%20pick%20up%20the%20correct%20pool%20size%E2%80%94this%20is%20why%20you%20see%20pool%20exhaustion%20during%20batch%20uploads%2C%20and%20why%20single%20uploads%20work%20fine.%20Recent%20changes%20have%20made%20pool%20timeout%20and%20max%20overflow%20configurable%2C%20but%20they%20do%20not%20address%20this%20root%20cause%20or%20provide%20a%20fix%20for%20the%20pool%20size%20issue%20with%20Celery%20workers%20and%20gevent.%20There%E2%80%99s%20no%20merged%20patch%20or%20workaround%20in%20the%20codebase%20yet%2C%20other%20than%20uploading%20sequentially%20to%20avoid%20exhausting%20the%20pool.%20%20%0A%5BSee%20code%20details%5D%28https%3A//github.com/langgenius/dify/blob/c58a093fd1545347e3f137497dc48fd1037f855b/api/app_factory.py%23L18-L144%29) [![Join Discord](https://camo.githubusercontent.com/7d2066700925db1e370d956834f9ea0e5bc92cecbe84963fbd2a363e45091b4e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6a6f696e2d3538363546323f6c6f676f3d646973636f7264266c6f676f436f6c6f723d7768697465266c6162656c3d)](https://go.dosu.dev/discord-bot) [![Share on X](https://camo.githubusercontent.com/a8bd7f3fcf3f5e3bd124eee9ae50ae2ac17b40971726665ac2121d48f9aee155/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f582d73686172652d626c61636b)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/langgenius/dify/issues/30536) you are wrong,config apply always before db init
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: langgenius/dify#21430