Cloud TasksとCloud Runを使って非同期処理を作る
Web APIの中に重めな処理があって、それを複数箇所で行いたい要件が出てきた。
このままでは体験が悪くなっていくというところで、その重めな処理を非同期に処理する方向性になった。
ここでCloud Tasksを利用することになったので備忘をまとめておく。
選定対象としてPubSubかCloud Tasksかというところだったが、今回は単純に非同期にしたいという要件なのでPubSubよりもCloud Tasksの方が適任と判断した。
理解を深めるためにサンプル実装を作っていく。
workerを用意する
非同期処理を行うworkerを用意する。
今回はCloud Runでエンドポイントを立てる形を取る。
echoでエンドポイントを作る。
Zennで見つけた簡単なechoのエンドポイントを作る記事を参考に実装。
サンプル実装はこんな感じ。
構成としてはcmd/worker.go
にechoで書いたエンドポイントを用意。
このエンドポイントDockerfileでコンテナイメージとして、Artifact Registryにpush。
Artifact Registryに配置されたコンテナイメージをCloud Runで起動する構成。
そしてルート直下のmain.go
にCloud Tasks呼び出し処理が書いてあり、実行するとCloud Tasksを通してCloud Runにリクエストが送信される。
Cloud Tasksへリクエストを送るための準備
Cloud Tasksのキューを作成
キュー名とリージョンを設定するくらいなのでシンプル。
Service Accountの作成
Cloud TasksからCloud Runにリクエストをdispatchするための権限を持ったService Accountが必要。
- Cloud Run サービス起動元
- Cloud Tasks タスク実行者
Cloud Tasksでタスクを実行する権限とCloud Runを起動する権限を付与。
Cloud RunではIAMでの認証をするように設定している。
Cloud Tasksの呼び出し処理
projectID := os.Getenv("PROJECT_ID")
locationID := os.Getenv("REGION")
queueID := os.Getenv("QUEUE_ID")
url := os.Getenv("ENDPOINT_URL")
parent := fmt.Sprintf("projects/%s/locations/%s/queues/%s", projectID, locationID, queueID)
requestBody := []byte(`{"message":"Hello, Cloud Tasks!"}`)
serviceAccountEmail := os.Getenv("SA_EMAIL")
req := &taskspb.CreateTaskRequest{
Parent: parent,
Task: &taskspb.Task{
MessageType: &taskspb.Task_HttpRequest{
HttpRequest: &taskspb.HttpRequest{
HttpMethod: taskspb.HttpMethod_POST,
Url: url,
Headers: map[string]string{"Content-Type": "application/json"},
Body: requestBody,
AuthorizationHeader: &taskspb.HttpRequest_OidcToken{
OidcToken: &taskspb.OidcToken{
ServiceAccountEmail: serviceAccountEmail,
Audience: url,
},
},
},
},
},
}
リクエストをかけるキューを指定する。
Cloud Tasksからリクエストを送るエンドポイントの情報も指定する。
IAM認証をしている場合はAuthorizationHeaderを設定してOIDC認証できるようにする。
SA_EMAILに入れているのはCloud Tasks用に作成したService Accountのメールアドレス。
雑だがここまでやってエンドポイント側でRequestBodyをログに吐き出させてみたが問題なく送れていた。
参考
Discussion