Class: Pikuri::VectorDb::Server::Chroma

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

Overview

Supervisor for a self-managed Chroma docker container. Owns the process; Backend::Chroma owns the HTTP client, and #client returns one pre-pointed at the running container. Hosts that manage Chroma elsewhere wire port:) directly and never touch this class.

This class carries Chroma's identity (image pin, name, persist + heartbeat paths) and hands it to a composed DockerContainer, which does the docker work and documents the shared rationale. What stays here: #default_data_dir, the Backend::Chroma factory, and the Finalizers registration (the supervisor is the host-facing ownership boundary, so it registers, not the helper).

Constant Summary collapse

IMAGE =

Returns pinned chroma docker image. Bumping this constant is how the codebase upgrades the chroma version: #ensure_running! recreates the container from scratch on the next boot, so it comes up on the new pin automatically (the bind-mounted corpus is untouched).

Returns:

  • (String)

    pinned chroma docker image. Bumping this constant is how the codebase upgrades the chroma version: #ensure_running! recreates the container from scratch on the next boot, so it comes up on the new pin automatically (the bind-mounted corpus is untouched).

'chromadb/chroma:1.5.9'
CONTAINER_NAME =

Returns container name; the "pikuri-internal-" prefix is the namespace pikuri squats — see DockerContainer.

Returns:

  • (String)

    container name; the "pikuri-internal-" prefix is the namespace pikuri squats — see DockerContainer.

'pikuri-internal-chroma'
LABEL =

Returns docker label set on every container this class creates (for docker ps --filter enumeration).

Returns:

  • (String)

    docker label set on every container this class creates (for docker ps --filter enumeration).

'pikuri.internal=true'
CONTAINER_PERSIST_DIR =

Returns path inside the container where chroma persists its data. Chroma 1.x (the pinned IMAGE line) stores its SQLite + segment files at /data — this is the -v target the host's #default_data_dir bind-mounts onto. (Chroma 0.x used /chroma/chroma; mounting that path against a 1.x image silently leaves the host dir empty while the data accumulates in the container's writable layer, where teardown would destroy it.).

Returns:

  • (String)

    path inside the container where chroma persists its data. Chroma 1.x (the pinned IMAGE line) stores its SQLite + segment files at /data — this is the -v target the host's #default_data_dir bind-mounts onto. (Chroma 0.x used /chroma/chroma; mounting that path against a 1.x image silently leaves the host dir empty while the data accumulates in the container's writable layer, where teardown would destroy it.)

'/data'
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: 8000, healthcheck_timeout: DEFAULT_HEALTHCHECK_TIMEOUT, connection: nil) ⇒ Server::Chroma

Parameters:

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

    host path to bind-mount as chroma's persist dir. nil resolves to #default_data_dir.

  • port (Integer) (defaults to: 8000)

    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.



81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
# File 'lib/pikuri/vector_db/server/chroma.rb', line 81

def initialize(data_dir: nil, port: 8000,
               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: 8000,
    volume: "#{@data_dir}:#{CONTAINER_PERSIST_DIR}",
    health_path: '/api/v2/heartbeat',
    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.



98
99
100
# File 'lib/pikuri/vector_db/server/chroma.rb', line 98

def data_dir
  @data_dir
end

#portInteger (readonly)

Returns host-side port.

Returns:

  • (Integer)

    host-side port.



101
102
103
# File 'lib/pikuri/vector_db/server/chroma.rb', line 101

def port
  @port
end

Class Method Details

.ensure_running(data_dir: nil, port: 8000, healthcheck_timeout: DEFAULT_HEALTHCHECK_TIMEOUT) ⇒ Server::Chroma

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 ($XDG_CACHE_HOME or ~/.cache, then pikuri/chroma). Created if missing.

  • port (Integer) (defaults to: 8000)

    host port bound to chroma's 8000. Bound to 127.0.0.1 only.

  • healthcheck_timeout (Integer) (defaults to: DEFAULT_HEALTHCHECK_TIMEOUT)

    seconds to poll /api/v2/heartbeat before giving up.

Returns:



65
66
67
68
69
70
71
# File 'lib/pikuri/vector_db/server/chroma.rb', line 65

def self.ensure_running(data_dir: nil, port: 8000,
                        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::Chroma

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

Parameters:

  • collection (String)

    Chroma collection name.

Returns:



116
117
118
# File 'lib/pikuri/vector_db/server/chroma.rb', line 116

def client(collection:)
  Backend::Chroma.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.



141
142
143
# File 'lib/pikuri/vector_db/server/chroma.rb', line 141

def close
  @container.close
end

#default_data_dirString

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

Returns:

  • (String)


150
151
152
# File 'lib/pikuri/vector_db/server/chroma.rb', line 150

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

#endpointString

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

Returns:

  • (String)

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



105
106
107
# File 'lib/pikuri/vector_db/server/chroma.rb', line 105

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.



129
130
131
132
133
134
# File 'lib/pikuri/vector_db/server/chroma.rb', line 129

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