2007-01-24

cron ジョブに複雑な条件を与えやすくする

つーことで『cron, crontab, and more』でちまちま悩んでいましたが、思いついたのはまた Ruby ですが以下のものです。やってることは簡単で、要は

複雑な条件はお気に入りの言語で記述する

ってことです。そのために

  • 条件の名前と実行するプログラムを与えるだけのスクリプトを用意
  • 条件の名前はそのまま(この場合は Ruby の)実行するメソッド名に該当する
  • cron には(例えば)以下のように書く
complex-cron -c RULE 'program'

という方法にしてみました。以下のスクリプトでは RULE は省略可能で、その場合は `default' を指定したものとみなしています。

※ 比較的最近の Web アプリでよくあるプラグインと基本的には同じアイディア、だと思ってます。

呼び出すメソッド(つまり判定条件)に引き数を与えることはできません。一瞬悩みましたが必要ないだろうと思いますし、引き数を与えられるようにすると実行時のパラメータの与え方が複雑になります。

実行するスクリプト

(例えばcomplex-cron て名前にしておく)

#! /usr/bin/env ruby

require 'optparse'
Version = '0.1'

class ComplexCron
  def initialize
    @condfile     = '/etc/defaults/cronconds'
    @condname     = nil
    @cond_default = 'default'
    @debug        = false

    accept_options()
    @cmd = ARGV.shift
    exam_options()
    exec_indeed()
  end

  def exam_options
    if ( @cmd.nil? )
      raise 'Nothing to do.'
    end

    if ( !File.exist?( @condfile ) )
      raise "File #{@condfile} does not exist."
    else
      load( @condfile, false )
      if ( @condname.nil? )
        @condname = @cond_default
      elsif ( !ComplexCronConds.instance_methods().include?( @condname ) )
        raise "Rule #{@condname} is not defined."
      end
    end
  end

  def exec_indeed
    if ( ComplexCronConds.instance_method( @condname ) )
      if ( @debug )
        puts @cmd
      else
        exec @cmd
      end
    end
  end

  def accept_options
    opt = OptionParser.new()
    opt.on( '-f CONDFILE' ) { |file|
      @condfile = file
    }
    opt.on( '-c CONDNAME' ) { |method|
      @condname = method
    }
    opt.on( '-n', 'dry run' ) { |v|
      @debug = true
    }
    opt.parse!( ARGV )
  end
end # of class ComplexCron

ComplexCron.new()

設定ファイルとは名ばかりの Ruby スクリプト

例えば /etc/defaults/cronconds とかいう名前で置いておく。場所はシステムに応じて適当に決めて。

# -*- ruby -*-

module ComplexCronConds
  def default
    return false
  end
end

この中に上で RULE と書いた名前に該当するメソッドを定義していきます。内容はどうぞご自由に。ただしあくまで「条件」をメソッドとして書くので、必ず true か false を返してください。default はあった方がいいかなと思って定義してあるんですけど、実際どう使うのかはあんまりイメージできてません。

これでまぁ、第3水曜だのシステムの負荷の様子だの、Ruby で判別可能な条件はなんでも書けるようになったわけです。あとは必要に迫られたときに考えればいいんじゃないかと。

About

例によって個人のなんちゃらです