@brimdata/zealot
Version:
The Javascript Client for Zed Lakes
114 lines (97 loc) • 2.56 kB
text/typescript
import {ChildProcess, spawn} from "child_process"
import {mkdirpSync} from "fs-extra"
import {join} from "path"
import {getPath} from "../cmd/paths"
import fetch from "cross-fetch"
const zedCommand = getPath("zed")
type ConstructorOpts = {
root: string
logs: string
port?: number
bin?: string
}
export class Lake {
lake?: ChildProcess
root: string
port: number
logs: string
bin: string
constructor(opts: ConstructorOpts) {
this.root = opts.root
this.logs = opts.logs
this.port = opts.port || 9867
this.bin = opts.bin || zedCommand
}
addr(): string {
return `localhost:${this.port}`
}
start() {
// @ts-ignore
mkdirpSync(this.root, {recursive: true, mode: 0o755})
// @ts-ignore
mkdirpSync(this.logs, {recursive: true, mode: 0o755})
const args = [
"serve",
"-l",
this.addr(),
"-lake",
this.root,
"-log.level=info",
"-log.filemode=rotate",
"-log.path",
join(this.logs, "zlake.log"),
]
const opts = {
stdio: ["inherit", "inherit", "inherit"],
windowsHide: true,
}
// For unix systems, pass posix pipe read file descriptor into lake process.
// In the event of Zui getting shutdown via `SIGKILL`, this will let lake
// know that it has been orphaned and to shutdown.
if (process.platform !== "win32") {
// eslint-disable-next-line @typescript-eslint/no-var-requires
const {readfd} = require("node-pipe").pipeSync()
opts.stdio.push(readfd)
args.push(`-brimfd=${opts.stdio.length - 1}`)
}
// @ts-ignore
this.lake = spawn(this.bin, args, opts) as ChildProcess
this.lake.on("error", (err) => {
console.error("lake spawn error", err)
})
return waitFor(async () => this.isUp())
}
async stop(): Promise<boolean> {
if (this.lake) {
this.lake.kill("SIGTERM")
return waitFor(() => this.isDown())
} else {
return true
}
}
async isUp() {
try {
const response = await fetch(`http://${this.addr()}/status`)
const text = await response.text()
return text === "ok"
} catch (e) {
return false
}
}
async isDown() {
return !(await this.isUp())
}
}
async function waitFor(condition: () => Promise<boolean>) {
let giveUp = false
const id = setTimeout(() => {
giveUp = true
}, 5000)
while (!giveUp) {
if (await condition()) break
await sleep(50)
}
clearTimeout(id)
return !giveUp
}
const sleep = (ms: number) => new Promise((r) => setTimeout(r, ms))