各ユーザーの個別のレーティングとグループを更新する定期的なジョブを実行する(Codeforces API への外部リクエストが多数発生します)
大会が発生するたびに処理する定期的なジョブを実行する。レーティングは大会中にのみ変更されるため、ユーザーのレーティングが初期状態で一貫していれば、変更をリアルタイムに処理することで、変更されたレーティングのみを更新し、単一の外部 API 呼び出しで一貫性を維持できます
カスタムのレーティングとグループ解決機能を実装する。つまり、最後のレーティング取得時刻を保存し、次の GET rating/groups 呼び出しでレーティングが古くなっていれば、Codeforces API を叩いてユーザーのレーティングとグループを更新します。これは私の希望する解決策です。実装が簡単で、最終的には常に一貫性が保たれるように思えるからです。ただし、動的にユーザーからグループを削除したり追加したりする方法や、その影響について確信が持てません。あるいは、これがプラグインとして可能なのかどうかも不明です。
user_custom_field に Codeforces のハンドルが格納されていれば、ログイン時にプロフィールから必要な情報を更新するのは比較的簡単です(グループの割り当て、Codeforces のプロフィールデータを user custom fields に格納するなど)。
以下のような実装が可能です:
after_initialize do
DiscourseEvent.on(:user_logged_in) do |user|
# Codeforces からデータを取得
if codeforce_rating > 1400
group = Group.find_by(name: group_1400)
if group
gu = GroupUser.find_by(group_id: group.id, user_id: user.id)
GroupUser.create(group_id: group.id, user_id: user.id) unless gu
end
end
end
end
これはソース側から行うべきです。つまり、Codeforces でレーティングの変更が検知された時点で、Discourse に対して API リクエストを送信し、レーティング(またはそのレーティングに影響される他のユーザープロパティ)を更新させます。これにより、常に最新の状態を維持できます。同期が必要な場合、ポーリングは必ず何らかの問題を引き起こすため、可能な限り回避し、イベントベースのアプローチを採用してください。