Class: Pikuri::VectorDb::Server::Qdrant

Inherits:
Object
  • Object
show all
Defined in:
lib/pikuri/vector_db/server/qdrant.rb

Overview

Supervisor for a self-managed Qdrant docker container — pairs with Backend::Qdrant exactly as Chroma pairs with Backend::Chroma (this class owns the process; #client returns a backend pre-pointed at it). Carries only the engine's identity and composes a DockerContainer for the docker work + shared rationale.

Port 6333 caveat: +pikuri-memory+'s Mem0Server compose stack also publishes its own internal Qdrant on host 6333 (separate instance by design — see DESIGN.md), so running both at the defaults collides — pass a different port: here when the mem0 stack is up.

Constant Summary collapse

IMAGE =

Returns pinned qdrant docker image; bump it to upgrade (#ensure_running! recreates the container on next boot, data dir untouched). Kept in lockstep with +Pikuri::Memory::Mem0Server::DEFAULT_QDRANT_IMAGE+ so a host running both stacks holds one image — a convention (the gems don't depend on each other), bump both together.

Returns:

  • (String)

    pinned qdrant docker image; bump it to upgrade (#ensure_running! recreates the container on next boot, data dir untouched). Kept in lockstep with +Pikuri::Memory::Mem0Server::DEFAULT_QDRANT_IMAGE+ so a host running both stacks holds one image — a convention (the gems don't depend on each other), bump both together.

'qdrant/qdrant:v1.12.4'
CONTAINER_NAME =

Returns container name; "pikuri-internal-" namespace squat (see DockerContainer).

Returns:

  • (String)

    container name; "pikuri-internal-" namespace squat (see DockerContainer).

'pikuri-internal-qdrant'
LABEL =

Returns docker label (same as Chroma::LABEL).

Returns:

'pikuri.internal=true'
CONTAINER_PERSIST_DIR =

Returns the -v target #default_data_dir bind-mounts onto — qdrant's documented storage root (also what pikuri-memory mounts).

Returns:

  • (String)

    the -v target #default_data_dir bind-mounts onto — qdrant's documented storage root (also what pikuri-memory mounts).

'/qdrant/storage'
DEFAULT_PORT =

Returns default host port, qdrant's native REST port. See the class header for the collision caveat with the mem0 stack's inspection port.

Returns:

  • (Integer)

    default host port, qdrant's native REST port. See the class header for the collision caveat with the mem0 stack's inspection port.

6333
DEFAULT_HEALTHCHECK_TIMEOUT =

Returns default seconds to wait for the container's HTTP heartbeat to start returning 200 after docker run.

Returns:

  • (Integer)

    default seconds to wait for the container's HTTP heartbeat to start returning 200 after docker run.

30

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(data_dir: nil, port: DEFAULT_PORT, healthcheck_timeout: DEFAULT_HEALTHCHECK_TIMEOUT, connection: nil) ⇒ Server::Qdrant

Parameters:

  • data_dir (String, Pathname, nil) (defaults to: nil)

    host path to bind-mount as qdrant's storage dir. nil resolves to #default_data_dir.

  • port (Integer) (defaults to: DEFAULT_PORT)

    host port to publish.

  • healthcheck_timeout (Integer) (defaults to: DEFAULT_HEALTHCHECK_TIMEOUT)
  • connection (Faraday::Connection, nil) (defaults to: nil)

    DI hook for tests. Production callers leave it nil.



76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
# File 'lib/pikuri/vector_db/server/qdrant.rb', line 76

def initialize(data_dir: nil, port: DEFAULT_PORT,
               healthcheck_timeout: DEFAULT_HEALTHCHECK_TIMEOUT,
               connection: nil)
  @data_dir = Pathname.new(data_dir || default_data_dir).expand_path
  @port = port
  @container = DockerContainer.new(
    name: CONTAINER_NAME, image: IMAGE, label: LABEL,
    host_port: port, container_port: 6333,
    volume: "#{@data_dir}:#{CONTAINER_PERSIST_DIR}",
    health_path: '/healthz',
    healthcheck_timeout: healthcheck_timeout,
    connection: connection
  )
  @finalizer_handle = nil
end

Instance Attribute Details

#data_dirPathname (readonly)

Returns host-side data directory.

Returns:

  • (Pathname)

    host-side data directory.



93
94
95
# File 'lib/pikuri/vector_db/server/qdrant.rb', line 93

def data_dir
  @data_dir
end

#portInteger (readonly)

Returns host-side port.

Returns:

  • (Integer)

    host-side port.



96
97
98
# File 'lib/pikuri/vector_db/server/qdrant.rb', line 96

def port
  @port
end

Class Method Details

.ensure_running(data_dir: nil, port: DEFAULT_PORT, healthcheck_timeout: DEFAULT_HEALTHCHECK_TIMEOUT) ⇒ Server::Qdrant

Construct a server and immediately ensure it's running. Convenience factory — equivalent to new(...).tap(&:ensure_running!).

Parameters:

  • data_dir (String, Pathname, nil) (defaults to: nil)

    host path bind-mounted into the container's persist directory. nil resolves to #default_data_dir. Created if missing.

  • port (Integer) (defaults to: DEFAULT_PORT)

    host port bound to qdrant's 6333. Bound to 127.0.0.1 only.

  • healthcheck_timeout (Integer) (defaults to: DEFAULT_HEALTHCHECK_TIMEOUT)

    seconds to poll /healthz before giving up.

Returns:



60
61
62
63
64
65
66
# File 'lib/pikuri/vector_db/server/qdrant.rb', line 60

def self.ensure_running(data_dir: nil, port: DEFAULT_PORT,
                        healthcheck_timeout: DEFAULT_HEALTHCHECK_TIMEOUT)
  new(
    data_dir: data_dir, port: port,
    healthcheck_timeout: healthcheck_timeout
  ).tap(&:ensure_running!)
end

Instance Method Details

#client(collection:) ⇒ Backend::Qdrant

Build a Backend::Qdrant pointing at the supervised container. Constructor convenience — the supervisor carries the host/port, the caller carries the collection name.

Parameters:

  • collection (String)

    Qdrant collection name.

Returns:



111
112
113
# File 'lib/pikuri/vector_db/server/qdrant.rb', line 111

def client(collection:)
  Backend::Qdrant.new(host: 'localhost', port: @port, collection: collection)
end

#closevoid

This method returns an undefined value.

Remove the supervised container, leaving the bind-mounted #data_dir (the corpus survives). Best-effort and idempotent — see DockerContainer#close.



136
137
138
# File 'lib/pikuri/vector_db/server/qdrant.rb', line 136

def close
  @container.close
end

#default_data_dirString

Default host-side data directory (+$XDG_CACHE_HOME/pikuri/qdrant+, else ~/.cache/pikuri/qdrant). Public so tests and chapter examples reference the same path.

Returns:

  • (String)


145
146
147
# File 'lib/pikuri/vector_db/server/qdrant.rb', line 145

def default_data_dir
  Pikuri::Paths.cache.join('qdrant').to_s
end

#endpointString

Returns "http://localhost:<port>". Useful for wiring custom Backend::Qdrant constructions.

Returns:

  • (String)

    "http://localhost:<port>". Useful for wiring custom Backend::Qdrant constructions.



100
101
102
# File 'lib/pikuri/vector_db/server/qdrant.rb', line 100

def endpoint
  @container.endpoint
end

#ensure_running!void

This method returns an undefined value.

Idempotent: ensure a fresh container is running and healthy (see DockerContainer#ensure_running! for the reuse-or-recreate algorithm), then register #close with Finalizers — once — so the container is removed at process exit.

Raises:

  • (RuntimeError)

    on missing docker, any docker command failure, or healthcheck timeout.



124
125
126
127
128
129
# File 'lib/pikuri/vector_db/server/qdrant.rb', line 124

def ensure_running!
  FileUtils.mkdir_p(@data_dir)
  @container.ensure_running!
  @finalizer_handle ||= Pikuri::Finalizers.register(self)
  nil
end