Go 1.15 で GAE 独自 API を利用できるのか？

:::note warn
2022 年 4 月 13 日に Go 1.12 以降の環境からの GAE 独自 API アクセスが GA になりました。
この記事の内容は古くなっているのでご注意ください。
:::

https://cloud.google.com/appengine/docs/standard/go/release-notes#April_13_2022

https://cloud.google.com/blog/ja/products/serverless/support-for-app-engine-services-in-second-generation-runtimes

https://cloud.google.com/appengine/docs/standard/go/services/access

~~2021 年 10 月 3 日時点では Preview 段階のためか `app.yaml` に `app_engine_apis: true` を追加しても `gcloud beta app deploy` を使わないと機能が有効化されないようです。~~

以下、 2021 年 7 月 29 日時点の情報になります。


---

GAE には便利な独自 API が用意されていたものの、第 2 世代と呼ばれる環境ではサポートされなくなってしまいました。 [^1] [^2]
このことは GAE/Go 利用者が Go 1.11 を使い続ける大きな理由だと思います。

しかし先日リリースされた [golang/appengine](https://github.com/golang/appengine) v2.0.0-rc2 で Go 1.12 以降がサポートされました。

https://github.com/golang/appengine/releases/tag/v2.0.0-rc2

> Clean up interfaces for legacy APIs that will be supported for Go 1.12+

まだ RC ですが Go 1.11 では動かないライブラリも増えている昨今ですので新しいバージョンの Go に移行できるというのはとても魅力的です。
そこで現在のバージョン (v1.6.7) とどのような違いがあるのか調べてみました。

なお、特に記載がない限り 2021 年 7 月 29 日時点の情報になります。

## 短い結論

Go 1.15 で GAE 独自 API は動きませんでした。

## サポート API の違い

リリースノートに記載されているとおりすべての API が利用できるわけではなく削除された API もあります。
次の表は大まかな差異を godoc および commit ログから抜き出したものと実際に試した結果 (一部) です。

繰り返しになりますが特に記載がない限り 2021 年 7 月 29 日時点の情報になります。

| パッケージ (v1.6.7) | v2.0.0-rc2 でのサポート | Go 1.15 環境で試した結果 |
| ------------------- | ----------------------- | ------------------------ |
| `appengine`         | 利用可能                | partial                  |
| `aetest`            | 利用可能                | OK                       |
| `blobstore`         | 利用可能                | -                        |
| `capability`        | 利用可能                | -                        |
| `channel`           | 削除                    | -                        |
| `cloudsql`          | 削除                    | -                        |
| `datastore`         | 利用可能                | -                        |
| `delay`             | 利用可能                | NG                       |
| `file`              | 削除                    | -                        |
| `image`             | 利用可能                | -                        |
| `log`               | 利用可能 (一部制限あり) | partial                  |
| `mail`              | 利用可能                | NG                       |
| `memcache`          | 利用可能                | NG                       |
| `module`            | 利用可能                | NG                       |
| `remote_api`        | 削除                    | -                        |
| `runtime`           | 利用可能                | NG                       |
| `search`            | 削除                    | -                        |
| `socket`            | 削除                    | -                        |
| `taskqueue`         | 利用可能                | NG                       |
| `urlfetch`          | 利用可能                | NG                       |
| `user`              | 利用可能                | OK                       |
| `xmpp`              | 削除                    | -                        |

## 実際に動かしてみる

一部のパッケージについて実際に Go 1.11 と Go 1.15 で動かしてみました。
(パッケージに含まれるすべての機能を試したわけではないのでご注意ください)

使用したコードは次のリポジトリに格納しています。

https://github.com/sg0hsmt/gae-go-compat-check

### 動かなかった API

多くの API は Go 1.15 で実行すると次のようなエラーが返ってきました。
どうやら GAE 独自 API へのアクセスを明示的に有効化する必要があるみたいです。

```
module hostname: Call error 7: App Engine APIs are not enabled, please add app_engine_apis: true to your app.yaml to enable.
```

よく見るとデプロイ時に次の警告が出力されていました。

```console
WARNING: There is a dependency on App Engine APIs, but they are not enabled in your app.yaml. Set the app_engine_apis property.
```

この設定については GAE/Python 3 用のライブラリ (Beta) に記載がありました。

https://github.com/GoogleCloudPlatform/appengine-python-standard

しかし `app.yaml` に `app_engine_apis: true` を追加しても `gcloud app deploy` では無視されて `gcloud beta app deploy` ではエラーになるため利用できませんでした。
現時点では利用制限がかけられており GAE/Go では利用できないようです。

```console
ERROR: (gcloud.beta.app.deploy) INVALID_ARGUMENT: version.app_engine_apis is not valid for runtime go115
- '@type': type.googleapis.com/google.rpc.BadRequest
  fieldViolations:
  - description: version.app_engine_apis is not valid for runtime go115
    field: version.app_engine_apis
```

### 動いた API

`appengine` パッケージのうち GAE 独自 API を必要とする関数は前述のとおり動きませんでしたが、環境変数を参照する形で実装されている関数 (主に IsXXX 系) は Go 1.15 でも正常に動作しました。

`aetest` パッケージは特に問題なくテストを実行できました。
(v1.6.7 の時点でも新しい Go で実行できていました)

`user` パッケージは内部的に GAE 固有の HTTP ヘッダーを参照しており、GAE 独自 API を使用していないため Go 1.15 でも正常に動作しました。

### 制限付きで動いた API

`log` パッケージはログ検索系の API が削除されたほかログ出力も GAE 独自 API を呼ぶのではなく構造化ログを標準出力するように変更されています。 [^3]
コードを見る限りではトレース ID も出力しているようなのですがログビュワーには表示されず、リクエストログとの紐づけもされなくなったようです。

- GAE/Go 1.11 (v1.6.7)
  ![go111_with_v1.6.7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38635/64e2e475-fa20-625e-1796-edc712d1ab0e.png)

- GAE/Go 1.11 (v2.0.0-rc2)
  ![go111_with_v2.0.0-rc2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38635/da712b6d-db3d-6df2-fa5c-29dc1a3da32d.png)

- GAE/Go 1.15 (v1.6.7)
  内部エラーになりログが残りませんでした。

  ```
  2021/07/04 10:01:12 internal.flushLog: Flush RPC: Call error 7: App Engine APIs are not enabled, please add app_engine_apis: true to your app.yaml to enable.
  ```

- GAE/Go 1.15 (v2.0.0-rc2)
  ![go115_with_v2.0.0-rc2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/38635/7cf11d3a-42d9-40ff-3fe4-4e881a11d132.png)

## その他

### login: admin 設定

Go 1.12 以降では非推奨になっていますが `app.yaml` の `login: admin` 指定は機能しているようです。

### App Engine to Cloud Run

`app_engine_apis: true` について調べている過程で GAE サービスを Cloud Run に変換するアンオフィシャルツールを見つけました。

https://github.com/GoogleCloudPlatform/app-engine-cloud-run-converter

コードを見たところ次のような警告出力が含まれていました。

- `runtime` が第 1 世代の環境を使用している場合は第 2 世代に移行するように警告する
- `app_engine_apis` が指定されている場合は Google Cloud client libraries に移行したうえで設定を削除するように警告する

### Google Cloud Buildpacks

GAE/Go をデプロイする時に裏で動く [buildpacks](https://github.com/GoogleCloudPlatform/buildpacks) のコードを調べてみました。
デプロイ時の警告メッセージは次の場所で定義されているようです。

https://github.com/GoogleCloudPlatform/buildpacks/blob/main/pkg/appengine/appengine.go#L31-L32

https://github.com/GoogleCloudPlatform/buildpacks/blob/main/cmd/go/appengine/main.go#L43-L65

## まとめ

残念ながら Go 1.15 で GAE 独自 API は動きませんでした。

将来的に app.yaml に設定を追加することで第 2 世代の環境から GAE 独自 API を利用可能にするのだと思いますが利用できなくなる機能も存在します。

特にログ出力周りはリクエストログとの紐づけが失われているので注意する必要がありそうです。

[^1]: https://cloud.google.com/appengine/docs/standard/runtimes
[^2]: https://cloud.google.com/appengine/docs/standard/go/go-differences
[^3]: https://cloud.google.com/appengine/docs/standard/go111/writing-application-logs#writing_structured_logs