非同期Lambdaの注意点とタイムアウト検知

AWS

S3のイベント通知などで動作させるバッチ系のAWS Lambdaを設計する際の注意点とAWS Lambdaがタイムアウトになった場合の検知方法についてです。

非同期AWS Lambda設計時の注意点

非同期Lambdaの場合、エラー発生時のリトライ回数がデフォルトで2回になっています。
バッチ系の処理をしている場合、処理が2回行われると困る場面もあると思いますので、そのような場合はリトライ回数を0回に設定しておきましょう。

明示的に正常、エラーを返却しているような関数でも予期せぬAWS障害等でLambdaがタイムアウトになる可能性もあるので要注意です。

非同期AWS Lambdaのタイムアウト検知

非同期Lambdaでタイムアウトが発生した場合、
SQS、SNS、Lambda、EventBridge
に通知をすることが可能です。

別のアプローチとしてデッドレターキューを利用する方法もありますが
今回はLambdaに通知するサンプルを記載します。

AWS SAMテンプレートサンプル

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: >
  error-notice-sample

Resources:
  # タイムアウトエラーを発生させるLambda
  LogOutputFunc:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: log_output_func/
      Handler: app.lambda_handler
      Runtime: python3.8
      Events:
        LogOutputFuncEvent:
          Type: S3
          Properties:
            Bucket:
              Ref: MyBucket
            Events: s3:ObjectCreated:*
      EventInvokeConfig:
        # 非同期Lambdaのリトライ回数を0回に設定
        MaximumRetryAttempts: 0
        DestinationConfig:
          # エラー発生時に呼び出すLambdaを指定
          OnFailure:
            Type: Lambda
            Destination: !GetAtt ErrorNoticeFunc.Arn

  # LogOutputFuncでエラー発生した場合に起動するLambda
  ErrorNoticeFunc:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: error_notice_func/
      Handler: app.lambda_handler
      Runtime: python3.8

  MyBucket:
    Type: "AWS::S3::Bucket"
    Properties:
      BucketName: "2021-yy-dd-mytestbucket"
      AccessControl: Private
      PublicAccessBlockConfiguration:
        BlockPublicAcls: true
        BlockPublicPolicy: true
        IgnorePublicAcls: true
        RestrictPublicBuckets: true

エラー通知側AWS LambdaのEventオブジェクト

ErrorNoticeFuncが呼び出された時にどのようなEventデータが取得できるか?
ですが、以下は実行時例外発生時のEventデータサンプルです。
スタックトレースやリクエストパラメータ等も格納されています。

{
'version': '1.0',
'timestamp': '2021-12-08T12:11:29.345Z',
'requestContext':
  {'requestId': 'xxxx-xxxx-xxxx',   
  'functionArn': 'arn:aws:lambda:ap-northeast-1:xxx:function:xxxfuncname:$LATEST',
   'condition': 'RetriesExhausted',
   'approximateInvokeCount': 1},
   'requestPayload':
   {'Records': [
    {'eventVersion': '2.1',
     'eventSource': 'aws:s3', 
     'awsRegion': 'ap-northeast-1',
     'eventTime': '2021-12-08T12:11:27.454Z',
     'eventName': 'ObjectCreated:Put',
     'userIdentity': {'principalId': 'AWS:xxxx'},
     'requestParameters': {
      'sourceIPAddress': 'xxx.xx.38.00'}, 
      'responseElements': {
      'x-amz-request-id': 'xxx',
      'x-amz-id-2': 'xxx'},
`         's3': {'s3SchemaVersion': '1.0',
                 'configurationId': 'xxx', 
          'bucket': {'name': 'xxx', 
          'ownerIdentity':
          {'principalId': 'xxx'}, 
      'arn': 'arn:aws:s3:::bucketname'},
       'object': {'key': '6.html', 'size': 1584, 
             'eTag': 'xxx', 
                      'sequencer': 'xxxx'}}}]},
 'responseContext':
 {'statusCode': 200,
 'executedVersion': '$LATEST',
 'functionError': 'Unhandled'},
 'responsePayload': {
   'errorMessage': "'ab'",
   'errorType': 'KeyError',
   'stackTrace': ['  File "/var/task/app.py", 
   line 12, in lambda_handler\n    a = map["ab"]\n']}}

タイムアウト発生時も同様のEventが渡されます。
エラーメッセージは以下のように「Task timed out after xxx」が出力されます。

{'errorMessage':
 '2021-12-08T12:26:13.100Z xxxx-xxxx Task timed out after 3.00 seconds'}}

以上

タイトルとURLをコピーしました