Created
May 15, 2025 20:51
-
-
Save stevekinney/1c17f31556902d67ef11f451313c3524 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import chalk from 'chalk'; | |
import getPort, { portNumbers } from 'get-port'; | |
export type TemporalServerOptions = { | |
/** The port for the Temporal server to listen on.*/ | |
port: number; | |
/** The port for the Temporal UI to listen on. */ | |
uiPort: number; | |
/** The port for the Temporal HTTP API to listen on. */ | |
httpPort: number; | |
}; | |
export class Temporal { | |
readonly #port: number; | |
readonly #uiPort: number; | |
readonly #httpPort: number; | |
#server: import('bun').Subprocess | null = null; | |
static async create(): Promise<Temporal> { | |
const defaultPort = 7233; | |
const port = await getPort({ | |
port: portNumbers(defaultPort, defaultPort + 1000), | |
}); | |
const uiPort = await getPort({ port: port + 1000 }); | |
const httpPort = await getPort({ port: uiPort + 1000 }); | |
const temporal = new Temporal({ | |
port, | |
uiPort, | |
httpPort, | |
}); | |
return temporal; | |
} | |
private constructor(options: TemporalServerOptions) { | |
this.#port = options.port; | |
this.#uiPort = options.uiPort; | |
this.#httpPort = options.httpPort; | |
this.shutdown = this.shutdown.bind(this); | |
process.on('SIGINT', this.shutdown); | |
process.on('SIGTERM', this.shutdown); | |
process.on('exit', this.shutdown); | |
} | |
get port(): string { | |
return String(this.#port); | |
} | |
get uiPort(): string { | |
return String(this.#uiPort); | |
} | |
get httpPort(): string { | |
return String(this.#httpPort); | |
} | |
start() { | |
if (this.#server) return; | |
this.#server = Bun.spawn([ | |
this.cmd, | |
'server', | |
'start-dev', | |
'--log-level', | |
'error', | |
'--port', | |
this.port, | |
'--ui-port', | |
this.uiPort, | |
'--http-port', | |
this.httpPort, | |
]); | |
} | |
async shutdown(exitCode: number = 0) { | |
if (this.#server && this.#server.pid && !this.#server.killed) { | |
console.log(); | |
this.log(chalk.blue('Terminating Temporal process…')); | |
this.#server.kill(exitCode); | |
await this.#server.exited; | |
this.log(chalk.blue('Temporal process terminated.')); | |
} | |
process.off('SIGINT', this.shutdown); | |
process.off('SIGTERM', this.shutdown); | |
process.off('exit', this.shutdown); | |
} | |
get cmd(): string { | |
const cmd = Bun.which('temporal'); | |
if (!cmd) { | |
throw new Error( | |
'Temporal CLI not found. Please install it by running `brew install temporal` or refer to the Temporal documentation for installation instructions.', | |
); | |
} | |
return cmd; | |
} | |
log(...message: unknown[]) { | |
console.log(chalk.bgMagenta(' Temporal '), ...message); | |
} | |
} | |
if (import.meta.main) { | |
const temporal = await Temporal.create(); | |
temporal.start(); | |
temporal.log( | |
chalk.green('Started'), | |
chalk.cyan(`http://localhost:${temporal.port}`), | |
); | |
temporal.log( | |
chalk.yellow(`UI`), | |
chalk.cyan(`http://localhost:${temporal.uiPort}`), | |
); | |
temporal.log( | |
chalk.yellow(`HTTP API`), | |
chalk.cyan(`http://localhost:${temporal.uiPort}`), | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment