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

Категории