web-dev-qa-db-ja.com

s3.getObject()。createReadStream():エラーをキャッチする方法は?

私はs3からZipファイルを取得し、それを解凍し、それをS3にアップロードするプログラムを作成しようとしています。しかし、私はキャッチできない2つの例外を見つけました。

1。StreamContentLengthMismatch: Stream content length mismatch. Received 980323883 of 5770104761 bytes.これは不規則に発生します。

2。NoSuchKey: The specified key does not exist.これは、間違ったキーを入力したときに発生します。

これらの2つの例外が発生すると、このプログラムはクラッシュします。

これらの2つの例外を正しくキャッチして処理したいと思います。

クラッシュを防ぎたい。

   const unzipUpload = () => {
        return new Promise((resolve, reject) => {
            let rStream = s3.getObject({Bucket: 'bucket', Key: 'hoge/hoge.Zip'})
                .createReadStream()
                    .pipe(unzip.Parse())
                    .on('entry', function (entry) {
                        if(entry.path.match(/__MACOSX/) == null){

                            // pause
                            if(currentFileCount - uploadedFileCount > 10) rStream.pause()

                            currentFileCount += 1
                            var fileName = entry.path;
                            let up = entry.pipe(uploadFromStream(s3,fileName))

                            up.on('uploaded', e => {
                                uploadedFileCount += 1
                                console.log(currentFileCount, uploadedFileCount)

                                //resume
                                if(currentFileCount - uploadedFileCount <= 10) rStream.resume()

                                if(uploadedFileCount === allFileCount) resolve()
                                entry.autodrain()
                            }).on('error', e => {
                                reject()
                            })
                        }

                    }).on('error', e => {
                        console.log("unzip error")
                        reject()
                    }).on('finish', e => {
                        allFileCount = currentFileCount
                    })
            rStream.on('error', e=> {
                console.log(e)
                reject(e)
            })
        })
    }

    function uploadFromStream(s3,fileName) {
        var pass = new stream.PassThrough();

        var params = {Bucket: "bucket", Key: "hoge/unzip/" + fileName, Body: pass};
        let request = s3.upload(params, function(err, data) {
            if(err) pass.emit('error')
            if(!err) pass.emit('uploaded')
        })
        request.on('httpUploadProgress', progress => {
            console.log(progress)
        })

        return pass
    }

これは、解凍時に使用するライブラリです。 https://github.com/mhr3/unzip-stream

助けて!!

18
tomoya ishizaka

NoSuchKeyによってスローされるcreateReadStreamエラーをキャッチしたい場合、2つのオプションがあります。

  1. キーを読み込む前に存在するかどうかを確認してください。
  2. ストリームからエラーをキャッチ

最初の

s3.getObjectMetadata(key)
  .promise()
  .then(() => {
    // This will not throw error anymore
    s3.getObject().createReadStream();
  })
  .catch(error => {
    if (error.statusCode === 404) {
      // Catching NoSuchKey
    }
  });

getObjectMetadataからの応答の解析とcreateReadStreamの実行の間で、ファイルが一瞬で削除された場合にエラーをキャッチしない唯一のケース

2番目

s3.getObject().createReadStream().on('error', error => {
    // Catching NoSuchKey & StreamContentLengthMismatch
});

これはより一般的なアプローチであり、ネットワークの問題など、他のすべてのエラーをキャッチします。

16
Vlad Holubiev

発生したエラーを早期にリッスンする必要があります。エラーハンドラは、解凍部分のエラーのみを探します。

スクリプトの簡易バージョン。

s3.getObject(params)
.createReadStream()
.on('error', (e) => {
  // handle aws s3 error from createReadStream
})
.pipe(unzip)
.on('data', (data) => {
  // retrieve data
})
.on('end', () => {
  // stream has ended
})
.on('error', (e) => {
  // handle error from unzip
});

この方法では、AWSが存在するかどうかを確認するためにAWSに追加の呼び出しを行う必要はありません。

4
dmo

受信しているストリーム内のイベント(エラー、データ、終了など)をリッスンできます。 イベントの詳細を読む

function getObjectStream (filePath) {
  return s3.getObject({
    Bucket: bucket,
    Key: filePath
  }).createReadStream()
}

let readStream = getObjectStream('/path/to/file.Zip')
readStream.on('error', function (error) {
  // Handle your error here.
})

「キーなし」エラーのテスト済み。

it('should not be able to get stream of unavailable object', function (done) {
  let filePath = 'file_not_available.Zip'

  let readStream = s3.getObjectStream(filePath)
  readStream.on('error', function (error) {
    expect(error instanceof Error).to.equal(true)
    expect(error.message).to.equal('The specified key does not exist.')
    done()
  })
})

成功のテスト済み

it('should be able to get stream of available object', function (done) {
  let filePath = 'test.Zip'
  let receivedBytes = 0

  let readStream = s3.getObjectStream(filePath)
  readStream.on('error', function (error) {
    expect(error).to.equal(undefined)
  })
  readStream.on('data', function (data) {
    receivedBytes += data.length
  })
  readStream.on('finish', function () {
    expect(receivedBytes).to.equal(3774)
    done()
  })
})
1
Rash