minifyされたjavascriptはAIに読ませよ〜Google製品のバグと戦う〜
前置き
仕事で一番楽しい瞬間は何ですか?
私は障害対応が一番楽しいです。
俺が最強だ。誰にも負けねぇ。と感じられるからです。
しかし、最近は以前と障害対応のやり方が変わってきたな。効率が格段に良くなったなと感じています。AIのおかげです。
以前は自分が書いていないクソ複雑怪奇なコードを時間をかけて読んだり、フロントエンドであればブラウザの開発者ツールからminifyされたスクリプトを落としてきて何時間もかけて解読したりとかすることもありました。(今でもたまにやりますが)
しかし、最近は大部分をAIに任せられるようになってきました。
本記事は、突然発生した弊社ECサイトのフリーズという大事故に対し、サードパーティー(Google Tag Manager、以下GTM)のminifyされたスクリプトのバグに対してCopilotを活用して原因を突き止め、GoogleさんにGTMのバグを修正してもらうまでの話です。
Google大好き。めっちゃ大好きです。
超大手のプラットフォーマーの製品のバグに対して、日系企業のしがない一般エンジニアがCopilotの助手席に乗って立ち向かう話として書いているので他意はございません。
改めて言いますがGoogle大好きです。日頃からお世話になっております。いつもありがとうございます。
ある日、弊社ECサイトがフリーズする事象が発生
何気なく弊社ECサイトを閲覧していると突然画面がフリーズしました。
しかし、毎回フリーズするわけではありません。
体感で7割〜8割ほどの確率でフリーズします。
しかも、Googleの広告経由でアクセスしたときにだけフリーズします。
社内の第一発見者は恐らく私です。
ひとまず落ち着いてチャットで報告します。
やばい、なんか、めっちゃ画面フリーズする!!!
とりあえず報告が完了したので事象の整理をします。以下のような特徴があることを確認できました。
- Google広告経由でアクセスしたときのみフリーズする。
- 発生する商品と発生しない商品がある
- 毎回ではなく、体感で7割〜8割ほどの確率で発生する。
GTMに問題があることを特定
全く完全にフリーズ、タブを閉じる以外の一切の操作を受け付けなくなるので、おそらくどこかで無限ループに陥っているのだろうと勘が働きました。
フリーズ中に開発者ツールで実行中のjavascriptを一時停止すると、GTMのスクリプト内で無限ループが発生していることを特定しました。(というか、javascriptで無限ループを発生させるとここまで悲惨な挙動になるんですね)
ブラウザが完全に反応しなくなり、タブを閉じる以外の操作を受け付けない状態だったため、おそらくどこかで無限ループに陥っているのだろうと勘が働きました。
Chromeの開発者ツールで実行中のJavaScriptを一時停止したところ、Google Tag Manager(GTM)のスクリプト内で無限ループが発生していることを特定しました。
誰も「何もしていない」らしいので調査開始
まずは社内独自で設定しているスクリプトが悪さをしているのではないかと疑い、聞き込み調査を開始しました。大体こういうときは自分たちが悪いものです。ライブラリやフレームワークを疑うのは最後です。それでも大抵自分達が悪いものです。多くの場合。
社内に誰か心当たりがある人がいて、サクッと解消するかと楽観視していたのですが、どうやら誰も「何もしていない」のにサイトが壊れたらしいです。
とはいえ、他社サイトが軒並み壊れているという話も聞きません。Google検索だけでなくXなどのSNSもフル活用です。
やはり自社で設定したカスタムのスクリプトが原因だろうと考え、GTMのコードを解読することにしました。
問題は、そのコードがminifyされており、解読するのが非常に難しいことです(時間をかければ読めなくはないですが。。。)
さらに、別の部署でGTMを管理しているので、私はGTMの管理者権限すら持っていません。
やはり、ブラウザから取得できるminifyされたスクリプトを読み解くしかないでしょう。。。
開発者ツールでブレークポイントを張り、スタックトレースを追いかけて処理フローを整理した結果、以下のことが判明しました。
- 弊社が独自に設定しているクエリパラメータが、なぜかBase64デコードされる(Base64エンコードしていないのに)
- その結果、意味不明な配列が生成される
- その配列に対して何らかのハッシュ値の計算を行おうとした結果、無限ループが発生している
社内の運用メンバーがわざわざこんな複雑な処理を仕込むとは思えず、ここで初めて「これはGTM本体のバグではないか?」という疑念が生じました。
検証のため他社サイトのGTMを確認したところ、無限ループを引き起こしている箇所と同じコードが他社サイトにも存在するではないですか。
さらに、弊社独自のクエリパラメータを付与して他社サイトにアクセスし、何度かリロードしたところ、実際に他社サイトでもフリーズが発生します。
フリーズする確率が弊社サイトよりずっと低いのが気掛かりですが、フリーズする以上は「GTM自体にバグがある」がある可能性が高そうです。
仕事なのでサイトの復旧を最優先
原因をさらに深掘りしたい気持ちもありましたが、広告経由のお客様のブラウザをフリーズさせてしまう状況を解消するのが最優先です。これ以上に優先しなくてはならないことは多くはないでしょう。
普段、GTMなんて触らない(管理者権限を持っていないことからも明らかです)ので色々と疑問が浮かんできます。聞き込みと検証を進めていきます。
Q: 独自パラメータはどこで設定している?
• A: Google広告の管理画面で設定。Google広告経由でアクセスした時のみ設定される。一般的な運用であり、数年前から変更していない。
Q: パラメータを削除できるか?
A: 社内のレポートツールなどに必要だが、背に腹は代えられない。ただし設定箇所が数百あり、削除には時間がかかる。
Q: 問題のクエリパラメータが不当にBase64デコードされた結果としてフリーズするのであれば、GTMが読み込まれる前にBase64エンコードすれば良い?
A: 開発者ツールでスクリプトを書き換えるなどの涙ぐましい努力でフリーズしなくなることを確認。
Q:誰に連絡すれば良い?
A:Google広告の営業担当に聞くのが良さそう。
では、システム全体でどう対応するか?
弊社のフロントシステムはたくさんある(たくさんありすぎる)ので、全てのシステムで対応するのに一体何日かかるかわかったものではありません。
しかし、妙案を思いつきました。
聞き込みの結果、弊社は歴史的経緯でAdobe Analytics経由でGTMを読み込んでいるようです。
ならば、Adobe AnalyticsのカスタムスクリプトでクエリパラメータをBase64エンコードする処理をGTMの実行前に差し込めば、全システムを改修せずに済むのではないかと。
Adobe Analyticsの運用担当者に情報を連携し、どういうスクリプトをどのタイミングで実行するようにしてほしいか伝えて、実際にやってみたところ、期待通りにフリーズしなくなることを確認できました!
これでお客様影響はなくなったかと思います。
Googleの営業担当に連絡してみる
暫定対応は終わりましたが、GTMの不具合に対処するための不自然なカスタムスクリプトは残ったままですし、
社内で利用しているレポートツールもこの暫定対応のせいで壊れているようです。
何より、弊社も数日で数百万規模の被害を受けているようです。非は認めてもらったほうが良いでしょう。その後にどうするかは偉い人に任せます。
また、他にも同様の被害を受けている企業もあるかもしれません。世のため人のためにもGTMを修正してもらいましょう。
Google広告の営業担当者に無限ループ箇所のスクリーンショットと、発生条件、他社サイトでもクエリパラメータを付加すると再現する旨を伝え、調査を依頼しました。
しかしというか、当然と言いますか「御社側の問題ではないですか?(要約)」となかなかGTMのバグと信じてもらえません。
メールを数回重ねても、なかなか不具合として認めてもらえないので、Copilotと協力してスクリプトをさらに深掘りして、Google側にどういった修正をして欲しいのか明確化することにしました。(Base64デコードやめてとは既に伝えてい
ますが)
Google側が実施しているA/Bテストが原因で、発生確率が「1 - 0.9^(GTMスクリプトを読み込んだ回数)」であることを特定
フリーズを引き起こす無限ループに突入するためのif文が確率的に分岐していることは特定できていましたが、なぜそうなるのかが不明でした。
Copilotに「この分岐が実行される条件を調査して」と指示し、
何度もやり取りを重ね、開発者ツールで得た設定値などを追加情報として提供した結果、Google側で実施しているA/Bテストが原因であることを突き止めました。
フリーズするB面に振り分けられる確率が10%であり、弊社のサイトは(構造上の課題で)GTMが1ページで十数回 回も読み込まれていたため、約7割という高い確率でフリーズが発生していたのです。
また、他社サイトに問題のクエリパラメータを付与しても弊社サイトと比較して低確率で発生することの説明にもなっています。
開発者ツールでスクリプトを上書きし、A面を100%にしてみたところ発生しなくなることを確認できました。
Googleには一先ずはこのA/Bテストを中止して貰えば良さそうです。
ちなみにですが、調査のためにGTMスクリプトを1つしか読み込まないようにネットワークをブロックした上で調査したので、10%の確率でしか発生しなくなり、かなり難航しました。
ここが一番難しかったです。
Claude Sonnet 4.0が無ければ一生かかっても読み解けなかった自信があります。
ループ処理の正体は「LEB128」だと特定
無限ループを引き起こしていた「ハッシュ化のような処理」についてAIに尋ねたところ、LEB128という文字列を圧縮するアルゴリズムであることを教えてくれました。
さらに「Google製品でよく使われるのか?」と聞くと、「Protocol Buffers等で使われている」との回答。
調査を進めると、プロトコルバッファーのコードでは存在するLEB128の処理において不正な入力に対して無限ループを回避するためのハンドリングが、GTMには含まれていないことが分かりました。
さらに、copilotに頼んで「ある入力に対して、無限ループが発生することを確認するための簡単なCLIスクリプト」を組んでもらいました。
こういう小さな検証用のスクリプトをサクッと組んでくれるのもAIの良いところですね。検証のサイクルが爆上がりしてます。
色々な入力を検証したところ、弊社がクエリパラメータにつけているプレフィックスが運悪く無限ループを引き起こしているようです。
他社サイトがカスタムで追加しているクエリパラメータでは再現しません。
これで弊社サイトだけがフリーズしていることへの説明にもなっています。
ここまで外堀を埋めれば流石にわかってくれるでしょう。
原因を突き止めて再度連絡してみる
ここまで詳細なエビデンスを揃え、「エンジニアに伝えればすぐ理解できるはずだ」と強く伝えたところ、やっとわかってもらえました。
割とすぐに、Google側はそのA/Bテストを停止してくれました。
総括
今回の件で感じたのは、エンジニアの役割の変化です。
AIはまだ、社内の聞き込み調査や、人間関係の調整、開発者ツールを駆使した現場のコンテキスト収集を完結させることはできません。
しかし、minifyされたJavaScriptを解読するような「職人芸」的な作業は、AIの得意分野になりつつあります。我々エンジニアは、AIが最高のパフォーマンスを出せるように「正しいコンテキスト」を集めて提供したり、人間関係等の調整をしたり、そんな働き方にシフトしていくのだと予感がします。
ついでに
実はもう一つ話があります。時期的にはAdobe Analyticsでなんやかんやワークアラウンドをしてから、Googleに認めてもらうまでの期間です。
お盆に妻の実家に帰省したときです。場所は四国です。
「あれ、直したはずのフリーズが再発している……?」
また愛用の開発者ツールを開いてブレークポイントをたくさん置きます。
どうやらGTMより先に実行されるはずのAdobe Analyticsに仕込んだクエリパラメータをBase64エンコードするスクリプトがGTMより後に実行されている。。。。
都内では「Adobe Analytics(回避策) → GTM(本体)」の順で実行されていたのに、四国ではGTMが先に実行されていたのです。
おそらく、都内であればスクリプトの記述の順序が早いAdobe Analyticsの方のスクリプトが先に読み込まれて実行されていたのでしょう。
しかし、きっとGoogleさんは四国にもエッジサーバーを置いているのでしょう、何か凄く効率的にスクリプトを配信しているのでしょう。
それに対してAdobeは東京とかに置いているんでしょうね。
スクリプトのダウンロード時間によって実行順序が逆転してしまっていたのです。
ここまでわかれば後は実行順序を固定するだけです。
しかし、正攻法としてAdobeのドキュメントを探し漁ってもChatGPTに聞いてもまるでわかりません。
仕方がないので、GTMと同じようにAdobe Anayitcsのコードを開発者ツールからエディターにコピー&ペーストして「ここのコードをそのコードより先に実行したい。どうすれば良いか検討して。ちなみにこれはAdobe Analyticsの配信しているコードです。」と質問して、いつものように不足しているコンテキストを開発者ツールを使って補ってあげると、Adobeのドキュメント化されていない挙動を探しあてて、設定項目をゴニョゴニョすると実行順序を固定できると教えてくれました。(実際にここに至るまでに涙なしには語れない苦労もあります)
本来であればドキュメント化されていない仕様の使用は避けたいでしょうが、今は一刻も早くフリーズを止めることが求められているので動けば良かろうなのだ。100点満点の回答をありがとう。
やはり、minifyされたjavascriptを人間が読む時代は終わったのかもしれません。
私の仕事が1つAIに奪われたのを実感しました。
Discussion