test(cli): isolate service registration lease
This commit is contained in:
parent
e5f380cb97
commit
0548ad718f
3 changed files with 87 additions and 69 deletions
|
|
@ -8,6 +8,7 @@ import fs from "node:fs/promises"
|
|||
import os from "node:os"
|
||||
import path from "node:path"
|
||||
import { ServiceConfig } from "../src/services/service-config"
|
||||
import { ServiceRegistration } from "../src/services/service-registration"
|
||||
|
||||
test("managed service ports are stable per installation channel", () => {
|
||||
expect(ServiceConfig.defaultPort("latest")).toBe(0xc0de)
|
||||
|
|
@ -413,32 +414,37 @@ test("port contender recognizes an incumbent registered during the bind race", a
|
|||
}
|
||||
}, 45_000)
|
||||
|
||||
test("stale dead registration is replaced after binding the selected port", async () => {
|
||||
test("service registration replaces a stale owner with the bound address", async () => {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), "opencode-service-stale-"))
|
||||
const port = await availablePort()
|
||||
const registration = path.join(root, "state", "opencode", "service-local.json")
|
||||
await fs.mkdir(path.join(root, "config", "opencode"), { recursive: true })
|
||||
await fs.mkdir(path.dirname(registration), { recursive: true })
|
||||
await fs.writeFile(path.join(root, "config", "opencode", "service-local.json"), JSON.stringify({ port }))
|
||||
await fs.writeFile(
|
||||
registration,
|
||||
JSON.stringify({ id: "dead", version: "dead", url: `http://127.0.0.1:${port}`, pid: 2_147_483_647 }),
|
||||
JSON.stringify({ id: "dead", version: "dead", url: "http://127.0.0.1:4321", pid: 2_147_483_647 }),
|
||||
)
|
||||
const owner = Bun.spawn([process.execPath, path.join(import.meta.dir, "../src/index.ts"), "serve", "--service"], {
|
||||
env: serviceEnv(root),
|
||||
stderr: "pipe",
|
||||
stdout: "ignore",
|
||||
})
|
||||
try {
|
||||
const info = await waitForInfo(registration, (value) => value.id !== "dead", 60_000)
|
||||
expect(new URL(info.url).port).toBe(String(port))
|
||||
expect(info.pid).toBe(owner.pid)
|
||||
const cleanup = await Effect.runPromise(
|
||||
ServiceRegistration.register(
|
||||
{ _tag: "TcpAddress", hostname: "127.0.0.1", port: 4321 },
|
||||
"secret",
|
||||
"owner",
|
||||
registration,
|
||||
Effect.never,
|
||||
).pipe(Effect.scoped, Effect.provide(NodeFileSystem.layer)),
|
||||
)
|
||||
expect(await Bun.file(registration).json()).toEqual({
|
||||
id: "owner",
|
||||
version: OPENCODE_VERSION,
|
||||
url: "http://127.0.0.1:4321",
|
||||
pid: process.pid,
|
||||
password: "secret",
|
||||
})
|
||||
await Effect.runPromise(cleanup.pipe(Effect.provide(NodeFileSystem.layer)))
|
||||
expect(await Bun.file(registration).exists()).toBe(false)
|
||||
} finally {
|
||||
owner.kill("SIGTERM")
|
||||
await owner.exited
|
||||
await fs.rm(root, { recursive: true, force: true })
|
||||
}
|
||||
}, 75_000)
|
||||
})
|
||||
|
||||
test("a failed service stays registered and owns the selected port until stopped", async () => {
|
||||
const root = await fs.mkdtemp(path.join(os.tmpdir(), "opencode-service-failed-"))
|
||||
|
|
@ -479,9 +485,8 @@ test("a failed service stays registered and owns the selected port until stopped
|
|||
}
|
||||
}, 30_000)
|
||||
|
||||
async function waitForInfo(file: string, accept: (info: Info) => boolean = () => true, timeout = 20_000) {
|
||||
const deadline = Date.now() + timeout
|
||||
while (Date.now() < deadline) {
|
||||
async function waitForInfo(file: string, accept: (info: Info) => boolean = () => true) {
|
||||
for (let attempt = 0; attempt < 400; attempt++) {
|
||||
const value = await Bun.file(file)
|
||||
.json()
|
||||
.catch(() => undefined)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue