📌

Cloud TasksとCloud Runを使って非同期処理を作る

2024/12/17に公開

Web APIの中に重めな処理があって、それを複数箇所で行いたい要件が出てきた。

このままでは体験が悪くなっていくというところで、その重めな処理を非同期に処理する方向性になった。
ここでCloud Tasksを利用することになったので備忘をまとめておく。

選定対象としてPubSubかCloud Tasksかというところだったが、今回は単純に非同期にしたいという要件なのでPubSubよりもCloud Tasksの方が適任と判断した。

理解を深めるためにサンプル実装を作っていく。

workerを用意する

非同期処理を行うworkerを用意する。
今回はCloud Runでエンドポイントを立てる形を取る。
echoでエンドポイントを作る。
Zennで見つけた簡単なechoのエンドポイントを作る記事を参考に実装。

サンプル実装はこんな感じ。
https://github.com/kimuray/cloud-tasks-sample

構成としてはcmd/worker.goにechoで書いたエンドポイントを用意。
このエンドポイントDockerfileでコンテナイメージとして、Artifact Registryにpush。
Artifact Registryに配置されたコンテナイメージをCloud Runで起動する構成。

そしてルート直下のmain.goにCloud Tasks呼び出し処理が書いてあり、実行するとCloud Tasksを通してCloud Runにリクエストが送信される。

Cloud Tasksへリクエストを送るための準備

Cloud Tasksのキューを作成

https://console.cloud.google.com/cloudtasks
キューを作成しておく。
キュー名とリージョンを設定するくらいなのでシンプル。

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をログに吐き出させてみたが問題なく送れていた。

参考

https://cloud.google.com/tasks/docs/dual-overview?hl=ja
https://zenn.dev/terurou/scraps/0953f4853c2c7c
https://zenn.dev/def_yuisato/articles/echo-get-started

Discussion