Amazon API GatewayのREST APIからLambdaを非同期に呼んでみた

Amazon API GatewayのREST APIから非同期にLambdaを呼び出し、ジョブキュー的にイベントを処理する方法を紹介します。
2020.04.19

Amazon API Gateway でジョブ系のイベントを受け取る場合、イベントを非同期で処理したいときがあります。

非同期に処理すると、バックエンドの処理が完了するのを待たず、29秒のタイムアウトを気にすることなく即座にクライアントにレスポンスを返せたり、キューイングを利用してより堅牢にイベントを処理できるなど、様々なメリットがあります。

そこで Amazon API Gateway の REST API から非同期に Lambda を呼び出し、ジョブキュー的にイベントを処理する方法を紹介します。

非同期Lambdaでイベントをキュー管理する

非同期呼び出しの場合、イベントはキューで管理されます。

このキューにはエラー発生時に再試行する仕組みが備わっており、イベント処理の成功・失敗に応じて別のサービスにレコードを送信できます。

送信先の失敗設定はデッドレターキューとして利用できるため、イベントをより堅牢に処理できます。

前提

Lambdaの非同期呼び出しは REST API の Lambda プロキシ統合でのみ利用できます。

  • REST API の Lambdaプロキシ統合
  • HTTP API

では利用できません。

API Gateway から Lambda を非同期に呼び出す

コンソールで設定

Lambda を非同期に呼び出すには、Integration Request の HTTP ヘッダーに以下のフィールドを追加します。

  • Name : X-Amz-Invocation-Type
  • Mapping from: 'Event'

Serverless フレームワークで非同期 API を構築

API Gateway を構築するのは手間なので、Serverless フレームワークで構築してみました。

https://github.com/quiver/aws-api-gateway-async-lambda-sample

デプロイ方法

$ serverless install -u https://github.com/quiver/aws-api-gateway-async-lambda-sample
$ cd aws-api-gateway-async-lambda-sample
$ serverless deploy
...
endpoints:
  GET - https://XXX.execute-api.ap-northeast-1.amazonaws.com/dev/sync
  GET - https://XXX.execute-api.ap-northeast-1.amazonaws.com/dev/async
...

3秒かかる処理を用意し

import time

def func(event, context):
    time.sleep(3)
    return {'statusCode': 200,
            'body': 'ok'}

同期(sync)・非同期(async)に呼び出せるようにしてあります。

Serverless フレームワークでは、events の設定で async オプションを true にしたフィールドを追加すると、非同期呼び出しになります。

...
functions:
  func_name:
    handler: filename.hander_name
    events:
      - http:
          path: sync
          method: get
          async: true

同期・非同期の違いを確認

同期・非同期それぞれのエンドポイントを呼び出してみます。

同期呼び出し

$ time curl -s -o /dev/null \
  https://XXX.execute-api.ap-northeast-1.amazonaws.com/dev/sync
curl -s -o /dev/null   0.01s user 0.01s system 0% cpu 3.166 total

同期呼び出しは、バックエンドの処理が完了してからレスポンスを返します。 そのため、リクエスト完了に3秒以上かかっています。

非同期呼び出し

$ time curl -s -o /dev/null \
  https://XXX.execute-api.ap-northeast-1.amazonaws.com/dev/async
curl -s -o /dev/null   0.02s user 0.01s system 15% cpu 0.153 total

非同期呼び出しでは、バックエンドを呼び出すと、その処理の成功・失敗を待たずに即座にレスポンスを返します。 そのため、リクエスト完了にわずか 0.153 秒しかかかっていません。

より堅牢にイベントを処理

イベントをより堅牢に処理したい場合、Lambda 関数の

  • 再試行回数
  • 送信先

を適宜設定し、要件に合わせて異常系フローを適切に処理してください。

参考 : 非同期呼び出しAWS Lambdaのエラーハンドリング機能を整理してみた(宛先指定・経過時間・試行回数・DLQ) | Developers.IO

非同期Lambda以外のアプローチ

API Gateway からイベントを SNS/SQS にプロキシーしても同様のことを実現できます。

  • Lambda 以外をワーカーに利用したい
  • Lambda の並列数制限が気になる
  • ファンアウトしたい

といったケースでは、メリット・デメリットを比較して適切なアプローチを選択してください。

最後に

Amazon API GatewayのREST APIから非同期にLambdaを呼び出すと、ジョブキュー的にイベントを処理できます。

昨年末に強化された非同期Lambdaのエラーハンドリング系機能は、API Gatewayと連携させても相性は抜群です。

参考