【Tips】TerraformでAPI Gatewayを構築しているときに出る ConflictException の回避手段


はじめに

Terraform で API Gateway を構築していて、メソッドや統合を多用していると、たまに

Error: error deleting API Gateway Integration Response (xxxx-xxxxxxxxxx-xxxxxx-PUT-500): ConflictException: Unable to complete operation due to concurrent modification. Please try again later.

みたいな感じでエラーが出て悩まされることがある。

これはおそらく、API Gateway を更新する API(Terraform が裏で叩いていると思われるもの)が、並列処理に対応していない(処理を排他している)と考えられる。
Terraform はお利口なので、依存関係のないリソースについてはなるべく並列で処理をして高速化をしてくれる。この仕様が仇になって、排他処理しているところに並列でAPIを叩きんでエラーになっているようだ。

対処策

その1: もう一度 terraform apply する

一番原始的な方法。別に HCL が悪いわけではないので、ConflictException が出ている限りは何度も apply すれば良い。でもこれ、他のエラーとか見落としてしまうとかありそうだよね……。

その2: Terraform の実行並列度を下げる

こんな感じ。

$ terraform destroy --parallelism=1

別に 1 多重まで落とす必要はないのかもしれないけど、冪等性を考えるなら絶対に処理が並列にならない 1 を指定すべき。リソースがいっぱいあるとめちゃくちゃ遅くなるので選択したくない案。

その3: 排他される処理については depends_on で順序性を持たせる

仕方がないので、aws_api_gateway_integration_response のように排他されるリソースについては、全部 depends_on で他の aws_api_gateway_integration_response の名前を書いて順序を持たせる。

resource "aws_api_gateway_integration_response" "example1" {
  depends_on = []
  (中略)
}

resource "aws_api_gateway_integration_response" "example2" {
  depends_on = [aws_api_gateway_integration_response.example1]
  (中略)
}

resource "aws_api_gateway_integration_response" "example3" {
  depends_on = [aws_api_gateway_integration_response.example2]
  (中略)
}

分かりにくい!

これ、後になって知らない人が見たら「なぜ関係のないリソースに依存関係を持たせるんだろう……」と思ってしまうよね。

結論

どの案もイマイチだったので、作っている人の好みに合わせれば良いのではないかと思う。
ただ、いずれも初めてこの問題にあたる人は悩むことになるだろうから、ちゃんとドキュメンテーションはしておいてあげよう(めちゃくちゃ悩んだ)。