スポンサーリンク
ちょいとハマったのでメモ。
EC2上のNode.jsから以下のようなソースを書いてSQSからメッセージを受信していました。
await sqs.receiveMessage(params , function(err, data) {
if (err) {
console.log(err, err.stack);
} else {
...
}
}).promise();
SQSに突っ込む件数が少ないうちは問題なかったんですが、件数を増やしていくと以下のエラーが出るように(T T)
TypeError: Cannot read property 'push' of undefined
調べてみると、どうやらaws-sdkの以下の部分で起こっているようです。
- 対象ソース:aws-sdk/lib/event_listeners.js
add('HTTP_DATA', 'httpData', function HTTP_DATA(chunk, resp) {
if (chunk) {
if (AWS.util.isNode()) {
resp.httpResponse.numBytes += chunk.length;
var total = resp.httpResponse.headers['content-length'];
var progress = { loaded: resp.httpResponse.numBytes, total: total };
resp.request.emit('httpDownloadProgress', [progress, resp]);
}
// ココでエラー
resp.httpResponse.buffers.push(AWS.util.buffer.toBuffer(chunk));
}
});
なぜかレスポンスのbuffersが削除されている模様。
どうやら同じソースにある以下の処理が先に動いてしまっているみたいです。
add('HTTP_DONE', 'httpDone', function HTTP_DONE(resp) {
// convert buffers array into single buffer
if (resp.httpResponse.buffers && resp.httpResponse.buffers.length > 0) {
var body = AWS.util.buffer.concat(resp.httpResponse.buffers);
resp.httpResponse.body = body;
}
delete resp.httpResponse.numBytes;
delete resp.httpResponse.buffers; // ココでbuffersを消している
});
処理内容を見る感じだと、処理の実行順序が誤って動作している様子。
- 正しい動き: HTTP_DATAの関数が動いてから、HTTP_DONEの関数が動く
- エラー時の動き:HTTP_DONEの関数が動いてから、HTTP_DATAの関数が動いている
うーん、これ系はなんとなく非同期処理周りがあやしい気がする・・・
ネットをいろいろ調べていると、以下のページで同じような事象にハマっている人を発見!
https://github.com/aws/aws-sdk-js/issues/2700
読み進めてみると、event_listeners.jsを変更すれば解決したというレスが。
でもsdkのソースを書き換えるのはちょっとなあ・・・
そう思いながらさらに読み進めると、以下のように実装すると解決するというレスを見つけました!!
(この記事ではdynamoDB.scanでしたが、事象は同じっぽい)
new Promise((resolve, reject) => {
sqs.receiveMessage(params , function(err, data) {
if (err) {
console.log(err, err.stack);
reject(err);
} else {
...
resolve(data);
}
}
});
実際にやってみたところ・・・無事解決!!
うーん、Promiseはまだまだ謎が多いなあ・・・もっと勉強せねば。
コメントを残す