こちらは バイセルテクノロジーズ Advent Calendar 2021 の23日目の記事です。
前日の記事は今井さんの「GCP でのアクセス制限や IP 制限の話」でした。
こんにちは。テクノロジー戦略本部 開発1部の杉田です。
これまでは、
技術で遊んでみたり:フルリモートになったからSlack勤怠コマンドを作った - バイセル Tech Blog
新宿御苑でピクニックしてみたり:新宿御苑ピクニックのすゝめ - バイセル Tech Blog
してきましたが、今回は全力で反省をしたいと思います。
前提
まず前提として、私は現在BtoBオンラインオークションの開発運用に携わっています。(ヤフオクのようなものをイメージしていただければ分かりやすいかと思います。プロダクトの詳細については同じアドベントカレンダーの12月3日の記事で紹介されていますので、ご興味を持たれた方はそちらをご覧ください!)
このBtoBオークションの一機能として、去る10月に「LIVEオークション」というものがリリースされました。
「LIVEオークション」とは、オークショニアがLIVE配信をしながら商品の紹介や進行を行い、ユーザーはまるで対面オークションに参加しているかのようにオンラインで入札をすることができるオークションです。チャット機能を使って画面の中のオークショニアに質問することもできるので、細かい商品の状態などを確認することも可能です。
そしてこの機能のメイン開発を担当したのが私でした。
わりと大きめの施策で、期待も大きくPRが打たれたりもしました。
なにが起きたのか
そして迎えた記念すべきLIVEオークション初開催。あれは忘れもしない2021年10月8日の夕方。
この日までに死に物狂いで開発を進め、さんざんテスト環境でテストも行ってバグを潰してきた私は、準備万端でパソコンの前でLIVEの配信開始を待っていました。
ドキドキはしていたものの、正直、なにかあるとしたら、LIVE配信の遅延問題くらいだろうと思っていました。
時間になり、LIVE配信がスタート。オークショニアの司会進行により入札が始まります。
このLIVEオークションは技術的にはWebSocketを使用しており、オークショニア側の管理画面で「入札開始」とすると、ユーザー画面でもリアルタイムに入札ボタンが押せるようになる仕組みになっています。
しばらくLIVE配信を見ていると、違和感が襲ってきました。
動画の中のオークショニアは入札開始したつもりでいる口調だけど、私のユーザー画面では入札ボタンは disabled
のまま、押せるようになっていない。
この辺りから冷や汗が出てきました。
恐る恐るブラウザのconsoleを開いてみると...なんか赤い文字出てるーーー!!!
具体的な内容はショックのあまり忘れましたが、フロントエンドからWebSocketに接続できていないことを示すエラーが出ていました。
私の思考はしばらく停止しました。あんなにテストを繰り返したのに、なぜ...!?!?
なぜ起きたのか
結論から言うと、CORSの設定不備が原因でした。
フロントエンドからWebSocketへの接続を確立する際に、バックエンド側で接続元ドメインをホワイトリスト的に許可しているのですが、そこで設定しているドメインが正規表現で書かれており、サブドメインありきのドメインしか許可されていなかったのです。
自分でも書いていて「日本語でおk」と思いましたので、例を出してみます。
フロントエンドの本番ドメインが https://example.com
の場合、リリース前はサブドメインをつけた https://hoge.example.com
のようなテスト環境でテストを行うことが一般的だと思います。その際、バックエンド側のホワイトリストの設定が \Ahttps://.*\.example.com\z
という正規表現だと、 https://hoge.example.com
や https://fuga.example.com
のようにサブドメインがあるドメインしか許可されません。本番環境の https://example.com
はそれに当てはまらないのです。
この施策を開発中の時も https://hoge.example.com
のようなテスト環境でテストを繰り返していたため、そこでは完璧に動いていたのですが、一番動いてほしい本番でのみ、動かない設定がされてしまっていました。
反省ポイント
WebSocketはこの施策のために初めてこのプロジェクトに導入されました。設定がおかしかったのにレビューで気付けなかったことや、事前に気付ける仕組みを作れていなかったことはもちろん反省すべきところです。
ただ、一度障害が起きてしまったら、その時点で過去をどんなに嘆いて悔やんでも仕方ありません。今やるべきことは!調査して復旧!!のみ!!!
ということは理解しているのですが、この時はその対応も良くなかったという自責の念があるため、今回私が反省したいのは、その部分です。
この事件が起きた後、自分の中で整理した反省点が以下になります。
1. アプリケーションログをすぐに確認しなかった
一番ダメなパターン。
え!WebSocket繋がってない!え!フロントエンドからの接続の仕方が悪いのか!?え!?のような当てずっぽうな原因探りから入ってしまい、フロントエンドの実装に問題がないか確認したりしてしまいました。完全に時間の無駄です。
そもそもWebSocketに接続できていない=バックエンドに届いていない、という思考になってしまったのも一因だったと思います。
「とりあえずログを見ろ」というエンジニアとしての基本を忘れる大失態でした。
その後、ログからCORS周りが怪しそうなことが判明し、その部分を重点的に調査していきました。
2. 原因究明中、問題の部分のコードを一度は見たが、自分ではおかしいところに気付けずスルーしていた
目の付け所は良かったものの、テンパり過ぎて見落としたパターン。
他のエンジニアに協力を仰いで複数人で原因究明にあたっていたので、「今このファイルを見ている」等、とりあえず話題に出せば誰かがその時点で気付けて、もっと早く復旧できた可能性もあったと思います。(結局のところ完全復旧まで90分ほどかかった障害となってしまいました)
後から別のエンジニアが気付いてくれたことにより、復旧に繋がりました。
3. 他プロジェクトの教訓を活かせなかった
これも良くないパターン。
以前、「CORSのドメイン設定をミスっている」という点においてほぼ同じ失敗を別チームが別プロジェクトでしていた経緯がありました。私が直接的に関わっていたプロジェクトではなかったのですが、なんとなく障害情報を耳にはしていたので、「そういうこともあるんだなぁ」というくらいの認識はしていました。
今回の自分の失敗と、過去の別の失敗をすぐに頭の中で結びつけられなかったということは、他人の失敗を自分事として捉えられていなかったということなので、ここも反省ポイントです。
最近、弊社ではチームやプロジェクトをまたいだ障害情報の共有をするSlackチャンネルが新設されたので、今後は他人事と思わず注視していきたいと思っています。
終わりに
この事件が起きた直後はショックのあまり何も考えられず、浴びるようにお酒を飲んでいましたが、周りの方々の寛容な心&時間の経過のお陰で今はなんとか落ち着いて、年内に失敗談を供養することができて良かったです。
ご迷惑をおかけした関係者の皆様にはこの場をお借りして改めてお詫び申し上げます。
同じ過ちを繰り返さないよう、このブログを読んでくださった方にも是非この失敗を反面教師にしていただきたいです。
一方、今回の失敗は、プロジェクトで新しい挑戦をさせてもらえたからこそできた貴重な経験でもあります。「常に挑戦し続けよう」はバイセルの組織の理念のようなもので、仮に誰かが失敗をしたとしても、責めずにみんなで協力して問題解決に取り組む姿勢があり、とても成長できるありがたい環境だと実感しています。
前述の通り、弊社ではプロジェクトをまたいだ情報や知見の共有をできる仕組みも整ってきました。今回の学びや、他の人の経験も活かしながら、失敗を恐れ過ぎずに今後も頑張っていきたいと思います。
さて、弊社ではエンジニアを募集しています。
私のような失敗を犯しても暖かく見守って成長させてくれる優しい会社ですので、ご興味をお持ちいただけた方は是非、以下からコンタクトしてみてください。
明日の バイセルテクノロジーズ Advent Calendar 2021 は情報システム部の天野さんによる「1000人規模の会社でSlackを導入・運用してみた」です。
これまで我々テクノロジー戦略本部ではSlackの利用が当たり前だったものの、全社的には別サービスが公式のコミュニケーションツールでした。それが最近になって全社でSlackが導入されたのです。そのきっかけやその際の秘話が読めると思いますので、どうぞお楽しみに!