背景
nodejsのシステムで、httpリクエストがあってからDB更新するまで、排他制御をする必要が出てきました。
方法概要
いろいろとネット上を調べてみた結果、async.jsのQueueでconcurrencyを1、pause(),resume()を使えばできるのでは?と考えました。
https://github.com/caolan/async#queue
実装したコード
var http = require('http');
var async = require('async');
var server = http.createServer();
var q = async.queue(function (task, done) {
console.log("task:"+task.name);
done();
}, 1); // 同時実行数を1に制限
var index=0;
server.on('request', function (request, response) {
response.writeHead(200);
var taskname='task_'+index;
console.log('task push!: ' + taskname);
index++;
q.push({
name: taskname,
}, function (err) {
q.pause(); // queueのタスク実行を一時停止する
setTimeout(function(){
console.log({message: taskname });
// 実際のDBデータ取得・更新処理など。コールバック処理でq.resume()を実行
q.resume(); // queueのタスクを再開する
response.end();
},500);
});
}).listen(8080);
実行
loadtestを使って実行してみます。
$ loadtest -n 1 -c 10 http://localhost:8080
結果です。
$ node index.js
task push!: task_0
task:task_0
task push!: task_1
task push!: task_2
task push!: task_3
task push!: task_4
task push!: task_5
task push!: task_6
task push!: task_7
task push!: task_8
task push!: task_9
{ message: 'task_0' }
task:task_1
{ message: 'task_1' }
task:task_2
{ message: 'task_2' }
task:task_3
{ message: 'task_3' }
task:task_4
{ message: 'task_4' }
task:task_5
{ message: 'task_5' }
task:task_6
{ message: 'task_6' }
task:task_7
{ message: 'task_7' }
task:task_8
{ message: 'task_8' }
task:task_9
{ message: 'task_9' }
まとめ
ひとまず排他的な動作にはなったのですが、この方法で良いのかもう少し勉強してみます。
当然なのですが、エラーなどでresume()を忘れると、ずっと止まります。
NodeJS初心者なので、「こうしたほうがよい」などありましたらご教授ください。