[AWS] EC2上のNode.jsでSQSのメッセージを受信した際に軽くハマった話

スポンサーリンク

ちょいとハマったのでメモ。

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はまだまだ謎が多いなあ・・・もっと勉強せねば。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です