diff --git a/src/selfhost/qdrant-vectorize.ts b/src/selfhost/qdrant-vectorize.ts index 9621d01362..028f887350 100644 --- a/src/selfhost/qdrant-vectorize.ts +++ b/src/selfhost/qdrant-vectorize.ts @@ -48,6 +48,11 @@ function qdrantHeaders(): Record { return h; } +/** Build the unauthenticated Kubernetes-style readiness endpoint for a configured Qdrant base URL. */ +export function qdrantReadyzUrl(url: string): string { + return `${url.replace(/\/+$/, "")}/readyz`; +} + /** * Ensures the Qdrant collection exists. Safe to call on every startup — a 409 (already exists) * is silently ignored. Call this before createQdrantVectorize() when QDRANT_URL is set. diff --git a/src/server.ts b/src/server.ts index 189d62c085..8158843b7f 100644 --- a/src/server.ts +++ b/src/server.ts @@ -380,7 +380,7 @@ async function main(): Promise { let vectorizeOverride: Vectorize | undefined; if (process.env.QDRANT_URL) { const qdrantUrl = process.env.QDRANT_URL; - const { createQdrantVectorize, initQdrantCollection } = + const { createQdrantVectorize, initQdrantCollection, qdrantReadyzUrl } = await import("./selfhost/qdrant-vectorize"); // Retry until Qdrant accepts the collection PUT — the container may still be booting when we start. await retryUntilReady("qdrant", () => initQdrantCollection(qdrantUrl)); @@ -389,7 +389,7 @@ async function main(): Promise { name: "qdrant", check: () => withTimeout( - fetch(qdrantUrl, { signal: AbortSignal.timeout(1500) }) + fetch(qdrantReadyzUrl(qdrantUrl), { signal: AbortSignal.timeout(1500) }) .then((r) => r.ok) .catch(() => false), ), diff --git a/test/unit/selfhost-qdrant-vectorize.test.ts b/test/unit/selfhost-qdrant-vectorize.test.ts index bbfa0ec161..9b6a25467c 100644 --- a/test/unit/selfhost-qdrant-vectorize.test.ts +++ b/test/unit/selfhost-qdrant-vectorize.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it, vi, beforeEach, afterEach } from "vitest"; -import { createQdrantVectorize, initQdrantCollection } from "../../src/selfhost/qdrant-vectorize"; +import { createQdrantVectorize, initQdrantCollection, qdrantReadyzUrl } from "../../src/selfhost/qdrant-vectorize"; import { resetMetrics, renderMetrics } from "../../src/selfhost/metrics"; const BASE = "http://qdrant:6333"; @@ -9,6 +9,13 @@ function mockFetch(status: number, body: unknown = {}) { return vi.fn(async () => new Response(JSON.stringify(body), { status })); } +describe("qdrantReadyzUrl (#1482 regression)", () => { + it("points readiness probes at Qdrant's unauthenticated /readyz endpoint", () => { + expect(qdrantReadyzUrl(BASE)).toBe(`${BASE}/readyz`); + expect(qdrantReadyzUrl(`${BASE}/`)).toBe(`${BASE}/readyz`); + }); +}); + describe("initQdrantCollection (#1217)", () => { afterEach(() => { vi.restoreAllMocks(); resetMetrics(); });