なっく日報

技術やら生活やらのメモ

Node.jsでThreadLocal変数的なやつ

TL;DR

Node.jsでスレッドローカル変数を使うような処理を実現したい場合

GitHub - othiym23/node-continuation-local-storage: implementation of https://github.com/joyent/node/issues/5243

が使えるかもという話です。

きっかけ

kenn.hatenablog.com

に書いているようなユースケースです。

モデル層とかサービス層(とにかく、コントローラ層より深いところ)でHTTP Requestでやって来た情報(APIバージョンだとか、ユーザエージェントだとか)

を使いたい場合、Node.jsだとスレッドローカル変数みたいなのは使えません。

代替案として、パッと思い浮かぶのは第1引数に必要な情報の詰まったオブジェクトをひたすら引き渡し続けるように規約で縛るくらいだけど

それもイケてないなぁと。

JavaだとThreadLocalとかで一発なんだけど、なんかないだろうか?

一応あった

ググって見た感じ、othiym23という有名な方が

context: core module to manage generic contexts for async call chains · Issue #5243 · nodejs/node-v0.x-archive · GitHub

なissueを上げており、

github.com

なものを作ったみたいでした。

使い方

ソース

a.js

'use strict';
var createNamespace = require('continuation-local-storage').createNamespace;
var session = createNamespace('my session');

var finish = require('./b');

module.exports = 1;

function handle(obj) {
  session.set('obj', obj);
}

session.run(function() {
  var obj = {
    count: 1,
  };
  handle(obj);
  setTimeout(function() {
    finish();
  }, 2000);
});

session.run(function() {
  var obj = {
    count: 2,
  };
  handle(obj);
  setTimeout(function() {
    finish();
  }, 1000);
});

b.js

'use strict';
var getNamespace = require('continuation-local-storage').getNamespace;
var session = getNamespace('my session');

module.exports = function() {
  var obj = session.get('obj');
  console.log(obj);
}

実行

node a.js
// { count: 2 }
// { count: 1 }

何が実現できた?

タイミングによらずsession.run(function() {})のスコープで設定したオブジェクトを session.get('obj');で取得できているようです。

あんま使ったことないですが、Node.jsのdomainっぽいですね。 https://nodejs.org/api/domain.html

まとめ

パフォーマンス的な部分は検証してないので、何ともですが、なんとなく使えそうな気はしています。

この記事を見た人で、実際使っているとか、もっといい方法があるとかあれば、教えていただければ幸いです。

補足

github.com

This is similar to the concept of thread-local data in Java.

とあり、求めていたものズバリでした。

が、まだまだ開発中とのことで、本番導入は無理かなぁというところです。