AtCoder Rivalsを支える技術
この記事はCompetitive Programming (1) Advent Calendar 2020の19日目の記事です。
私が作っているAtCoder RivalsというWebアプリについて紹介します。
AtCoder Rivalsとは
AtCoderのコンテストでのパフォーマンスやレート遷移、日々の精進などをライバルたちと比較し、モチベーション向上に繋げるためのアプリです。
AtCoderユーザーを検索&フォローすることで、そのユーザーの最近の提出とコンテスト成績を見ることができます。
最近の提出画面
コンテスト成績画面
ユーザーのフォロー画面
システム構成図
構成要素
・バックエンドとフロントエンド(Rails, ERB)
古き良きERBです。本当は記事投稿までにフロントエンドをNuxt.js、バックエンドをRailsのAPIモードに改修したかったのですが、全然間に合いませんでした😇 今年中には改修したいですね。
ただ、ページ数も少なくリッチなUIも求められていないのでこのままでも良い気もしています。
・スケジューラ(Rake)
Rakeタスクで以下を行っています。
・ユーザーの提出を一定間隔で取得
・コンテスト終了後に、順位やパフォーマンス、レート変動を取得
取得した情報をDBに保存し、上で貼ったのスクショのように表示しています。ユーザーの提出の取得は、kenkooooさんのSubmission APIを使っています。いつもありがとうございます🙇♂️
・キューイングシステム(Redis+Sidekiq)
上記のスケジューラによる定期実行時以外にも、ユーザー登録やユーザーフォローによって新規ユーザーがDBに保存された際に、そのユーザーのこれまでの提出とコンテスト結果を取得します。
このとき提出とコンテスト結果の取得完了までに時間がかかるので、Sidekiqに積んでバックグラウンドで実行するようにしています。これにより、ユーザー登録やフォロー時の待ち時間を減らすことができています。
インフラ
構成図からも分かるように、サーバーは全てHeroku上で動いています。Herokuは無料枠だけでもかなり色々とできるので、趣味アプリのデプロイ先にはおすすめです。AtCoder Rivalsで使っている機能やプランについて説明します。
・dyno→Freeプラン
dynoとはHerokuで使われる軽量なLinuxコンテナです。Freeプランの場合はweb dyno × 1、worker dyno × 1、one-off dyno × 1の3つのdynoを使うことができ、月あたり合計1000時間使うことができます。
ただ30分間アクセスが無いとアイドル状態になってしまい、立ち上がるのが遅くなります。AtCoder Rivalsにアクセスしたときに妙にレスポンスが遅いときは30分間誰も見てなかったんだなと思ってください。
それぞれのdynoは以下のように使っています。
・web dyno→webサーバー(Puma)用
・worker dyno→バックグラウンド処理(Sidekiq)用
・one-off dyno→スケジューラー(Rakeタスク)実行用
・Heroku Postgres→Hobby Basicプラン($9/month)
Postgresqlも無料で使えるHobby Devプランがあるのですが、10,000行までしか保存することができません。月$9の課金してHobby Basicプランにすると、10,000,000行まで保存できるようになります。ユーザーの提出を保存する関係上こちらのプランを使っています。が、さすがに全ユーザーの全ての提出を保存すると足りなそうなので、ユーザー登録 or フォローされたユーザーの提出のみを保存するようにしています。
・Heroku Scheduler→Standardプラン(無料)
one-off dynoでタスクを定期実行するためのアドオンです。個人向けには無料プランしか無さそうな感じでした。
・Heroku Redis→Hobby Devプラン(無料)
今はRedisを酷使するような実装になっていないので、無料プランで十分でした。「大量にフォローしても提出やコンテスト結果が問題なく表示できるようにRedisでキャッシュしておく」みたいなことをする場合は課金する必要がありそうですね。
・おまけ(Herokuへのデプロイ)
Herokuへのデプロイは、DockerfileをpushしてHeroku側でbuildする方式を使っています。(参考)
この方式だと、上述したdynoをこちらで準備したDockerfileから構築することができます。
まとめ
Herokuに支えられている