프로세스 생성 (Bun.spawn())
문자열 배열로 명령을 제공합니다. Bun.spawn() 의 결과는 Bun.Subprocess 객체입니다.
const proc = Bun.spawn(["bun", "--version"]);
console.log(await proc.exited); // 0Bun.spawn 의 두 번째 인수는 서브프로세스를 구성하는 데 사용할 수 있는 매개변수 객체입니다.
const proc = Bun.spawn(["bun", "--version"], {
cwd: "./path/to/subdir", // 작업 디렉토리 지정
env: { ...process.env, FOO: "bar" }, // 환경 변수 지정
onExit(proc, exitCode, signalCode, error) {
// 종료 핸들러
},
});
proc.pid; // 서브프로세스의 프로세스 ID입력 스트림
기본적으로 서브프로세스의 입력 스트림은 정의되지 않으며 stdin 매개변수로 구성할 수 있습니다.
const proc = Bun.spawn(["cat"], {
stdin: await fetch("https://raw.githubusercontent.com/oven-sh/bun/main/examples/hashing.js"),
});
const text = await proc.stdout.text();
console.log(text); // "const input = "hello world".repeat(400); ..."| 값 | 설명 |
|---|---|
null | 기본값. 서브프로세스에 입력 제공 안 함 |
"pipe" | 빠른 증분 쓰기를 위한 FileSink 반환 |
"inherit" | 부모 프로세스의 stdin 상속 |
Bun.file() | 지정된 파일에서 읽기 |
TypedArray | DataView | 이진 버퍼 입력 사용 |
Response | 응답 body 를 입력으로 사용 |
Request | 요청 body 를 입력으로 사용 |
ReadableStream | 읽기 가능한 스트림 입력 사용 |
Blob | blob 입력 사용 |
number | 주어진 파일 디스크립터로 파일에서 읽기 |
"pipe" 옵션을 사용하면 부모 프로세스에서 서브프로세스의 입력 스트림에 증분적으로 쓸 수 있습니다.
const proc = Bun.spawn(["cat"], {
stdin: "pipe", // 쓰기를 위한 FileSink 반환
});
// 문자열 데이터 인큐
proc.stdin.write("hello");
// 이진 데이터 인큐
const enc = new TextEncoder();
proc.stdin.write(enc.encode(" world!"));
// 버퍼된 데이터 전송
proc.stdin.flush();
// 입력 스트림 닫기
proc.stdin.end();ReadableStream 을 stdin 에 전달하면 JavaScript ReadableStream 의 데이터를 서브프로세스 입력으로 직접 파이프할 수 있습니다.
const stream = new ReadableStream({
start(controller) {
controller.enqueue("Hello from ");
controller.enqueue("ReadableStream!");
controller.close();
},
});
const proc = Bun.spawn(["cat"], {
stdin: stream,
stdout: "pipe",
});
const output = await proc.stdout.text();
console.log(output); // "Hello from ReadableStream!"출력 스트림
stdout 및 stderr 속성을 통해 서브프로세스에서 결과를 읽을 수 있습니다. 기본적으로 이들은 ReadableStream 의 인스턴스입니다.
const proc = Bun.spawn(["bun", "--version"]);
const text = await proc.stdout.text();
console.log(text); // => "1.3.3\n"다음 값 중 하나를 stdout/stderr 에 전달하여 출력 스트림을 구성합니다.
| 값 | 설명 |
|---|---|
"pipe" | stdout 의 기본값. 출력을 반환된 Subprocess 객체의 ReadableStream 으로 파이프 |
"inherit" | stderr 의 기본값. 부모 프로세스에서 상속 |
"ignore" | 출력 폐기 |
Bun.file() | 지정된 파일에 쓰기 |
number | 주어진 파일 디스크립터로 파일에 쓰기 |
종료 처리
onExit 콜백을 사용하여 프로세스가 종료되거나 강제 종료될 때 리스닝합니다.
const proc = Bun.spawn(["bun", "--version"], {
onExit(proc, exitCode, signalCode, error) {
// 종료 핸들러
},
});편의상 exited 속성은 프로세스가 종료될 때 해결되는 Promise 입니다.
const proc = Bun.spawn(["bun", "--version"]);
await proc.exited; // 프로세스 종료 시 해결
proc.killed; // 불리언 — 프로세스가 강제 종료되었는가?
proc.exitCode; // null | number
proc.signalCode; // null | "SIGABRT" | "SIGALRM" | ...프로세스를 종료하려면:
const proc = Bun.spawn(["bun", "--version"]);
proc.kill();
proc.killed; // true
proc.kill(15); // 시그널 코드 지정
proc.kill("SIGTERM"); // 시그널 이름 지정부모 bun 프로세스는 모든 자식 프로세스가 종료될 때까지 종료되지 않습니다. proc.unref() 를 사용하여 자식 프로세스를 부모에서 분리합니다.
const proc = Bun.spawn(["bun", "--version"]);
proc.unref();리소스 사용량
프로세스가 종료된 후 프로세스의 리소스 사용량에 대한 정보를 얻을 수 있습니다.
const proc = Bun.spawn(["bun", "--version"]);
await proc.exited;
const usage = proc.resourceUsage();
console.log(`Max memory used: ${usage.maxRSS} bytes`);
console.log(`CPU time (user): ${usage.cpuTime.user} µs`);
console.log(`CPU time (system): ${usage.cpuTime.system} µs`);AbortSignal 사용
AbortSignal 을 사용하여 서브프로세스를 중단할 수 있습니다.
const controller = new AbortController();
const { signal } = controller;
const proc = Bun.spawn({
cmd: ["sleep", "100"],
signal,
});
// 나중에 프로세스 중단:
controller.abort();timeout 과 killSignal 사용
특정 시간 후에 자동으로 종료되도록 서브프로세스의 타임아웃을 설정할 수 있습니다.
// 5 초 후 프로세스 종료
const proc = Bun.spawn({
cmd: ["sleep", "10"],
timeout: 5000, // 밀리초 단위의 5 초
});
await proc.exited; // 5 초 후 해결기본적으로 타임아웃된 프로세스는 SIGTERM 시그널로 종료됩니다. killSignal 옵션으로 다른 시그널을 지정할 수 있습니다.
// 5 초 후 SIGKILL 로 프로세스 종료
const proc = Bun.spawn({
cmd: ["sleep", "10"],
timeout: 5000,
killSignal: "SIGKILL", // 문자열 이름 또는 시그널 번호 가능
});killSignal 옵션은 AbortSignal 이 중단될 때 전송되는 시그널도 제어합니다.
maxBuffer 사용
spawnSync 의 경우 프로세스가 종료되기 전에 출력의 최대 바이트 수를 제한할 수 있습니다.
// 100 바이트 이상의 출력을 생성한 후 'yes' 종료
const result = Bun.spawnSync({
cmd: ["yes"], // 또는 Windows 에서 ["bun", "exec", "yes"]
maxBuffer: 100,
});
// 프로세스 종료프로세스 간 통신 (IPC)
Bun 은 두 bun 프로세스 간 직접 프로세스 간 통신 채널을 지원합니다. 생성된 Bun 서브프로세스에서 메시지를 수신하려면 ipc 핸들러를 지정합니다.
const child = Bun.spawn(["bun", "child.ts"], {
ipc(message) {
/**
* 서브 프로세스에서 받은 메시지
**/
},
});부모 프로세스는 반환된 Subprocess 인스턴스의 .send() 메서드를 사용하여 서브프로세스에 메시지를 보낼 수 있습니다. 보내는 서브프로세스에 대한 참조는 ipc 핸들러의 두 번째 인수로도 사용할 수 있습니다.
const childProc = Bun.spawn(["bun", "child.ts"], {
ipc(message, childProc) {
/**
* 서브 프로세스에서 받은 메시지
**/
childProc.send("Respond to child");
},
});
childProc.send("I am your father"); // 부모도 자식에게 메시지 전송 가능한편 자식 프로세스는 process.send() 를 사용하여 부모에게 메시지를 보내고 process.on("message") 를 사용하여 메시지를 받을 수 있습니다. 이는 Node.js 의 child_process.fork() 에 사용되는 것과 동일한 API 입니다.
process.send("Hello from child as string");
process.send({ message: "Hello from child as object" });
process.on("message", message => {
// 부모의 메시지 출력
console.log(message);
});// 문자열 전송
process.send("Hello from child as string");
// 객체 전송
process.send({ message: "Hello from child as object" });serialization 옵션은 두 프로세스 간 기본 통신 형식을 제어합니다.
advanced: (기본값) 메시지는 JSCserializeAPI 를 사용하여 직렬화되며, everythingstructuredClonesupports 를 복제할 수 있습니다. 이는 객체 소유권 이전을 지원하지 않습니다.json: 메시지는JSON.stringify및JSON.parse를 사용하여 직렬화되며,advanced보다 많은 객체 타입을 지원하지 않습니다.
부모 프로세스에서 IPC 채널을 연결 해제하려면 다음을 호출합니다.
childProc.disconnect();Bun 과 Node.js 간 IPC
bun 프로세스와 Node.js 프로세스 간 IPC 를 사용하려면 Bun.spawn 에서 serialization: "json" 을 설정합니다. 이는 Node.js 와 Bun 이 서로 다른 JavaScript 엔진을 사용하며 서로 다른 객체 직렬화 형식을 사용하기 때문입니다.
if (typeof Bun !== "undefined") {
const prefix = `[bun ${process.versions.bun} 🐇]`;
const node = Bun.spawn({
cmd: ["node", __filename],
ipc({ message }) {
console.log(message);
node.send({ message: `${prefix} 👋 hey node` });
node.kill();
},
stdio: ["inherit", "inherit", "inherit"],
serialization: "json",
});
node.send({ message: `${prefix} 👋 hey node` });
} else {
const prefix = `[node ${process.version}]`;
process.on("message", ({ message }) => {
console.log(message);
process.send({ message: `${prefix} 👋 hey bun` });
});
}블로킹 API (Bun.spawnSync())
Bun 은 Bun.spawn 의 동기화된 버전인 Bun.spawnSync 를 제공합니다. 이는 Bun.spawn 과 동일한 입력과 매개변수를 지원하는 블로킹 API 입니다. SyncSubprocess 객체를 반환하며, 이는 몇 가지 측면에서 Subprocess 와 다릅니다.
- 프로세스가 0 종료 코드로 종료되었는지를 나타내는
success속성이 있습니다. stdout및stderr속성은ReadableStream대신Buffer의 인스턴스입니다.stdin속성이 없습니다. 서브프로세스의 입력 스트림에 증분적으로 쓰려면Bun.spawn을 사용하세요.
const proc = Bun.spawnSync(["echo", "hello"]);
console.log(proc.stdout.toString());
// => "hello\n"경험적 규칙으로, 비동기 Bun.spawn API 는 HTTP 서버와 앱에 더 적합하며, Bun.spawnSync 는 명령줄 도구 구축에 더 적합합니다.
벤치마크
NOTE
⚡️ 내부적으로 `Bun.spawn` 과 `Bun.spawnSync` 는 [`posix_spawn(3)`](https://man7.org/linux/man-pages/man3/posix_spawn.3.html) 을 사용합니다.Bun 의 spawnSync 는 Node.js child_process 모듈보다 60% 빠르게 프로세스를 생성합니다.
bun spawn.mjscpu: Apple M1 Max
runtime: bun 1.x (arm64-darwin)
benchmark time (avg) (min … max) p75 p99 p995
--------------------------------------------------------- -----------------------------
spawnSync echo hi 888.14 µs/iter (821.83 µs … 1.2 ms) 905.92 µs 1 ms 1.03 msnode spawn.node.mjscpu: Apple M1 Max
runtime: node v18.9.1 (arm64-darwin)
benchmark time (avg) (min … max) p75 p99 p995
--------------------------------------------------------- -----------------------------
spawnSync echo hi 1.47 ms/iter (1.14 ms … 2.64 ms) 1.57 ms 2.37 ms 2.52 ms참조
Spawn API 와 타입의 참조는 아래에 나와 있습니다. 실제 타입은 Bun.spawn 과 Bun.spawnSync 에 전달된 옵션으로 Subprocess 스트림을 강력하게 타입 지정하기 위한 복잡한 제네릭을 가지고 있습니다. 전체 세부 정보는 bun.d.ts 에서 정의된 이러한 타입을 찾으세요.
interface Bun {
spawn(command: string[], options?: SpawnOptions.OptionsObject): Subprocess;
spawnSync(command: string[], options?: SpawnOptions.OptionsObject): SyncSubprocess;
spawn(options: { cmd: string[] } & SpawnOptions.OptionsObject): Subprocess;
spawnSync(options: { cmd: string[] } & SpawnOptions.OptionsObject): SyncSubprocess;
}
namespace SpawnOptions {
interface OptionsObject {
cwd?: string;
env?: Record<string, string | undefined>;
stdio?: [Writable, Readable, Readable];
stdin?: Writable;
stdout?: Readable;
stderr?: Readable;
onExit?(
subprocess: Subprocess,
exitCode: number | null,
signalCode: number | null,
error?: ErrorLike,
): void | Promise<void>;
ipc?(message: any, subprocess: Subprocess): void;
serialization?: "json" | "advanced";
windowsHide?: boolean;
windowsVerbatimArguments?: boolean;
argv0?: string;
signal?: AbortSignal;
timeout?: number;
killSignal?: string | number;
maxBuffer?: number;
}
type Readable =
| "pipe"
| "inherit"
| "ignore"
| null // "ignore" 와 동일
| undefined // 기본값 사용
| BunFile
| ArrayBufferView
| number;
type Writable =
| "pipe"
| "inherit"
| "ignore"
| null // "ignore" 와 동일
| undefined // 기본값 사용
| BunFile
| ArrayBufferView
| number
| ReadableStream
| Blob
| Response
| Request;
}
interface Subprocess extends AsyncDisposable {
readonly stdin: FileSink | number | undefined;
readonly stdout: ReadableStream<Uint8Array> | number | undefined;
readonly stderr: ReadableStream<Uint8Array> | number | undefined;
readonly readable: ReadableStream<Uint8Array> | number | undefined;
readonly pid: number;
readonly exited: Promise<number>;
readonly exitCode: number | null;
readonly signalCode: NodeJS.Signals | null;
readonly killed: boolean;
kill(exitCode?: number | NodeJS.Signals): void;
ref(): void;
unref(): void;
send(message: any): void;
disconnect(): void;
resourceUsage(): ResourceUsage | undefined;
}
interface SyncSubprocess {
stdout: Buffer | undefined;
stderr: Buffer | undefined;
exitCode: number;
success: boolean;
resourceUsage: ResourceUsage;
signalCode?: string;
exitedDueToTimeout?: true;
pid: number;
}
interface ResourceUsage {
contextSwitches: {
voluntary: number;
involuntary: number;
};
cpuTime: {
user: number;
system: number;
total: number;
};
maxRSS: number;
messages: {
sent: number;
received: number;
};
ops: {
in: number;
out: number;
};
shmSize: number;
signalCount: number;
swapCount: number;
}
type Signal =
| "SIGABRT"
| "SIGALRM"
| "SIGBUS"
| "SIGCHLD"
| "SIGCONT"
| "SIGFPE"
| "SIGHUP"
| "SIGILL"
| "SIGINT"
| "SIGIO"
| "SIGIOT"
| "SIGKILL"
| "SIGPIPE"
| "SIGPOLL"
| "SIGPROF"
| "SIGPWR"
| "SIGQUIT"
| "SIGSEGV"
| "SIGSTKFLT"
| "SIGSTOP"
| "SIGSYS"
| "SIGTERM"
| "SIGTRAP"
| "SIGTSTP"
| "SIGTTIN"
| "SIGTTOU"
| "SIGUNUSED"
| "SIGURG"
| "SIGUSR1"
| "SIGUSR2"
| "SIGVTALRM"
| "SIGWINCH"
| "SIGXCPU"
| "SIGXFSZ"
| "SIGBREAK"
| "SIGLOST"
| "SIGINFO";