Amazon EventBridgeのイベントソースをStripeにする

この記事はJP_Stripesアドベントカレンダーの記事です。 2019年のre:invent系列で発表されたサービスのひとつ、EventBridge。 これをStripeと連携させるサンプルプロジェクトがGitHubに […]

広告ここから
広告ここまで

目次

    この記事はJP_Stripesアドベントカレンダーの記事です。

    2019年のre:invent系列で発表されたサービスのひとつ、EventBridge。

    これをStripeと連携させるサンプルプロジェクトがGitHubにありましたので、さっそく試してみました。

    セットアップ

    Serverless Frameworkのセットアップ

    まずはデプロイに使うServerless Frameworkをインストールします。

    $ npm i -g serverless

    ちなみにここで使うプロジェクトは、version 1.54.0 ~ 2.0.0の間である必要があります。古いバージョンを使われている方はアップデートしておきましょう。

    プロジェクトのダウンロード

    プロジェクト一式をGitHubから持ってきます。

    $ git clone https://github.com/rangle/stripe-eventbridge.git
    $ cd stripe-eventbridge

    依存スタックの作成

    SNSとSecret Managerのリソースを作成するためのスタックをまず起動します。

    $ cd stacks
    $ pwd
    /path/to/stripe-eventbridge/stacks
    
    $ sls deploy
    
    Service Information
    service: stripe-eventbridge-deps
    stage: dev
    region: us-east-1
    stack: stripe-eventbridge-deps-dev
    resources: 4
    api keys:
      None
    endpoints:
      None
    functions:
      None
    layers:
      None

    このように出力されればOKです。

    メインスタックの作成

    続いてStripeからのWebhookをEventBridgeに流すAPIをデプロイします。

    $ cd ../
    $ pwd
    /path/to/stripe-eventbridge
    
    $ npm install
    
    $ sls deploy
    Service Information
    service: stripe-eventbridge
    stage: dev
    region: us-east-1
    stack: stripe-eventbridge-dev
    resources: 16
    api keys:
      None
    endpoints:
      POST - https://xxxxxx.execute-api.us-east-1.amazonaws.com/dev/stripe/webhook
    functions:
      stripe-webhook: stripe-eventbridge-dev-stripe-webhook
    layers:
      None
    Serverless: Run the "serverless" command to setup monitoring, troubleshooting and testing.

    APIのURLをコピーしておきましょう。

    StripeダッシュボードでWebhookを設定

    StripeのWebhookを設定します。先ほど作成したスタックのAPIをエンドポイントに指定します。

    今回はこのような形で設定しました。

    署名シークレットを取得

    Secret Managerに登録するシークレットを取得します。

    作成したwebhookの詳細画面から署名シークレットが取得できますので、取得しましょう。

    Secret Managerに署名シークレットを登録

    AWSのSecret Managerに取得したシークレットを登録します。すでに「stripe-webhook-endpoint-secret」というシークレットが発行されていますので、ここに追加しましょう。

    [シークレットの値を設定する]から追加できます。

    プレーンテキストで追加します。

    ここまででEventBridgeにイベントを送る部分を実装しました。

    イベントを受け取るLambdaを作る

    ここからはEventBridgeからきたイベントを処理するLambdaを作ります。

    Serverless Frameworkでさくっと作成したもの

    動かすコードはひとまずシンプルなこちらにします。

    $ vim index.js
    module.exports.eventSubscriber = async (event) => {
      console.log(JSON.stringify(event))
      return {
        message: 'Hello World',
        event
      }
    }

    yamlでのLambda定義はこちら

    functions:
      event-subscriber:
        handler: handler.eventSubscriber
        events:
          - eventBridge:
              pattern:
                source:
                  - Stripe
                detail-type:
                  - payment_intent.succeeded
                  - customer.created
                  - charge.succeeded

    これでデプロイすると、EventBridgeのセットアップ完了です。

    ルールを見てみる

    EventBridgeのイベント> ルールから作成されたルールを確認できます。

    YAMLで書いた内容そのままできていますね。

    動かしてみる

    さっそく動かしてみましょう。

    customer.createdイベントをsubscribeさせているので、これをまず使ってみます。

    CloudWatchのメトリクスをみると、実行されていることがわかります。

    Subscriber側のCloudWatch Logsをみると、StripeのWebhookから送られてきた値が確認できます。

    {
      "version": "0",
      "id": "d605ab01-0929-3611-e8a6-274e47638db3",
      "detail-type": "customer.created",
      "source": "Stripe",
      "account": "372284591230",
      "time": "2019-12-13T10:36:34Z",
      "region": "us-east-1",
      "resources": [],
      "detail": {
        "id": "evt_1FpB24DHnG67uihbAp2ahwld",
        "object": "event",
        "api_version": "2019-02-11",
        "created": 1576231560,
        "data": {
          "object": {
            "id": "cus_GLsnjVzuUF4zhQ",
            ...
        },
        "livemode": false,
        "pending_webhooks": 1,
        "request": {
          "id": "req_4N2kWCRsmCdhc8",
          "idempotency_key": "039455f2-3367-46b5-b2dc-dead83ee78dd"
        },
        "type": "customer.created"
      }
    }

    detailの中がStripeからの値ですね。

    実装チラ見

    ざっとソースを見た所、肝はlib/eventBridge.jsの様子です。

    
    const AWS = require('aws-sdk');
    const { promisify } = require('util');
    
    const eventbridge = new AWS.EventBridge();
    eventbridge.shipIt = promisify(eventbridge.putEvents)
    
    module.exports = {
        sendToEventBridge : async (bridgeName, event) => {
            const {id, type} = event
        
            console.log(`Sending event ${id} of type ${type} to the ${bridgeName} event bus on AWS EventBridge`)
            const params = {
                Entries: [
                  {
                    Detail: JSON.stringify(event),
                    DetailType: type,
                    EventBusName: 'default', //bridgeName,
                    Resources: [],
                    Source: 'Stripe',
                    Time: new Date()
                  },
                ]
            };
    
            await eventbridge.shipIt(params);
        }
    }

    Sourceにオリジナルなキーを指定し、DetailにString化した形でデータを投げつけています。EventBusNameやResourcesあたりがちょっと不明なので、この辺りは続けて調査かなと思います。

    使い所など

    EventBridgeにshipItでデータを投げ込むことで、EventBridgeに設定されたルールに基づいてAWS上で複数の処理を動かすことができます。

    ですのでStripeであれば、Stripe上のイベントをShipItして、後続のLambdaがCRMへの連携や社内通知などの処理を行うということができるようになります。

    問題点としては、StripeのWebhook自体はEventbridgeに投げ込むだけになるために、そこでエラーを検知することが難しくなります。

    今回のサンプルでもSNSを使うようにしていますが、subscribeする側の異常を検知できるように設定してやる必要があります。

    Serverless Frameworkを使うか否か

    これは個人的な意見ですが、ちょっとEventBridgeを使い込むには難しいかなと思います。

    というのも、Serverless Frameworkの書き方ではLambdaに対してEventBridgeを割り当てて作成する「1:1」のイメージです。が、EventBridgeの使い方としてはEvenrBridgeに対してLambdaを割り当てる「1:多」の構図になります。

    複数のイベントをsubscribeさせたいということを考えると、EventBridgeはEventBridgeで管理して、そこにLambdaなどのリソースをARNなどで登録していく形がよいかなと思います。

    広告ここから
    広告ここまで
    Home
    Search
    Bookmark