Panda Noir

JavaScript の限界を究めるブログでした。最近は幅広めに書いてます。

Nodeで外部のwebサーバーを建ててkillするまで

NodeでGoで書いたwebサーバーのテストをしている(地獄)のですが、child_processが孫プロセスをうまくkillできなかったので、ゴリ押しでkillする手法を考えました。

孫プロセスのPIDを取得する

孫プロセスのPIDを取得できれば、killすることはカンタンにできます。

process.kill(mago_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);
    console.log(stdout, stderr);
});

孫プロセスを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');
})();