高木のブログ

【Ruby】Timers を使って定期実行する

2022/07/28

スクリプト内でとある処理を一定の間隔で繰り返し実行したい時、すぐ思いつくのは loop と sleep を使う方法

しかし、これだと処理の実行時間分ズレが発生する

sleep.rb
loop do
  puts Time.now

  # 少し時間が掛かる処理
  [*1..5000000].map(&:to_s).count

  sleep 60
end
$ ruby sleep.rb
2022-07-25 22:12:22 +0900
2022-07-25 22:13:26 +0900
2022-07-25 22:14:28 +0900
2022-07-25 22:15:29 +0900
2022-07-25 22:16:31 +0900
2022-07-25 22:17:33 +0900
2022-07-25 22:18:35 +0900
2022-07-25 22:19:36 +0900
2022-07-25 22:20:38 +0900
2022-07-25 22:21:40 +0900

どうにかならないかと探してみたら、それを解決する timers という Gem を見つけた

timers.rb
require 'bundler/inline'

gemfile do
  source 'https://rubygems.org'
  gem 'timers'
end

timers = Timers::Group.new

timers.every(60) do
  puts Time.now

  # 少し時間が掛かる処理
  [*1..5000000].map(&:to_s).count
end

loop { timers.wait }
$ ruby timers.rb
2022-07-25 22:13:20 +0900
2022-07-25 22:14:20 +0900
2022-07-25 22:15:20 +0900
2022-07-25 22:16:20 +0900
2022-07-25 22:17:20 +0900
2022-07-25 22:18:20 +0900
2022-07-25 22:19:20 +0900
2022-07-25 22:20:20 +0900
2022-07-25 22:21:20 +0900
2022-07-25 22:22:20 +0900

しっかり60秒ごと実行されている

サンプルコードとしてわかりやすいように今回は every メソッドを使ったが、これは1回目の処理も60秒後に実行される
1回目の処理はすぐに実行して欲しい場合は now_and_every メソッドを使うと良い

参考

Timers を使って Ruby で遅延実行・定期実行するスクリプトを作る - Qiita


ytkg

Written by ytkg, Twitter, GitHub