はじめに
Node.jsのバッチを保守していると、データ増加に伴いメモリー不足で処理が落ちてしまうことがありました。
エラー発生時にはChatworkに通知が飛ぶようにしていたのですが、そのときは通知が飛びませんでした。
そこで、メモリー不足で処理が落ちる前に、ある程度やばそうな量のメモリーを使っている時点で、警告を飛ばすようにしてみました。
処理内容
プログラムは次のような状態でした。
yabaiyo.js
var メモリーを圧迫する変数 = []
function すごく繰り返す処理 (繰り返す回数) {
for (var i = 0; i < 繰り返す回数; i++) {
メモリーを圧迫する変数.push(new Array(10000))
}
}
try {
すごく繰り返す処理(1000000)
} catch (e) {
チャットワークに警告を送信('やばいよ')
}
function チャットワークに警告を送信 (メッセージ) {
console.log(メッセージ + 'をチャットワークに通知しました。')
}
これを実行すると、下記のようなログが出て処理が止まります。
<--- Last few GCs --->
[5414:0x100000000] 4874 ms: Mark-sweep 1824.4 (2051.4) -> 1824.4 (2044.9) MB, 692.6 / 0.0 ms (average mu = 0.075, current mu = 0.014) allocation failure GC in old space requested
<--- JS stacktrace --->
==== JS stack trace =========================================
(省略)
FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
(省略)
zsh: abort node yabaiyo.js
やばいのにChatworkに通知が飛びません。
改善
これを防ぐために、次のような関数を用意しました。
多分ほぼアウトオブメモリー.js
var v8 = require('v8')
function 多分ほぼアウトオブメモリー () {
var stats = v8.getHeapStatistics()
var 五百メガバイト = 500 * 1024 * 1024
var ここを超えるとやばそう = stats.heap_size_limit - 五百メガバイト
return stats.total_heap_size > ここを超えるとやばそう
}
「すごく繰り返す処理」の中に、「多分ほぼアウトオブメモリー」を判定する条件文を入れて、やばそうだったら例外を投げて「チャットワークに警告を送信」するようにしました。
function すごく繰り返す処理 (繰り返す回数) {
for (var i = 0; i < 繰り返す回数; i++) {
メモリーを圧迫する変数.push(new Array(10000))
// ↓ ここに追加
if (多分ほぼアウトオブメモリー()) {
throw new Error('多分ほぼアウトオブメモリー')
}
}
}
ファイルの全体像は下記になります。
yabaiyo.js
var v8 = require('v8')
function 多分ほぼアウトオブメモリー () {
var stats = v8.getHeapStatistics()
var 五百メガバイト = 500 * 1024 * 1024
var ここを超えるとやばそう = stats.heap_size_limit - 五百メガバイト
return stats.total_heap_size > ここを超えるとやばそう
}
var メモリーを圧迫する変数 = []
function すごく繰り返す処理 (繰り返す回数) {
for (var i = 0; i < 繰り返す回数; i++) {
メモリーを圧迫する変数.push(new Array(10000))
if (多分ほぼアウトオブメモリー()) {
throw new Error('多分ほぼアウトオブメモリー')
}
}
}
try {
すごく繰り返す処理(1000000)
} catch (e) {
チャットワークに警告を送信('やばいよ')
}
function チャットワークに警告を送信 (メッセージ) {
console.log(メッセージ + 'をチャットワークに通知しました。')
}
こうすることで、実行したときに次のように出力されます。
$ node yabaiyo.js
やばいよをチャットワークに通知しました。