最近更新: 2010-03-14

Ruby CronLine

Cron 是 Unix 平台上的工作排程服務,它有一套特定的時間記述方式,俗稱 crontab (See crontab(5))。例如 * 30 5,12,17 * * * 表示每逢 5點30分、12點30分與17點30分時,執行工作。CronLine 則是使用 Ruby 所實作的一個用於解析 crontab 的類別。它的源碼來自於 Rufus::Scheduler

利用 Rufus::Scheduler ,我們可以很簡單地實作一個 Cron 服務。不過基於某些目的,我單獨地取出它的 CronLine class 使用。源碼位於 cronline.rb 。配合 Ruby on Rails 的名稱慣例,我將源碼文件的名稱改為 cron_line.rb 。

Ruby on Rails 的自動載入機制是根據類別名稱轉小寫,並以底線分隔單字,取得源碼文件名稱與路徑。例如:

  1. 類別名稱是大小寫夾雜時,轉小寫並以底線分隔單字,作為源碼文件名稱。
    CronLine.new -> load lib/cron_line.rb
  2. 類別名稱是單純一字時,轉小寫作為源碼文件名稱。
    Cronline.new -> load lib/cronline.rb
  3. 前綴 namespace 時,將 namespace 視為子目錄名稱。
    Rufus::CronLine.new -> load lib/rufus/cron_line.rb

我選擇第一種方式儲放 CronLine 的源碼文件,並移除源碼中的 module Rufus 敘述。當然我們也可以直接使用 require 指令明確地指示類別源碼的載入名稱,此時就不一定要按照上述的方式處理文件名稱與 module Rufus 敘述。

下列是一個測試與範例程式。

#!/usr/bin/ruby
# encoding: utf-8

require 'test/unit'
require 'cron_line'
require 'time'

class TestCronLine < Test::Unit::TestCase
    def test_not_match
        cron = CronLine.new "* 10 * * * *"
        assert !(cron.matches? Time.local 2000, 1, 1, 1, 1, 0)
    end

    def test_match
        cron = CronLine.new "* 10 * * * *"
        assert cron.matches? Time.local 2000, 1, 1, 1, 10, 0
    end

    def test_match_without_second
        cron = CronLine.new "10 * * * *"
        assert !(cron.matches? Time.local 2000, 1, 1, 1, 1)
        assert cron.matches? Time.local 2000, 1, 1, 1, 10
    end

    def test_match_day_hour_min
        cron = CronLine.new "*/2 */2 1,3,5 * *"
        assert !(cron.matches? Time.local 2000, 1, 1, 1, 1)
        assert cron.matches? Time.local 2000, 1, 1, 2, 30
    end
    
    def test_next_time
        cron = CronLine.new "*/10 * * * * *"

        start_time = Time.new
        next_time = cron.next_time Time.new
        sleep (next_time - start_time).to_i + 1
        end_time = Time.new

        assert next_time.sec <= end_time.sec and end_time.sec <= next_time.sec + 1
    end

end

一般而言,我們首先將一個 crontab 的時間記述字串做為 CronLine 實例的建構參數。接著我們再透過自定的輪詢機制,定期地取得目前時間,再調用 cron.matches 方法判斷目前時間是否符合 crontab 所指定的時間區間內,即可決定是否要執行工作了。例如上列測試程式的第5個測試項目,第35行,使用cron.next_time Time.new 得到下一個 crontab 指示的時間區段還有多久時間,再用 sleep 方法讓程序沉睡到指定時間區段後醒過來。

樂多舊網址: http://blog.roodo.com/rocksaying/archives/11948255.html