Recipe 23.4. Running Periodic Tasks Without cron or at
Problem
You want to write a self-contained Ruby program that performs a task in the background at a certain time, or runs repeatedly at a certain interval.
Solution
Fork off a new process that sleeps until it's time to run the Ruby code.
Here's a program that waits in the background until a certain time, then prints a message:
#!/usr/bin/ruby
# lunchtime.rb
def background_run_at(time)
fork do
sleep(1) until Time.now >= time
yield
end
end
today = Time.now
noon = Time.local(today.year, today.month, today.day, 12, 0, 0)
raise Exception, "It's already past lunchtime!" if noon < Time.now
background_run_at(noon) { puts "Lunchtime!" }
The fork command only works on Unix systems. The win32-process third-party add on gives Windows a fork implementation, but it's more idiomatic to run this code as a Windows service with win32-service.
Discussion
With this technique, you can write self-contained Ruby programs that act as though they were spawned by the at command. If you want to run a backgrounded code block at a certain interval, the way a cronjob would, then combine fork with the technique described in Recipe 3.12.
#!/usr/bin/ruby
# reminder.rb
def background_every_n_seconds(n)
fork do
loop do
before = Time.now
yield
interval = n-(Time.now-before)
sleep(interval) if interval > 0
end
end
end
background_every_n_seconds(15*60) { puts 'Get back to work!' }
Forking is the best technique if you want to run a background process and a foreground process. If you want a script that immediately returns you to the command prompt when it runs, you might want to use the Daemonize module instead; see Recipe 20.1.
See Also
 |