【第10回】AWS Lambdaにおけるサーバレスエラーハンドリング(5)


本連載では、AWS Lambdaを使ったサーバレス処理でのエラーハンドリング方法を解説しています。 前回は以下の赤字の矢印のスコープにおいて、同期的なLambdaの呼び出しでシステムエラーが発生するケースを想定して、CloudWatch Logsに出力されたログをイベント契機として実行される、 Spring Cloud Functionを使ったLambdaファンクションを実装を解説しました。今回は実際にCloudWatch Logsに出力されたログをサブスクリプションして、Mattermostへメッセージ通知する環境を構築します。


../_images/errorhandling-sync-system-error.png


CloudFormationを使用したLambda環境の構築・CloudWatchサブスリプションの設定


LambdaファンクションのCloudFormationテンプレート の手順で構築したLambdaテンプレートに、前回実装したLambdaファンクションを追加して、スタックを作成し直します。


AWSTemplateFormatVersion: '2010-09-09'

#omit

Resources:
  LambdaForSyncExecuteSystemErrorFuntion:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket:
          Fn::ImportValue: debugroom-mynavi-sample-lambda-errorhandling-deploy-s3-bucket
        S3Key: spring-cloud-3-1-lambda-function-0.0.1-SNAPSHOT-aws.jar
      Handler: org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest
      FunctionName: mynavi-sample-aws-lambda-errorhandling-sync-system-error
      Environment:
        Variables:
          SPRING_CLOUD_FUNCTION_DEFINITION: syncExecuteSystemErrorFunction
      MemorySize: 1024
      Runtime: java11
      Timeout: 120
      Role: !GetAtt LambdaRole.Arn


  #omit

  LambdaForNotifySystemErrorFuntion:
    Type: AWS::Lambda::Function
    Properties:
      Code:
        S3Bucket:
          Fn::ImportValue: debugroom-mynavi-sample-lambda-errorhandling-deploy-s3-bucket
        S3Key: spring-cloud-3-1-lambda-function-0.0.1-SNAPSHOT-aws.jar
      Handler: org.springframework.cloud.function.adapter.aws.FunctionInvoker::handleRequest
      FunctionName: mynavi-sample-aws-lambda-errorhandling-notify-system-error
      Environment:
        Variables:
          SPRING_CLOUD_FUNCTION_DEFINITION: notifySystemErrorFunction
      MemorySize: 1024
      Runtime: java11
      Timeout: 120
      Role: !GetAtt LambdaRole.Arn

  #omit

Outputs:
  #omit

  LambdaForSyncExecuteSystemErrorFuntion:
    Description: Sync execute Lambda function for occuring system error function.
    Value: !Ref LambdaForSyncExecuteSystemErrorFuntion
    Export:
      Name: mynavi-sample-lambda-errorhandling-sync-execute-system-error-function-name

  LambdaForSyncExecuteSystemErrorFuntionArn:
    Description: Sync execute Lambda function for occuring system error function.
    Value: !GetAtt LambdaForSyncExecuteSystemErrorFuntion.Arn
    Export:
      Name: mynavi-sample-lambda-errorhandling-sync-execute-system-error-function-arn

  #omit

  LambdaForNotifySystemErrorFuntion:
    Description: Lambda function for notifying system error function.
    Value: !Ref LambdaForNotifySystemErrorFuntion
    Export:
      Name: mynavi-sample-lambda-errorhandling-notify-system-error-function-name

  LambdaForNotifiySystemErrorFuntionArn:
    Description: Lambda function for notifying system error function.
    Value: !GetAtt LambdaForNotifySystemErrorFuntion.Arn
    Export:
      Name: mynavi-sample-lambda-errorhandling-notify-system-error-function-arn


同様に、API Gatewayのテンプレートも、システムエラーが発生するファンクション向けにメソッドやリソースを定義して構築し直します。


#omit

ApiGatewaySystemExceptionResource:
  Type: "AWS::ApiGateway::Resource"
  Properties:
    RestApiId:
      Ref: ApiGatewayRestApi
    ParentId:
      Fn::GetAtt:
        - ApiGatewayRestApi
        - RootResourceId
    PathPart: "system-exception-sample-resource"

#omit

ApiGatewaySystemExceptionMethod:
  Type: "AWS::ApiGateway::Method"
  DependsOn: ApiGatewayModel
  Properties:
    RestApiId:
      Ref: ApiGatewayRestApi
    ResourceId:
      Ref: ApiGatewaySystemExceptionResource
    HttpMethod: "GET"
    AuthorizationType: "NONE"
    Integration:
      Type: "AWS_PROXY"
      Uri:
        Fn::Join:
          - ""
          - - "arn:aws:apigateway"
            - ":"
            - Ref: AWS::Region
            - ":"
            - "lambda:path/2015-03-31/functions/"
            - Fn::ImportValue: mynavi-sample-lambda-errorhandling-sync-execute-system-error-function-arn
            - "/invocations"
      IntegrationHttpMethod: "POST"
      PassthroughBehavior: WHEN_NO_MATCH
    MethodResponses:
      - StatusCode: 200
        ResponseModels:
          application/json: SampleSchema
      - StatusCode: 400
        ResponseModels:
          application/json: Error

SystemErrorLambdaPermission:
  Type: "AWS::Lambda::Permission"
  Properties:
    FunctionName:
      Fn::ImportValue: mynavi-sample-lambda-errorhandling-sync-execute-system-error-function-name
    Action: "lambda:InvokeFunction"
    Principal: "apigateway.amazonaws.com"


続いて、CloudWatchにサブスクリプションフィルタおよびロググループ、実行権限に関するテンプレートを実装します。


AWSTemplateFormatVersion: '2010-09-09'

#omit

Resources:
  CloudWatchLogsSyncExecuteSystemErrorSubscription:  #(1)
    Type: AWS::Logs::SubscriptionFilter
    Properties:
      LogGroupName: !Ref LogsGroupSyncExecuteSystemError
      FilterPattern: "Exception"                     #(2)
      DestinationArn:
        Fn::ImportValue: mynavi-sample-lambda-errorhandling-notify-system-error-function-arn #(3)

  LogsGroupSyncExecuteSystemError:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName:
        Fn::Join:
          - ""
          - - "/aws/lambda/"
            - Fn::ImportValue: mynavi-sample-lambda-errorhandling-sync-execute-system-error-function-name #(4)

  NotifyErrorLambdaPermission: #(5)
    Type: AWS::Lambda::Permission
    Properties:
      FunctionName:
        Fn::ImportValue: mynavi-sample-lambda-errorhandling-notify-system-error-function-name
      Action: lambda:InvokeFunction
      Principal: !Join [ ".", [ "logs", !Ref "AWS::Region", "amazonaws.com" ] ]
      SourceAccount: !Ref AWS::AccountId


ファンクションクラスの実装コードの詳細
項番 説明
CloudWatch Logsで特定のログをサブスクリプションする設定を行います。各プロパティの詳細は Type: AWS::Logs::SubscriptionFilter を参照してください。
ログでピックアップ対象とする文字列パターンを指定します。前節の実際の実装ではSystemExceptionをスローしていますが、実際は様々な想定外のExceptionクラスがスローされることになるので、「Exception」をパターン文字列として設定します。
実行するLambdaファンクションのARNをクロススタックリファレンスで参照します。
監視対象とするロググループを指定します。前節で作成したシステム例外を発生するLambdaファンクションのログが出力されるロググループを指定しています。
ロググループにLambdaの実行権限を付与します。


これらのテンプレートを実行し、環境を構築します。また、本連載では説明は省略しますが、 Mattermost環境の構築 や、Webhook の設定を行い、 URLをSystemsManager ParameterStoreに設定しておきます。なお、SystemsManager ParameterStoreの設定に関しては、AWSで実践! 基盤構築・デプロイ自動化で解説した 「第29回」 などを適宜参考にしてください。

必要な環境構築・設定後、API GatewayのCloudFormationテンプレート で実行した要領と同様、API Gatewayからシステムエラーが発生するファンクションを実行すると以下の通り、API Gatewayからインターナルサーバエラーが返却されます。


../_images/management-console-apigateway-resource-test-2.png


CloudWatch Logsには発生したエラーのスタックトレースが記録されます。


../_images/management-console-cloudwatch-logs-sync-system-error.png


CloudWatch Logsのサブスクリプションが別途Lambdaファンクションを呼び出し、Mattermost側へエラー内容を通知します。システム管理者や運用担当者はエラーの内容を確認して、AWSの外で優先度を設定し対応することができます。


../_images/mattermost-notification.png



今回は、API GatewayとLambdaを使用した同期呼び出しで、システムエラーが発生した際に、CloudWatchに出力されたエラーログを契機として、システム管理者へ通知を行うLambdaファンクション実装を含めて解説しました。 次回は、S3などのマネージドサービスから非同期に実行されるLambdaファンクション内で発生したエラーのハンドリングについて解説を進めていきます。


著者紹介

川畑 光平(KAWABATA Kohei) - NTTデータ エグゼクティブ ITスペシャリスト ソフトウェアアーキテクト・デジタルテクノロジーストラテジスト(クラウド)

../_images/aws_361383_075.jpeg

金融機関システム業務アプリケーション開発・システム基盤担当、ソフトウェア開発自動化関連の研究開発を経て、デジタル技術関連の研究開発・推進に従事。

Red Hat Certified Engineer、Pivotal Certified Spring Professional、AWS Certified Solutions Architect Professional等の資格を持ち、アプリケーション基盤・クラウドなど様々な開発プロジェクト支援にも携わる。

AWS Top Engineers & Ambassadors 選出。

本連載記事の内容に対するご意見・ご質問は Facebook まで。