Documentsragflow
Connection and Resource Management
Connection and Resource Management
Type
Topic
Status
Published
Created
Jul 7, 2026
Updated
Jul 7, 2026
Created by
Dosu Bot
Updated by
Dosu Bot

Connection and Resource Management#

RAGFlow's multi-worker, long-running architecture creates three distinct resource exhaustion risks: file descriptor leaks from unclosed handles, HTTP connection starvation from misconfigured pools, and connection storms from concurrent worker initialization. Each failure mode has a distinct fix location and pattern.


HTTP Client: Per-Request Scoping#

common/http_client.py is the central HTTP wrapper for outbound requests. Both async_request and sync_request open an httpx.AsyncClient / httpx.Client inside a with block, so the transport (and all its connections) is created and destroyed within a single request's scope . This avoids connection accumulation at the cost of no long-lived pool — acceptable for one-off LLM and OAuth calls where call rates are moderate.

Key env-tunable defaults :

VariableDefaultPurpose
HTTP_CLIENT_TIMEOUT15sRequest timeout
HTTP_CLIENT_MAX_RETRIES2Retry attempts
HTTP_CLIENT_BACKOFF_FACTOR0.5Exponential backoff base
HTTP_CLIENT_PROXYOptional proxy for all requests

Retries use exponential backoff: backoff_factor × 2^attempt .


Document Store Connection Pools#

OpenSearch#

The OSConnection singleton initializes a shared OpenSearch client. Prior to PR #15682, no pool_maxsize was set, causing urllib3 to default to maxsize=1 — forcing all concurrent operations to serialize on a single TCP connection and re-perform TLS handshakes. The fix passes pool_maxsize=10, enabling real parallel connections on the shared client.

Infinity#

common/doc_store/infinity_conn_pool.py controls the Infinity ConnectionPool via the INFINITY_POOL_MAX_SIZE environment variable (default: 4) . The default was reduced from 32 in PR #12006 after production deployments with 16 workers caused a connection storm: 16 workers × 32 connections = 512 simultaneous connections attempted at startup, exceeding Infinity's 128-connection limit and hanging most workers.


Multi-Worker Startup: Staggered Initialization#

To prevent the connection storm pattern from recurring, rag/svr/task_executor.py introduces a per-worker startup delay :

startup_delay = worker_num × 2.0s + random jitter [0, 0.5s]

The worker number is parsed from the CONSUMER_NAME env var (e.g., task_executor_abc123_5 → worker 5). Random jitter prevents thundering-herd scenarios where identically-delayed workers still collide. This was introduced alongside the Infinity pool-size reduction in PR #12006.


MCP Session Lifecycle#

MCPToolCallSession objects opened during agent canvas execution each spawn an event loop thread and hold an SSE/HTTP connection to an MCP server. Before PR #13295, these were never explicitly closed, accumulating indefinitely across canvas runs.

The fix adds Graph.close() to agent/canvas.py, which iterates all canvas components, identifies live MCPToolCallSession objects, and calls close_sync(timeout=3) on each (deduplication via seen = set()). This method is wired into canvas_service.py's streaming completion path inside a finally block , guaranteeing cleanup whether the canvas completes normally or raises an exception.


File Descriptor Leaks#

A systemic pattern of json.load(open(...)) — without closing the file — caused OSError: [Errno 24] Too many open files in long-running servers (PR #13997). The fix replaces bare open() calls with context managers in api/db/init_data.py and common/doc_store/infinity_conn_base.py.

Rule of thumb: always use with open(...) as f: for any file access in server code. The pattern json.load(open(...)) is invalid in long-running processes.


Key Source Files#

FilePurpose
common/http_client.pyShared HTTP wrapper with retry/backoff
rag/utils/opensearch_conn.pyOpenSearch singleton + pool config
common/doc_store/infinity_conn_pool.pyInfinity connection pool (INFINITY_POOL_MAX_SIZE)
rag/svr/task_executor.pyWorker startup staggering
agent/canvas.pyGraph.close() for MCP session cleanup
api/db/services/canvas_service.pyfinally: canvas.close() in completion stream
api/db/init_data.pyCorrected json.load file handle usage