Closed junohm410 closed 4 months ago
https://odentakashi.github.io/2023/10/01/post6.html
締め切りを過ぎた後の抽選をどのように行うか このサービスにおける重要な機能の一つに、抽選会の主催者が設定した締め切りを過ぎた後に抽選を行うというものがあります。 この処理は、締切日の翌日01:00時に定期的に実行されます。 この定期実行を実現するために、cronを使用して、Rakeタスクを実行しています。
最初は、この処理を実行するためにActiveJob+Redis+Sidekiqを検討していましたが、 アドバイスを受けて、このツールは非同期処理のためのものであり、特定の日時に実行することには向いていないと判断しました。 またUNIX系サーバーにおいてはcronを使用するのが一般的ということもアドバイスいただきました。
したがって、非同期処理から定期処理へのアプローチを採用し、締切後に抽選を行うためのRakeタスクを作成しました。 そして、このRakeタスクを毎日01:00に実行するようにcrontabを設定しました。
私のアプリの現在の仕様では、定期的(例: 毎日決まった時間)な実行ではなく、商品ごとに異なる締切に抽選を実行する(動的な処理時間の登録)。
cronは「定まった日時・頻度」に繰り返す処理を登録・実行するのに便利という理解 https://e-words.jp/w/cron.html
実行スケジュールは分刻みで指定することができ、毎時、毎日、毎週、毎月、再起動時(reboot)などを指定できるほか、該当する値を列挙したり範囲を指定することにより、「毎週月曜・水曜・金曜の午前0時」「9時から17時の毎時0分と30分」といった指定もできる。
cronは定期的に繰り返しコマンドを実行する場合に用いるもので、ある特定の日時に一度だけ実行したい場合はcronではなくatコマンドを使用する。
ActiveJobの場合はこんな感じで動的にジョブを登録できるかも
class Product < ApplicationRecord
after_create :schedule_winner_selection
# こんな感じで締め切り(deadline)時に実行される処理を登録
def schedule_winner_selection
SelectWinnerJob.set(wait_until: deadline).perform_later(id)
end
end
そもそも「何時何分に締め切り」みたいなことをする意味はそこまでないかも? (その厳密性は対して大事じゃない?) 6/12 締め切り -> 6/13 1時に抽選 は合理的かもしれない
📝
まずcronを使ったことがなかったので、簡単なrakeタスク(puts 'hello world'
)をcronで実行してログファイルに毎分吐き出すことを実験 -> 成功
簡単なrakeタスクをcronで定期実行する - shodan
デプロイに使う候補となる各PaaSには、cronを設定するための仕組みやWeb上の管理画面でのインターフェースなどが色々用意されている
という考え方ではなく、
という考え方になりそう。
この『その時点で締切が過ぎている商品を商品テーブルから検索し、もしあれば抽選処理を行う』をRakeタスクで書いておき、それをcronで定期実行する、というイメージ。
購入申込期限を「分単位」で設定できるようにしてしまうと、cronも分単位で設定し、(締め切りが過ぎた商品が本当にあるかどうかにかかわらず)毎分単位でRakeタスクを実行しないといけなくなる。
締切は「日」レベルでOK。 (6/17が締切の場合、6/17 23:59:59まで希望を出せるイメージ)
抽選はその翌日の朝くらいに行い、出品者や当選者にDiscordでメッセージを送るような感じで仕様としてはOK。
参考: https://odentakashi.github.io/2023/10/01/post6.html
ありえそうなアプローチ
cronとは https://e-words.jp/w/cron.html