Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,14 @@ services:
profiles: ["ollama"]
volumes:
- ollama-models:/root/.ollama
# The image ships the ollama CLI but no curl/wget, so probe the daemon through it directly instead of a
# raw HTTP request: `ollama list` only succeeds once the server is accepting API calls.
healthcheck:
test: ["CMD", "ollama", "list"]
interval: 10s
timeout: 5s
start_period: 15s
retries: 5

# ── Litestream (--profile litestream) ─────────────────────────────────────
# Continuous WAL backup of the SQLite DB to S3/B2/R2. Copy litestream.yml.example
Expand Down
28 changes: 28 additions & 0 deletions test/unit/selfhost-compose-ollama-health.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { readFileSync } from "node:fs";
import { parse } from "yaml";
import { describe, expect, it } from "vitest";

function readYaml(path: string): Record<string, unknown> {
const value = parse(readFileSync(path, "utf8"));
if (!value || typeof value !== "object" || Array.isArray(value)) {
throw new Error(`${path} must be a YAML object`);
}
return value as Record<string, unknown>;
}

// Pure structural checks only (no `docker` CLI invocation): the self-hosted runner container this actually
// runs on does not have Docker-in-Docker access, so a test that shells out to `docker compose config`
// would be unreliable/environment-dependent here (same constraint as docker-compose-override-example.test.ts).
describe("docker-compose.yml — ollama healthcheck (#2504)", () => {
it("gives ollama a healthcheck so docker compose ps and a future depends_on can gate on it", () => {
const compose = readYaml("docker-compose.yml");
const services = (compose.services as Record<string, Record<string, unknown>>) ?? {};
const ollama = services.ollama ?? {};
const healthcheck = ollama.healthcheck as { test?: unknown[]; retries?: number };

// The image ships the ollama CLI but no curl/wget/nc, so `ollama list` is the only in-image probe that
// only succeeds once the daemon is actually serving API calls.
expect(healthcheck.test).toEqual(["CMD", "ollama", "list"]);
expect(healthcheck.retries).toBeGreaterThan(0);
});
});
Loading