Cloud SchedulerでCloud Functions gen2を定期実行する

- Cloud Scheduler + Cloud Functionsの構成で、Cloud Functionsを定期実行できます。
- 第2世代のCloud Functions (gen2) を使います。
- CDK for Terraformを使用します。

# サービスの構成

![architecture.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1950110/9bf0ef00-c9be-fbb2-f005-b820760417c5.png)

- Cloud SchedulerがCloud FunctionsのHTTPエンドポイントに定期的にアクセスします。

# Cloud Functionsのコード

Functions Framework, HTTP用のサンプルほぼそのままです。

https://github.com/GoogleCloudPlatform/functions-framework-go#http-functions

```go
package function

import (
	"log"
	"net/http"

	"github.com/GoogleCloudPlatform/functions-framework-go/functions"
)

func init() {
	functions.HTTP("HelloWorld", helloWorld)
}

func helloWorld(w http.ResponseWriter, r *http.Request) {
	log.Print("begin")
	w.Write([]byte("Hello, World!"))
	log.Print("end")
}
```

# CDK for Terraform

Cloud Functions, Cloud Scheduler部分のみ抜粋します。
全体は[GitHub](https://github.com/hsmtkk/symmetrical-spork)を参照してください。

## Cloud Functionsを構成する箇所抜粋

```typescript
    const exampleFunction = new google.cloudfunctions2Function.Cloudfunctions2Function(this, 'exampleFunction', {
        buildConfig: {
            entryPoint: 'HelloWorld',
            runtime: 'go120',
            source: {
                storageSource: {
                    bucket: assetBucket.name,
                    object: assetObject.name,
                },
            },
        },
        location: region,
        name: 'example-function',
        serviceConfig: {
            serviceAccountEmail: functionRunner.email,
        },
    });
```

## Cloud Schedulerを構成する箇所抜粋

- `<Cloud Functions>.serviceConfig.uri` でCloud FunctionsのURLを参照できます。

```typescript
    new google.cloudSchedulerJob.CloudSchedulerJob(this, 'scheduler', {
        name: 'schedule',
        region,
        httpTarget: {
            oidcToken: {
                serviceAccountEmail: schedulerRunner.email,
            },
            uri: exampleFunction.serviceConfig.uri,
        },
        schedule: '* * * * *',
    });
```

### Cloud Functionsの認証

- Cloud Functionsには認証がかかっているので、何も工夫をしないとCloud SchedulerからCloud Functionsの呼び出しは失敗します。
- 認証のため、サービスアカウントを作成、サービスアカウントに `roles/run.invoker` (※)を付与、Open ID Connectトークンを付与、という構成にしてあります。
- (※)Cloud Functions gen2のため。gen1の場合は `roles/functions.invoker` になります。

https://cloud.google.com/functions/docs/securing/authenticating?hl=ja#authenticating_function_to_function_calls

- 以下失敗時のログ、PERMISSION_DENINEDと出力されています。

```
{
  "insertId": "4qda07f6rtitd",
  "jsonPayload": {
    "targetType": "HTTP",
    "@type": "type.googleapis.com/google.cloud.scheduler.logging.AttemptFinished",
    "url": "https://example-function-rcrphj3eqa-uc.a.run.app/",
    "jobName": "projects/symmetrical-spork/locations/us-central1/jobs/schedule",
    "status": "PERMISSION_DENIED"
  },
  "httpRequest": {
    "status": 403
  },
  "resource": {
    "type": "cloud_scheduler_job",
    "labels": {
      "project_id": "symmetrical-spork",
      "job_id": "schedule",
      "location": "us-central1"
    }
  },
  "timestamp": "2023-03-13T01:27:00.827233932Z",
  "severity": "ERROR",
  "logName": "projects/symmetrical-spork/logs/cloudscheduler.googleapis.com%2Fexecutions",
  "receiveTimestamp": "2023-03-13T01:27:00.827233932Z"
}
```

# 実行結果

## Cloud Schedulerの画面、ログ

![scheduler0.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1950110/a19cc2fd-6661-3654-7721-1b6ed76a8493.png)

```
{
  "insertId": "epocfhf6sjz2x",
  "jsonPayload": {
    "targetType": "HTTP",
    "jobName": "projects/symmetrical-spork/locations/us-central1/jobs/schedule",
    "url": "https://example-function-rcrphj3eqa-uc.a.run.app/",
    "@type": "type.googleapis.com/google.cloud.scheduler.logging.AttemptFinished"
  },
  "httpRequest": {
    "status": 200
  },
  "resource": {
    "type": "cloud_scheduler_job",
    "labels": {
      "project_id": "symmetrical-spork",
      "location": "us-central1",
      "job_id": "schedule"
    }
  },
  "timestamp": "2023-03-13T01:38:00.296884186Z",
  "severity": "INFO",
  "logName": "projects/symmetrical-spork/logs/cloudscheduler.googleapis.com%2Fexecutions",
  "receiveTimestamp": "2023-03-13T01:38:00.296884186Z"
}
```

## Cloud Functionsのログ

- 1分間隔で実行されています。

![functions.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1950110/f5ca6028-b9ad-b2be-dd70-39d3ba9a147d.png)

# ソースコード全体
https://github.com/hsmtkk/symmetrical-spork