Special Weekendってチームでダッシュボードっぽいやつを書いてました。バックエンドはGo、フロントエンドはReactで書いてました。今回は本当に問題にノータッチだった……
仕事ではHTMLやJS関係を全く触らないし、もっと言えばDockerもRDBも触らないという環境なので、ICFPCが唯一の触る環境だった感じもあります(社内にDockerじゃないコンテナフォーマットとか、Kubernetesの前身のコンテナオーケストレーションシステムとか、RDBの皮を被っているようでで被っていないDBMSなどがある)。チーム変わってからKubernetesとかAWSとかAzureを使い始めたので、そこらへんはわかってきた。
コンテスト前におさけーさんがReactとかMaterial UIとか使うと適当にUIが作れて便利〜って言っていたので、当日ぶっつけ本番でCreate React Appってやつをベースに適当に作りました。また、当日にぶっつけ本番でGKEを初めて使い、ほぼ初めてSQLiteとMySQLを使ってバックエンドを作ってました。使ったTech stackの中で、GoとKubernetesのジェネリックな部分だけがちゃんと知っているところだった気がする。
以下、記憶があるうちに箇条書きでどんなことをやったか:
- とりあえず問題を解く班と解かない班(解かない班とは)に別れて、解かない班は手動UIとダッシュボードを作る感じに。自分はダッシュボードをやる感じに。
- 最近はKubernetesを触っているし、GKEでいいやろって思って適当にGCP Projectを作ってGKE Autopilotでクラスタ作成。
- ご自宅に立ててるGoのサーバー向けに使ってたDockerfileをコピペして、Goが動くイメージを作ってデプロイ。マネージドKubernetes使ってるとServiceとかIngressあたりがうまく統合されていて、ロードバランサーとかも適当に作られて便利。
- あとGKEはCloud Consoleから適当にKubenetesオブジェクト見れることができて便利ですね。
- でもNetwork Endpoint Groupあたりのアタッチが遅い気がする……
- ここらへんはProberを適切に設定することで、改善した雰囲気もある。
- 作らない班でデータどうしようか話す。みんなして「データベースは持ちたくない……」って話をする。これが仇になってあとでMySQLへのマイグレーションをすることになる。
- 話の中ではGitをデータベースとして使えばいいんでは、ってなって最初はそういうコードを書こうと思ったけど、途中でやっぱそれも面倒くさくなってPersistent Volume + SQLiteという構成にした。
- Gitサーバーをやっていた身としてはGitをデータベースとして使うのは万死に値する行為だけど、使う側からすれば便利っぽく見えるよね……
- Gitサーバー側からすれば、たかだか一秒にN回(しかしフルでcloneされる場合もある)みたいな要件と、一秒に1000×N回(ただし1ファイルしか読まない)みたいなのが混在したトラフィックは超厳しいです……まぁ現実には1000×N回フルcloneが一秒間に同時に来て死ぬんですが。
- 雑にSQLiteでデータを保存するやつを、マニュアル見ながらせこせこ書く。DBファイルと問題と回答のファイルは適当にPVへ。
- git pushしたあとにgit fetchしたらGoのコードはきれいになっていて、ReactのコードはTypeScriptになっていた。すごい。
- git pushしたあとにgit fetchしたらビジュアライザが勝手についていた。すごい。
- KubernetesはSecretあたりの管理が楽でいいなぁと思う
- JavaScriptよくわからないなぁって話をした気がする。JavaとかGoはなんだかんだ言って仕様を読むと良いんだけど、JavaScriptはESの仕様を読むといいんだろうか、みたいな話をした。
- 回答のバリデーションとかDislikeの計算をサーバーサイドでしたいけど、そのコードはRustで書かれている…… 妥当なのはDockerfileでRustのバイナリをビルドするんだけど、どうせそんなに更新されないしな、と思ってバイナリをレポジトリに突っ込む。ギルティ。
- 公式サイトからMinimal dislikeをとってくるコードとかすでにsubmitされた回答をscrapeするコードをサーバーサイドに移植して定期的に走らせる。
- ここらへんがAPIとしてアクセス可能ではなくて厳しい。去年は一応すべてがAPIでアクセス可能だったので非常に良かった気がする。
- ダッシュボードから公式にsubmitできるようにする
- なんかデプロイするとダッシュボード(API)サーバーが一時的に落ちたりとかするのが厳しいという思いが出てくる。しかしデータベースがSQLiteだったり、PVがReadWriteOnceだったりしてレプリカ作るのは厳しい。そこにちょうどタスクキューシステムをCloud SQLで動かすということになったので、データをすべてCloud SQLのMySQLにマイグレーションするってことをやる。
- 泣きながらMySQLのドキュメントを読んでSQLを書く。
- 特に問題なくマイグレーション完了。ダウンタイム20分ぐらい。
- ついでにフロントエンドのデプロイとバックエンドのデプロイを分けたい、という思いから分ける。バックエンドはフロントエンドのassetサーバーのプロキシとして動作するようにして、フロントエンドのassetサーバー単体で更新できるようにする。
- まぁこれはAPIサーバーを最初から別ドメインで運用しておけばよかった気がする。
- ダッシュボードからタスクキューに投げるボタンをつける
- ダッシュボードが重すぎる
- なんかChromeのプロファイラすら動かない……と思ったらuseEffectの部分があれで無限ループになってる部分があった。
- それでも重いと思ったけど、ちゃんとWarningみてkeyをつけたら軽くなった。なんか想像するにReactの仮想DOM計算時にkeyをベースにして計算を省いている部分がある?
- あと、ダッシュボードが実質全回答をサーバーから取得するようになっていて厳しい。が、これは最後まで手をつけられず。まぁ数人しか使っていないサーバーだし……
以下、事後の感想:
- なんか今年はFPな雰囲気が弱かった……気もする。まぁ毎年問題はFPと関係ないようになってる気がするけど、どこかしらにFPっぽいなにかが散らばってたような気もする。
- JSONとかテキストで表現された問題郡に対して、色々JSONとかテキストで回答を提示し、それに対するメタデータ(点数とか)をつけてランキングをつくったりタグ付けしたり、というダッシュボード要件は変わらないんだから、パッとできるようになっておきたい。なっていたい……
- まぁそれはタスクキューもそうだね……
- もしかしたら雑にMongoとか使うとこういうときは楽なのかもしれない
- GKEとCloud SQLはよかった
- React便利だったけど、当日ぶっつけでコピペしながら使ったので、微妙にこれ使い方違ったなってところがあったりする。あとReduxとかでグローバルな状態をそっちに押し込んでおけば良かったみたいな気持ちもある。
- まぁでも1分ぐらいしか触ってない人でも、とりあえず見れるダッシュボードが作れる仕組みは良いですね。
- RDBを脳死で使えるようになったほうがいいなぁ、と思いつつ、仕事で使わないと微妙にモチベーションがわかんのだよな…… SpannerでQuery書くのそこまで推奨されてないし、Query書くのはDremel向けだし……
- あとSpannerはスキーマ定義だけすれば、あとは差分が自動で適用されていいなぁと思いました。まぁSpannerはSpannerで(というか地域分散する都合で)主キーの設計あたりで微妙に別プラクティスがある気がする(e.g. 番号が連続したキーを作らないとか)。
- まぁICFPCで普段使わないツールを使ったり、チーム変わって違うツール使ったりするけど、なんだかんだ言ってすぐ使えるようになれてるので、必要になったら学ぶでも普段は問題ない気がする。こういうコンテストみたいに「今すぐ必要」みたいなときに、やっときゃよかったって思う。
こうやって見返してみると、本当に問題にノータッチだったな。まぁ問題ノータッチでも参加して楽しめるってことで。