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 its time to run the Ruby code.
Heres 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, "Its 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 its 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
- Both the win32-process and the win32-service libraries are available at http://rubyforge.org/projects/win32utils/
- Recipe 3.12, "Running a Code Block Periodically"
- Recipe 20.1, "Running a Daemon Process on Unix"
Категории