S3のObjectCreated:PutイベントでLambdaが起動しなかった話

こんにちは、サーバーサイドエンジニア1年目のharukiです。

先日、AWS上でS3トリガーのLambda起動を試していたところ、なかなか上手く行かずに少しハマってしまったため、 今回はそちらの原因と対処法&プチ調査結果についてまとめたいと思います。

本題の前に

まず、今回のお話に出てくるシステムのイメージ図はざっくりと下記の様な形で、 LaravelからのS3へのファイルアップロードに対してLambdaを起動するといった仕組みになっています。

なお、この際AWSの3Sイベント通知ではObjectCreated:PutのみをLambdaのトリガーイベントとして設定していました。

f:id:h0r4k:20220404164302p:plain

問題発生の状況

今回発生した問題としては、アップロードしたファイルサイズによってLambdaが実行されたりされなかったりするというものでした。 (7.9MBのファイルでは成功し、16.9MBのファイルでは失敗するといった感じでした)

はじめは、Lambdaの処理に時間がかかって強制終了しているだけかなと思っていたのですが、 メトリクスのInvocationsをみてもピクリともしておらず、 そもそもLambda自体が呼び出されていないのではということで、 S3アップロード時に発生するイベントについて確認してみました。

実際に発生しているイベントを確認してみる

まず、前回のファイルアップロード時にLambdaの起動に成功・失敗したそれぞれのファイルについて、 LocalStackを使用して実際に発生するイベントを確認してみました。

前回成功していたファイル

前回Lambdaの起動に成功していた7.9MBのファイルでは、ファイルアップロード時にObjectCreated:Putのイベントが発生していました。

{
    "Records": [
        {
            "eventName": "ObjectCreated:Put",
            "s3": {
                "object": {
                    "size": 7888901,
                }
            }
        }
    ]
}
前回失敗していたファイル

前回Lambdaの起動に失敗していた16.9MBのファイルでは、ファイルアップロード時にObjectCreated:CompleteMultipartUploadのイベントが発生していました。

{
    "Records": [
        {
            "eventName": "ObjectCreated:CompleteMultipartUpload",
            "s3": {
                "object": {
                    "size": 16888901,
                }
            }
        }
    ]
}

上記の結果通り、ファイルサイズの違いによってeventNameObjectCreated:PutObjectCreated:CompleteMultipartUploadで異なっていることが確認できました。

解決方法

ということで、AWSの3Sイベント通知に上記の2つObjectCreated:PutObjectCreated:CompleteMultipartUploadをLambda実行のトリガーとして設定することで、無事に問題が解決することが分かりました。

もう少し詳細に

好奇心でもう少し詳細に調べてみます。

まず、Laravel8のS3ファイルアップロードにはleague/flysystem-aws-s3-v3が使用されており、さらにその中ではaws/aws-sdk-phpが呼び出されています。

そしてこのaws/aws-sdk-phpupload関数まで辿っていくと、Docコメントに「アップロードサイズが閾値(mup_threshold)を超えると、multipart uploadsを使用するよ」と記載されていました。

f:id:h0r4k:20220403045255p:plain
aws-sdk-php(3.216.3)のupload関数のDoc

こちらにも同様の記載があります。
Amazon S3 Transfer Manager with AWS SDK for PHP Version 3 - AWS SDK for PHP

mup_threshold (int)
Size in bytes in which a multipart upload should be used instead of PutObject. Defaults to 16777216 (16 MB).

はたしてホントでしょうか・・・?
確かめてみます。

確かめてみる

先程のDocに記載されていた、mup_thresholdの値を基準に、224-1 (16777215) byteのファイルと224 (16777216) byteの2種類のファイルを作成しました。

では、実際にこれらの2つのファイルをアップロードし、イベントの差異を確認してみましょう。

16777215 byteのファイルアップロード時の3Sイベント

結果こちらはObjectCreated:Putとなりました。

{
    "Records": [
        {
            "eventName": "ObjectCreated:Put",
            "s3": {
                "object": {
                    "size": 16777215,
                }
            }
        }
    ]
}
16777216 byteのファイルアップロード時の3Sイベント

結果こちらはObjectCreated:CompleteMultipartUploadとなりました。

{
    "Records": [
        {
            "eventName": "ObjectCreated:CompleteMultipartUpload",
            "s3": {
                "object": {
                    "size": 16777216,
                }
            }
        }
    ]
}

やはりDocに記載の通り、mup_thresholdの値 224 byteがPutObjectCreateMultipartUploadの実行の境目となっているようです。

ということで、今回はS3ファイルアップロード時のイベントについてのプチ調査記事でした。
最後まで見て頂きありがとうございました。

さいごに

これまで培った技術力を活かして地域を元気にしたいという想いを持っている方を絶賛募集中です。
ご興味をお持ちいただけましたら、是非以下の募集ページをご覧ください!

www.wantedly.com