はじめに
この記事では、GitHub Actions 上で reviewdog/action-golangci-lint が reviewdog のダウンロード中に 504 を返して失敗したときの切り分けを整理します。
最初に結論を書くと、手元で確認できた事実は次の2点です。
- ワークフロー内に
MAINTENANCEという環境変数定義があると失敗した - その定義を外すと通った
ただし、これだけで「原因は環境変数名そのものだった」とは断定できません。この記事では、観測できた事実と、そこから立てられる仮説を分けて書きます。
何が起きたのか
失敗したのはアプリ本体のビルドや golangci-lint の実行ではなく、reviewdog を取得する段階でした。
ログは次のような内容です。
Run reviewdog/action-golangci-lint@f9bba13753278f6a73b27a56a3ffb1bfda90ed71
Installing Go ...
go env
:犬の顔: Installing reviewdog ... https://github.com/reviewdog/reviewdog
finding a release for latest
downloading from https://github.com/reviewdog/reviewdog/releases/download/v0.21.0/reviewdog_0.21.0_Linux_x86_64.tar.gz
Unexpected HTTP response: 504
Waiting 13 seconds before trying again
Unexpected HTTP response: 504
Waiting 12 seconds before trying again
Error: Error: Unexpected HTTP response: 504
ここから分かるのは次のことです。
- 失敗箇所は
reviewdogの取得処理 -
golangci-lintのルール違反ではない - Go コード自体のコンパイルエラーでもない
- 外部取得時の HTTP 504 が直接の失敗理由
つまり、まず疑うべきはアプリコードではなく、GitHub Actions 実行時の外部通信です。
最初に見た相関
ワークフロー定義に MAINTENANCE という環境変数がある状態では失敗し、それを消すと通る、という相関がありました。
例えばイメージとしては次のような差分です。
env:
MAINTENANCE: "true"
この定義があると失敗し、外すと reviewdog のダウンロードが通る、という挙動です。
ただし、ここで注意が必要です。
- 相関がある
- でも因果はまだ分からない
この2つは分けて考えた方が安全です。
ここで断定しない方がよい理由
「MAINTENANCE という名前が悪い」とすぐ言いたくなりますが、この時点ではまだ仮説です。
例えば次の可能性があります。
-
MAINTENANCE定義の追加と同時に、別の差分がたまたま一緒に入っていた - 外部通信の一時障害がたまたまその変更前後で起きていた
-
latest解決まわりの不安定さがたまたま重なった - 追加した環境変数の影響範囲が、想定より広かった
特に 504 は、相手先や途中経路のタイムアウトでも起きるので、アプリ設定だけで原因を断定しにくいです。
それでも環境変数を疑った理由
それでもワークフロー内の環境変数差分を疑う理由は、観測として次があったからです。
- ワークフローの失敗箇所が毎回ほぼ同じ
-
MAINTENANCE定義の有無で通過可否が変わった - アプリコードを変えていない
この状況では、少なくとも「コードのロジックが悪い」という説明はかなり弱いです。
むしろ、次のような切り分けの方が自然です。
- アプリの実装問題ではない
- CI 実行環境か外部通信まわりの問題である
- その中でワークフロー側の設定差分が影響している可能性がある
ありえる仮説
ここから先は仮説です。事実として断定はしません。
仮説1. ワークフローの環境差分が取得処理に影響した
今回の観測では、MAINTENANCE 定義の有無が成否と連動していました。
ただし、ここからすぐに「環境変数名そのものが特別な意味を持っていた」とは言えません。
可能性としては、次のようなものが考えられます。
- 環境変数を追加したタイミングで別の差分も混ざっていた
- 実行環境の条件がその前後で変わっていた
- 環境変数の追加が、想定していないスクリプトや設定参照に影響した
今回の観測だけでは、どれが当たっていたかは決められません。
仮説2. latest 解決や外部ダウンロードがたまたま不安定だった
ログを見ると、失敗は reviewdog の最新版解決とダウンロード中です。
finding a release for latest
downloading from https://github.com/reviewdog/reviewdog/releases/download/...
Unexpected HTTP response: 504
このため、単に次の可能性もあります。
- GitHub 側の一時的な応答不安定
- 通信経路上のタイムアウト
- アクション側のリトライでは吸収しきれない一時障害
この場合、MAINTENANCE 定義との関係は偶然だった可能性も残ります。
このケースでの考え方
この種の問題では、「真因を完全に証明する」より先に、「どこまでが観測事実か」を分ける方が大事です。
今回の観測事実は次のとおりです。
-
reviewdogのダウンロードで 504 が出た -
MAINTENANCE定義ありで失敗し、なしで通った - Go アプリ本体のロジック不具合を示す証拠はない
この時点で言えるのは次までです。
- コードのバグとして扱うのは不適切
- CI 実行環境または外部通信が怪しい
- ワークフローの設定差分は疑う価値がある
実務でやるとよい対処
真因を断定できない場合でも、再発しにくくする手はあります。
1. 環境変数名を一般名詞のまま使いすぎない
MAINTENANCE のような短く一般的な名前は、広い文脈で衝突しやすいです。
例えば次のようにプレフィックスを付けた方が安全です。
env:
APP_MAINTENANCE: "true"
これは「今回の原因が名前だった」と断定しているわけではなく、CI や運用全体で衝突しにくくする一般的な対策です。
2. 外部ツールのバージョンを固定する
今回のログでは latest 解決が入っています。
外部取得の不安定さを減らしたいなら、できるだけバージョン固定の方が扱いやすいです。
- uses: reviewdog/action-golangci-lint@v2
with:
reviewdog_version: v0.21.0
これで必ず直るとは言いません。実際には固定後も GitHub Releases からのダウンロードは続きます。
それでも、少なくとも「毎回 latest を探しに行く」不確定要素は減らせます。
3. 原因と回避策を分けて記録する
今回のようなケースでは、次の形で残しておくと後で助かります。
- 観測事実
- 立てた仮説
- 効いた回避策
- まだ未確定な点
これを混ぜると、「たまたま効いた回避策」が「確定原因」として社内で流通しやすくなります。
まとめ
今回の件で確実に言えるのは、Go のコードが悪かったわけではなく、GitHub Actions 上の reviewdog ダウンロードで 504 が出ていたことです。
また、MAINTENANCE という環境変数定義の有無と成否に相関がありました。
ただし、そこから
- 環境変数名が真因だった
- ネットワーク機器が誤判定した
- reviewdog 側の隠れた仕様だった
とまでは断定できません。
この種の問題では、原因を雑に言い切るより、次のように整理しておく方が実務的です。
- まず失敗箇所がコードか外部通信かを分ける
- 相関が見えた設定差分は仮説として扱う
- 変数名の見直しやバージョン固定で不確定要素を減らす
CI 障害は、コードの問題に見えて実際にはコード外に原因があることが珍しくありません。まずは「どこで失敗しているか」を冷静に切り分けるのが近道です。