Skip to content

QdrantVectorStore accumulates one asyncio.Lock per logical collection for the client's lifetime #1566

Description

@edwinyyyu

What happened

QdrantVectorStore._name_locks is a WeakKeyDictionary keyed by client, with a comment noting that locks are collected when the client is:

# Keyed by client so locks are garbage-collected when the client is.
_name_locks: ClassVar[
    WeakKeyDictionary[AsyncQdrantClient, defaultdict[tuple[str, str], asyncio.Lock]]
] = WeakKeyDictionary()

The outer mapping is indeed weak, but the inner defaultdict is not bounded. It gains an asyncio.Lock for every (namespace, name) the process ever touches, and never drops one. Since a logical collection is a session, a long-running server accumulates one lock object per session for the lifetime of the client — which in practice is the lifetime of the process.

Each lock is small, so this is a slow leak rather than an urgent one, but it is unbounded in the number of sessions served and is invisible because the comment reads as though the lifetime question is already handled.

Expected

Per-collection lock state should not grow without bound over a process's lifetime.

Suggested direction

The locks only serialise lifecycle operations within one process. Once collection metadata is arbitrated by a cross-process registry (#1526, #1527), their role is narrower still. Options, roughly in order of preference: drop them where the registry now provides the arbitration, evict the entry after a successful lifecycle operation, or keep them in a bounded cache.

Activity

  1. edwinyyyu commented on Sep 1, 2026

    @edwinyyyu
    ContributorAuthor

    Folding into #1564. The lock table isn't a standalone leak so much as a leftover of in-process lifecycle serialisation, which only exists because the non-sharded path predates cross-process arbitration. Once the registry arbitrates lifecycle (#1524, #1525), these locks should be removed rather than bounded, so the fix belongs with that work rather than on its own. Full detail preserved in #1564.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

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