LoginSignup
3
0

More than 1 year has passed since last update.

Amazon EventBridge API Destinationを使って外部API呼び出しを非同期的かつレートリミット内に収まるように行う(Slackで実装)

Last updated at Posted at 2022-12-24

この記事はPTAのアドベントカレンダー24日目の記事です。

概要

  • EventBridgeのAPI Destinationという機能を使うと、外部API呼び出しを非同期的に実行できる。
  • APIのレートリミット内に収まるように自動的に調整してくれる。
  • SlackのAPIで実験してみました。

EventBridge API Destinationとは

EventBridge API Destinationは、EventBridgeのターゲットにHTTP APIの呼び出しを指定できる機能です。

以下の特徴があります。

  1. 自動リトライ
  2. DLQにも対応
  3. 3種類の認証方式に対応
  4. APIのレートリミット内に収まるように自動的に調整

実装

全体像

今回は実験のために以下を実装します。
drawing

実装・設定するものは以下です。

  1. SlackのWebhook URLを取得
  2. EventBridgeのAPI Destination・接続を作成
  3. EventBridgeのイベントバスを作成
  4. EventBridgeのルールを作成
  5. EventBridgeのイベントを発行するコードを実装

SlackのWebhook URLを取得

こちらを参考にSlackのWebhook URLを取得します。

EventBridgeのAPI Destination・接続を作成

1. 接続を作成

drawing drawing

※今回はWebhook URLを使用するので認証は不要なのですが、必須なので適当に設定しました。ただ、本当はSlackアプリを作成してOAuth Tokenを取得し、認証を設定した方が良い気がします。

2. API Destinationを作成

API Destination(API 送信先)を作成します。

  • API 送信先エンドポイントの欄にWebhook URLを貼り付けてください。
  • SlackのIncoming webhooks APIのレートリミットは1秒に1リクエストまでなので、1秒あたりの呼び出しレート制限の欄に1と入力します。
drawing

EventBridgeのイベントバスを作成

スクリーンショット 2022-12-24 18.49.44.png

EventBridgeのルールを作成

  1. 上記で作成したイベントバスを指定し、ルールを作成
    スクリーンショット 2022-12-24 18.50.42.png

  2. イベントパターンは以下のようにします。
    スクリーンショット 2022-12-24 18.54.34.png

  3. ターゲットを設定します。

  • ターゲットタイプEventBridge APIの宛先を指定し、先程作成したAPI送信先を指定してください。

スクリーンショット 2022-12-24 19.03.02.png

  • ターゲット入力を設定一致したイベントの一部を選択肢、$.detailと入力します。

スクリーンショット 2022-12-24 19.03.18.png

EventBridgeのイベントを発行するコード

今回はGolangで実装しました。

package main

import (
	"encoding/json"

	"github.com/aws/aws-sdk-go/aws"
	"github.com/aws/aws-sdk-go/aws/session"
	"github.com/aws/aws-sdk-go/service/eventbridge"
)

type Payload struct {
	Text string `json:"text"`
}

func main() {
	payload := Payload{Text: "test-after"}
	p, err := json.Marshal(payload)
	if err != nil {
		panic(err)
	}

	sess, err := session.NewSession(&aws.Config{Region: aws.String("us-east-1")})
	if err != nil {
		panic(err)
	}

	e := eventbridge.New(sess)

	for i := 0; i < 200; i++ {
		_, err := e.PutEvents(&eventbridge.PutEventsInput{
			Entries: []*eventbridge.PutEventsRequestEntry{{
				EventBusName: aws.String("test"),
				Source:       aws.String("test.slack.post"),
				DetailType:   aws.String("detail"),
				Detail:       aws.String(string(p)),
			}},
		})
		if err != nil {
			panic(err)
		}
	}
}

実験

Before(SlackのWebhook URLを直接呼び出す)

比較のため、EventBridge API Destinationを経由せずSlackのWebhook URLに直接リクエストを大量に送ってみます。

package main

import (
	"encoding/json"
	"net/http"
	"net/url"
)

var hookURL = "" // NOTE: 今回は実験のためWebhook URLを変数に定義しましたが、危険なのでSecrets Managerなどに保管してください。

type Payload struct {
	Text string `json:"text"`
}

func main() {
	payload := Payload{Text: "test"}
	p, err := json.Marshal(payload)
	if err != nil {
		panic(err)
	}

	for i := 0; i < 200; i++ {
		resp, err := http.PostForm(hookURL, url.Values{"payload": {string(p)}})
		if err != nil {
			panic(err)
		}
		if resp.StatusCode != http.StatusOK {
			panic(resp.StatusCode)
		}

		err = resp.Body.Close()
		if err != nil {
			panic(err)
		}
	}
}

結果

レートリミットを超えるリクエストを大量に送信すると、以下のように警告文が表示された後しばらくして、429(Too Many Requests)レスポンスが返ってきます。1

drawing
panic: 429

After(EventBridge API Destinationを使って呼び出す)

結果

すべてのメッセージが投稿されました。
スクリーンショット 2022-12-24 18.42.55.png

まとめ

  • EventBridge API Destinationを使用することで、レートリミットを気にせずにAPIを呼び出せるようになりました。
  • 厳しいレートリミットを設けているAPIを利用する際などに活躍しそうです。
  • 一方で、ログが出力されない(自分が見つけられていないだけかも)ので、デバッグなどは難しくなる印象を受けました。

参考

  1. SlackのIncoming webhooks APIではレートリミットを超えた場合に短期間バーストします。その際にこのメッセージが表示されるようです。

3
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
0