loopbackでサーバーからバックグラウンドジョブを起動するサンプル。 子プロセスとして4つのバックグラウンドジョブを動作させる。
キャットファーム デモ
ソース:
https://github.com/yamorijp/catfarm
セットアップ&起動:
nodejs 5.6.xとnpmをインストールしてパスを通しておく。
$ git clone https://github.com/yamorijp/catfarm.git
$ cd catfarm-demo
$ npm install
$ npm start
仕様:
- 飼い主は家が準備出来たら4匹の猫を連れてくる。
- 飼い主は猫パンチを食らうとうめき声をあげ、猫をかわいがる。
- 飼い主は猫が居なくなると、すぐに連れ戻す。
- 猫はたまに「にゃー」と鳴く。
- 猫は稀に「みゃー」と鳴く。
- 猫は空腹になったら餌を催促し、飼い主に猫パンチを食らわす。
- 猫はしばしばいなくなる。
実装:
/server/server.js
サーバー用のbootディレクトリを追加し、オプションで指定する。
var options = {
"appRootDir": __dirname,
"bootDirs": [path.join(__dirname, "boot", "server")]
};
boot(app, options, err => {
if (err) throw err;
// start the server if `$ node server.js`
if (require.main === module)
app.start();
});
/server/boot/server/catfarm.js
サーバーが起動したら、バックグラウンドジョブをprocess.fork
で起動する。
app.on("started", () => {
cats.forEach((args, i, arr) => restart(args));
});
function restart(args) {
var child = fork(path.join(__dirname, '../../jobs/cat.js'), args);
...
}
ジョブからのメッセージは"message"イベントで受け取る。
ジョブへのメッセージ送信はsendメソッドを使う。ジョブが終了した場合は"close"イベントが発生する。
child
.on("message", (msg) => {
if (msg == 'punch') {
console.log(`${master}: Ouch!`[color]);
console.log(`${master}: ${args[0]}, wait a minutes.`[color]);
}
child.send("patting");
})
.on("close", () => {
console.log(`${master}: Come back, ${args[0]}.`[color]);
restart(args);
});
server/jobs/cat.js
バックグランドジョブの実装。
最初にloopback-boot#boot
をコールしてフレームワークを起動する。
boot(app, path.join(__dirname, '..'), function(err) {
if (err) throw err;
main();
});
猫の振る舞いを実装。
process.send
で親プロセスにメッセージを送信。
process.exit()
でプロセス終了。
function main() {
...
setInterval(() => {
// 稀にいなくなる
console.log(`-- ${name} lost. --`[color]);
process.exit();
}, random(20000, 50000));
process.on("message", (msg) => {
// 飼い主のいうことは全て無視
console.log(`${name}: ...`[color]);
});
}
メモ
- jobの最初に
loopback-boot#boot
をコールする。boot完了後からapp.models
でモデルオブジェクトを参照できるようになる。 - ブートディレクトリはサーバー用に別途用意し、デフォルトの/bootはジョブと共用する。
bootDirs
オプションを指定しても必ず/boot内のスクリプトをrequire
するようハードコードされている。 - jobは別プロセスで動作するのでモデルを編集してもサーバー側には通知されない。通知は
process.send(message)
やpubsub
で実装できる。