大したことない作業のようですが、若干つまりどころがあったので残しておきます。
やりたいこと
とあるS3バケットにあるgzipファイル(中身はjson)が生成されるたびに一部加工して、別のバケットに再圧縮して出力したい。
図を書くほどのものでもないんですが、こんな構成になります。
どうやるか
Source BucketからSQSに通知してLambdaを呼び出すところは一般的な設定なので割愛します。
gzipを取り扱えるnpmパッケージは有名どころだとnode-zipなどがありますが、zlibだけで出来ましたので今回のようなシンプルなケースだと外部パッケージは不要でした。
解凍・加工・再圧縮を行うLambdaは下記のようになります。(nodejs14.x)
const AWS = require('aws-sdk')
const s3 = new AWS.S3()
const zlib = require('zlib');
exports.handler = async (event) => {
try{
for (const record of event.Records) {
for (const recordBody of JSON.parse(record.body)) {
const key = recordBody.s3.object.key
if (/\.gz$/.test(key)){
// Source Bucketからgzipオブジェクトを取得
const getParams = {
Bucket: 'SOURCE_BUCKET_NAME',
Key: key
}
const source = await s3.getObject(getParams).promise()
// 1. 解凍
const sourceData = JSON.parse(zlib.gunzipSync(source.Body))
// 2.加工
// ...
// 3. 再圧縮
const destData = zlib.gzipSync(JSON.stringify(sourceData))
// 4. 保存
const putParams = {
Bucket: 'DESTINATION_BUCKET_NAME',
Key: key,
Body: destData,
ContentType: 'application/json',
ContentEncoding: 'gzip'
}
await s3.putObject(putParams).promise()
}
}
}
// done
return true
}catch(err){
throw new Error("Exception error")
}
}
1. 解凍
zlib.gunzipSync(data)
dataは下記の形式いずれかとなります。今回はバケットから取得したBuffer値をそのまま入れています。
<Buffer> | <TypedArray> | <DataView> | <ArrayBuffer> | <string>
第2引数でオプションを渡すことも可能です。
zlib.gunzipというメソッドもありますが、別スレッドでのコールバック形式になります。
zlib.gunzipSyncだと同スレッドでの実行となるためコールバック形式となりません。
2. 加工
解凍後のデータ(今回はjson形式)をここで加工しています。
3. 再圧縮
zlib.gzipSync(data)
dataは下記の形式いずれかとなります。今回は加工したstringをそのまま入れています。
<Buffer> | <TypedArray> | <DataView> | <ArrayBuffer> | <string>
第2引数でオプションを渡すことも可能です。
こちらも同様にzlib.gzipというメソッドもあり、別スレッドでのコールバック形式になります。
zlib.gzipSyncだと同スレッドでの実行となるためコールバック形式となりません。
4. 保存
Destination Bucketにputするだけ、ではあるのですが、今回保存するのはjsonをgzip圧縮したものなので下記のメタデータを付けています。
ContentType: 'application/json'
ContentEncoding: 'gzip'
このメタデータを付けることによってS3でのオブジェクトの取り扱いが変わり、コンソールからダウンロードした際に自動的に解凍されるようになります。
ちなみにメタデータを付けず保存した場合はContentTypeがapplication/octet-stream
となります。
このあたりは後続の処理に応じて適切な値を付けるのが望ましいと思います。
その他
エラーハンドリングについてもDLQの再処理や後続の処理に影響があるので適宜調整が必要です。
今回は再処理をそこまでシビアに考える必要が無かったためシンプルな記載にしています。
参考
https://nodejs.org/api/zlib.html
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/UsingMetadata.html