Goで書いたwebサーバーを、Nodeでテストをしています(地獄)。テストする上で、Nodeのchild_processモジュールが孫プロセスをうまくkillできずに躓きました。そこで、孫プロセスをゴリ押しでkillする方法を調べて実装してみました。
孫プロセスのPIDを取得する
孫プロセスのPIDさえ取得できれば、killすることはとてもカンタンにできます。イメージはこんな感じです。
process.kill(mago_pid); // PIDがmago_pidのプロセスをkill
孫プロセスのPIDの取得は、親子共々殺したい - Qiitaを参考に書いてみます。
const child_process = require('child_process'); const server = child_process.spawn('go', ['run', `server.go`]); // サーバーのPIDはserver.pidで取得できる child_process.exec(`ps --ppid=${server.pid} | cut -d' ' -f1`, (error, stdout, stderr) => { if (error) throw new Error(error); // 孫プロセスのPID値を取得できた! console.log(stdout, stderr); });
孫プロセスをkillする
あとは取得したPIDを使ってkillすれば完成です。
const child_process = require('child_process'); const server = child_process.spawn('go', ['run', `server.go`]); (async () => { // サーバーが立ち上がるまで待つ await new Promise(resolve => { server.stdout.on('data', data => { if (data.toString() === 'Start server\nListening port 12345...\n') resolve(); }); }); console.log('server started'); // サーバーのPIDはserver.pidで取得できる const {stdout, stderr} = await new Promise((resolve, reject) => { child_process.exec(`ps --ppid=${server.pid}`, (error, stdout, stderr) => { if (error) reject(error); resolve({stdout, stderr}); }) }); for (const line of stdout.split('\n').slice(1)) { const pid = line.trim().split(' ')[0]; if (pid === '') continue; process.kill(pid, 'SIGINT'); } console.log('finish server'); })();
番外編: util.promisifyを使ってもっと見やすく書く
util.promisifyはべんりなのでドンドン使いましょう
const util = require('util'); const child_process = require('child_process'), exec = util.promisify(child_process.exec).bind(util); const server = child_process.spawn('go', ['run', `server.go`]); (async () => { // サーバーが立ち上がるまで待つ await new Promise(resolve => { server.stdout.on('data', data => { if (data.toString() === 'Start server\nListening port 12345...\n') resolve(); }); }); console.log('server started'); // サーバーのPIDはserver.pidで取得できる const {stdout, stderr} = await exec(`ps --ppid=${server.pid}`); for (const line of stdout.split('\n').slice(1)) { const pid = line.trim().split(' ')[0]; if (pid === '') continue; process.kill(pid, 'SIGINT'); } console.log('finish server'); })();