Skip to content

Feature: Connection Pooling #170

@dyleeeeeeee

Description

@dyleeeeeeee

Is your feature request related to a problem?

Currently, the SurrealDB async client does not support connection pooling. When multiple coroutines execute queries concurrently, they share a single WebSocket connection. This leads to concurrency issues because the WebSocket protocol does not allow multiple simultaneous recv() operations. As a result, applications using SurrealDB in an asynchronous environment may encounter the following error:

websockets.exceptions.ConcurrencyError: cannot call recv while another coroutine is already running recv or recv_streaming

To avoid this, developers must serialize queries using asyncio.Lock or an external task queue. However, this approach creates a bottleneck, significantly limiting throughput in high-concurrency scenarios.

Describe the solution

To improve scalability and concurrency, SurrealDB should implement connection pooling in its async WebSocket client. This would allow multiple WebSocket connections to be maintained, distributing queries among them instead of relying on a single connection.

Key features of the proposed solution:
1. Pool Management: Maintain a configurable number of WebSocket connections (e.g., pool_size=5 by default).
2. Automatic Connection Assignment: When a query is made, assign it to an available connection.
3. Efficient Reuse: After a query is executed, the connection should return to the pool for reuse.
4. Graceful Scaling: If all connections are busy, either queue the query or allow an optional expansion of the pool.
5. Automatic Cleanup: Close unused or idle connections after a configurable timeout.

Implementation Example (Python)

A simple connection pool could be implemented as follows:

import asyncio
from surrealdb import Surreal

class SurrealDBPool:
    def __init__(self, pool_size=5):
        self.pool = asyncio.Queue()
        self.pool_size = pool_size

    async def initialize_pool(self):
        for _ in range(self.pool_size):
            db = Surreal()
            await db.connect("ws://localhost:8000")
            await self.pool.put(db)  # Store connection in queue

    async def query(self, query_string):
        db = await self.pool.get()  # Get an available connection
        try:
            return await db.query(query_string)
        finally:
            await self.pool.put(db)  # Return connection to pool

✅ Scales efficiently for high-concurrency applications
✅ Eliminates WebSocket concurrency errors
✅ Reduces query latency by preventing bottlenecks

Why This Matters

Adding built-in connection pooling to the SurrealDB async client would:
• Provide out-of-the-box concurrency handling, reducing the need for workarounds.
• Improve performance and responsiveness for applications handling frequent queries.
• Ensure a better developer experience, making SurrealDB easier to integrate with async frameworks like Quart, FastAPI, and Django Async.

Alternative methods

I have tried to serialize queries using asyncio.Lock or an external task queue. However, this approach creates a bottleneck, significantly limiting throughput in high-concurrency scenarios

SurrealDB version

surreal x.x.x

surrealdb.py version

1.x.x

Contact Details

[email protected]

Is there an existing issue for this?

  • I have searched the existing issues

Code of Conduct

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions