Class: Rufus::Scheduler
- Inherits:
-
Object
- Object
- Rufus::Scheduler
- Defined in:
- lib/rufus/scheduler.rb,
lib/rufus/scheduler/jobs.rb,
lib/rufus/scheduler/util.rb,
lib/rufus/scheduler/locks.rb,
lib/rufus/scheduler/zones.rb,
lib/rufus/scheduler/zotime.rb,
lib/rufus/scheduler/cronline.rb,
lib/rufus/scheduler/job_array.rb
Defined Under Namespace
Classes: AtJob, CronJob, CronLine, D, Error, EvInJob, EveryJob, FileLock, InJob, IntervalJob, Job, JobArray, NotRunningError, NullLock, OneTimeJob, RepeatJob, TimeoutError, ZoTime
Constant Summary collapse
- VERSION =
'3.1.9'- MAX_WORK_THREADS =
MIN_WORK_THREADS = 3
28- DURATIONS2M =
[ [ 'y', 365 * 24 * 3600 ], [ 'M', 30 * 24 * 3600 ], [ 'w', 7 * 24 * 3600 ], [ 'd', 24 * 3600 ], [ 'h', 3600 ], [ 'm', 60 ], [ 's', 1 ] ]
- DURATIONS2 =
DURATIONS2M.dup
- DURATIONS =
DURATIONS2M.inject({}) { |r, (k, v)| r[k] = v; r }
- DURATION_LETTERS =
DURATIONS.keys.join
- DU_KEYS =
DURATIONS2M.collect { |k, v| k.to_sym }
- TIMEZONES =
%w[ GB NZ UCT EET CET PRC ROC WET GMT EST ROK UTC MST HST MET Zulu Cuba Iran W-SU Eire GMT0 Libya Japan Egypt GMT+0 GMT-0 Israel Poland Navajo Turkey GB-Eire Iceland PST8PDT Etc/UCT CST6CDT NZ-CHAT MST7MDT Jamaica EST5EDT Etc/GMT Etc/UTC US/Samoa Etc/GMT0 Portugal Hongkong Etc/Zulu Singapore Asia/Baku Etc/GMT-9 Etc/GMT+1 Etc/GMT+0 Asia/Aden Etc/GMT+2 Etc/GMT+3 Etc/GMT+4 Etc/GMT+5 Etc/GMT+6 Etc/GMT+7 Etc/GMT+8 Etc/GMT+9 Etc/GMT-0 Etc/GMT-1 Universal Asia/Dili Greenwich Asia/Gaza Etc/GMT-8 Etc/GMT-7 US/Alaska Asia/Oral Etc/GMT-6 Etc/GMT-5 Etc/GMT-4 Asia/Hovd Etc/GMT-3 US/Hawaii Etc/GMT-2 Kwajalein Asia/Omsk Asia/Macao Etc/GMT-14 Asia/Kabul US/Central Etc/GMT-13 US/Arizona Asia/Macau Asia/Qatar Asia/Seoul Asia/Tokyo Asia/Dubai US/Pacific Etc/GMT-12 Etc/GMT-11 Etc/GMT-10 Asia/Dhaka Asia/Dacca Asia/Chita Etc/GMT+12 Etc/GMT+10 Asia/Amman Asia/Aqtau Etc/GMT+11 US/Eastern Asia/Thimbu Asia/Brunei Asia/Tehran Asia/Beirut Europe/Rome Europe/Riga Brazil/Acre Brazil/East Europe/Oslo Brazil/West Africa/Lome Asia/Taipei Asia/Saigon Asia/Riyadh Asia/Aqtobe Asia/Anadyr Europe/Kiev Asia/Almaty Africa/Juba Pacific/Yap US/Aleutian Asia/Muscat US/Mountain Asia/Harbin Asia/Hebron Asia/Manila Asia/Kuwait Asia/Urumqi US/Michigan Indian/Mahe SystemV/EST5 Asia/Kashgar Indian/Cocos Asia/Jakarta Asia/Kolkata Asia/Kuching America/Atka Asia/Irkutsk Pacific/Apia Asia/Magadan Africa/Dakar America/Lima Pacific/Fiji Pacific/Guam Europe/Vaduz Pacific/Niue Asia/Nicosia Africa/Ceuta Pacific/Truk America/Adak Pacific/Wake Africa/Tunis Africa/Cairo Asia/Colombo SystemV/AST4 SystemV/CST6 Asia/Karachi Asia/Rangoon SystemV/MST7 Asia/Baghdad Europe/Malta Africa/Lagos Europe/Minsk SystemV/PST8 Canada/Yukon Asia/Tbilisi America/Nome Asia/Bahrain Africa/Accra Europe/Paris Asia/Bangkok Asia/Bishkek Asia/Thimphu SystemV/YST9 Asia/Yerevan Asia/Yakutsk Europe/Sofia Asia/Ust-Nera Australia/ACT Australia/LHI Europe/Tirane Asia/Tel_Aviv Australia/NSW Africa/Luanda Asia/Tashkent Africa/Lusaka Asia/Shanghai Africa/Malabo Asia/Sakhalin Africa/Maputo Africa/Maseru SystemV/HST10 Africa/Kigali Africa/Niamey Pacific/Samoa America/Sitka Pacific/Palau Pacific/Nauru Pacific/Efate Asia/Makassar Pacific/Chuuk Africa/Harare Africa/Douala America/Aruba America/Thule America/Bahia America/Jujuy America/Belem Asia/Katmandu America/Boise Indian/Comoro Indian/Chagos Asia/Jayapura Europe/Zurich Asia/Istanbul Europe/Zagreb Etc/Greenwich Europe/Warsaw Europe/Vienna Etc/Universal Asia/Dushanbe Europe/Athens Europe/Berlin Africa/Bissau Asia/Damascus Africa/Banjul Europe/Dublin Africa/Bangui Africa/Bamako Europe/Jersey Africa/Asmera Europe/Lisbon Africa/Asmara Europe/London Asia/Ashgabat Asia/Calcutta Europe/Madrid Europe/Monaco Europe/Moscow Europe/Prague Europe/Samara Europe/Skopje Asia/Khandyga Canada/Pacific Africa/Abidjan America/Manaus Asia/Chongqing Asia/Chungking Africa/Algiers America/Maceio US/Pacific-New Africa/Conakry America/La_Paz America/Juneau America/Nassau America/Inuvik Europe/Andorra Africa/Kampala Asia/Ashkhabad Asia/Hong_Kong America/Havana Canada/Eastern Europe/Belfast Canada/Central Australia/West Asia/Jerusalem Africa/Mbabane Asia/Kamchatka America/Virgin America/Guyana Asia/Kathmandu Mexico/General America/Panama Europe/Nicosia America/Denver Europe/Tallinn Africa/Nairobi America/Dawson Europe/Vatican Europe/Vilnius America/Cuiaba Africa/Tripoli Pacific/Wallis Atlantic/Faroe Pacific/Tarawa Pacific/Tahiti Pacific/Saipan Pacific/Ponape America/Cayman America/Cancun Asia/Pontianak Asia/Pyongyang Asia/Vientiane Asia/Qyzylorda Pacific/Noumea America/Bogota Pacific/Midway Pacific/Majuro Asia/Samarkand Indian/Mayotte Pacific/Kosrae Asia/Singapore Indian/Reunion America/Belize America/Regina America/Recife Pacific/Easter Mexico/BajaSur America/Merida Pacific/Chatham Pacific/Fakaofo Pacific/Gambier America/Rosario Asia/Ulan_Bator Indian/Maldives Pacific/Norfolk America/Antigua Asia/Phnom_Penh America/Phoenix America/Caracas America/Cayenne Atlantic/Azores Pacific/Pohnpei Atlantic/Canary America/Chicago Atlantic/Faeroe Africa/Windhoek America/Cordoba America/Creston Africa/Timbuktu America/Curacao Africa/Sao_Tome Africa/Ndjamena SystemV/AST4ADT Europe/Uzhgorod Europe/Tiraspol SystemV/CST6CDT Africa/Monrovia America/Detroit Europe/Sarajevo Australia/Eucla America/Tijuana America/Toronto America/Godthab America/Grenada Europe/Istanbul America/Ojinaga America/Tortola Australia/Perth Europe/Helsinki Australia/South Europe/Guernsey SystemV/EST5EDT Europe/Chisinau SystemV/MST7MDT Europe/Busingen Europe/Budapest Europe/Brussels America/Halifax America/Mendoza America/Noronha America/Nipigon Canada/Atlantic America/Yakutat SystemV/PST8PDT SystemV/YST9YDT Canada/Mountain Africa/Kinshasa Africa/Khartoum Africa/Gaborone Africa/Freetown America/Iqaluit America/Jamaica US/East-Indiana Africa/El_Aaiun America/Knox_IN Africa/Djibouti Africa/Blantyre America/Moncton America/Managua Asia/Choibalsan America/Marigot Australia/North Europe/Belgrade America/Resolute America/Mazatlan Pacific/Funafuti Pacific/Auckland Pacific/Honolulu Pacific/Johnston America/Miquelon America/Santarem Mexico/BajaNorte America/Santiago Antarctica/Troll America/Asuncion America/Atikokan America/Montreal America/Barbados Africa/Bujumbura Pacific/Pitcairn Asia/Ulaanbaatar Indian/Mauritius America/New_York Antarctica/Syowa America/Shiprock Indian/Kerguelen Asia/Novosibirsk America/Anguilla Indian/Christmas Asia/Vladivostok Asia/Ho_Chi_Minh Antarctica/Davis Atlantic/Bermuda Europe/Amsterdam Antarctica/Casey America/St_Johns Atlantic/Madeira America/Winnipeg America/St_Kitts Europe/Volgograd Brazil/DeNoronha Europe/Bucharest Africa/Mogadishu America/St_Lucia Atlantic/Stanley Europe/Stockholm Australia/Currie Europe/Gibraltar Australia/Sydney Asia/Krasnoyarsk Australia/Darwin America/Dominica America/Edmonton America/Eirunepe Europe/Podgorica America/Ensenada Europe/Ljubljana Australia/Hobart Europe/Mariehamn Africa/Lubumbashi America/Goose_Bay Europe/Luxembourg America/Menominee America/Glace_Bay America/Fortaleza Africa/Nouakchott America/Matamoros Pacific/Galapagos America/Guatemala Pacific/Kwajalein Pacific/Marquesas America/Guayaquil Asia/Kuala_Lumpur Europe/San_Marino America/Monterrey Europe/Simferopol America/Araguaina Antarctica/Vostok Europe/Copenhagen America/Catamarca Pacific/Pago_Pago America/Sao_Paulo America/Boa_Vista America/St_Thomas Chile/Continental America/Vancouver Africa/Casablanca Europe/Bratislava Pacific/Enderbury Pacific/Rarotonga Europe/Zaporozhye US/Indiana-Starke Antarctica/Palmer Asia/Novokuznetsk Africa/Libreville America/Chihuahua America/Anchorage Pacific/Tongatapu Antarctica/Mawson Africa/Porto-Novo Asia/Yekaterinburg America/Paramaribo America/Hermosillo Atlantic/Jan_Mayen Antarctica/McMurdo America/Costa_Rica Antarctica/Rothera America/Grand_Turk Atlantic/Reykjavik Atlantic/St_Helena Australia/Victoria Chile/EasterIsland Asia/Ujung_Pandang Australia/Adelaide America/Montserrat America/Porto_Acre Africa/Brazzaville Australia/Brisbane America/Kralendijk America/Montevideo America/St_Vincent America/Louisville Australia/Canberra Australia/Tasmania Europe/Isle_of_Man Europe/Kaliningrad Africa/Ouagadougou America/Rio_Branco Pacific/Kiritimati Africa/Addis_Ababa America/Metlakatla America/Martinique Asia/Srednekolymsk America/Guadeloupe America/Fort_Wayne Australia/Lindeman America/Whitehorse Arctic/Longyearbyen America/Pangnirtung America/Mexico_City America/Los_Angeles America/Rainy_River Atlantic/Cape_Verde Pacific/Guadalcanal Indian/Antananarivo America/El_Salvador Australia/Lord_Howe Africa/Johannesburg America/Tegucigalpa Canada/Saskatchewan America/Thunder_Bay Canada/Newfoundland America/Puerto_Rico America/Yellowknife Australia/Melbourne America/Porto_Velho Australia/Queensland Australia/Yancowinna America/Santa_Isabel America/Blanc-Sablon America/Scoresbysund America/Danmarkshavn Pacific/Port_Moresby Antarctica/Macquarie America/Buenos_Aires Africa/Dar_es_Salaam America/Campo_Grande America/Dawson_Creek America/Indianapolis Pacific/Bougainville America/Rankin_Inlet America/Indiana/Knox America/Lower_Princes America/Coral_Harbour America/St_Barthelemy Australia/Broken_Hill America/Cambridge_Bay America/Indiana/Vevay America/Swift_Current America/Port_of_Spain Antarctica/South_Pole America/Santo_Domingo Atlantic/South_Georgia America/Port-au-Prince America/Bahia_Banderas America/Indiana/Winamac America/Indiana/Marengo America/Argentina/Jujuy America/Argentina/Salta Canada/East-Saskatchewan America/Indiana/Vincennes America/Argentina/Tucuman America/Argentina/Ushuaia Antarctica/DumontDUrville America/Indiana/Tell_City America/Argentina/Mendoza America/Argentina/Cordoba America/Indiana/Petersburg America/Argentina/San_Luis America/Argentina/San_Juan America/Argentina/La_Rioja America/North_Dakota/Center America/Kentucky/Monticello America/North_Dakota/Beulah America/Kentucky/Louisville America/Argentina/Catamarca America/Indiana/Indianapolis America/North_Dakota/New_Salem America/Argentina/Rio_Gallegos America/Argentina/Buenos_Aires America/Argentina/ComodRivadavia ]- TIMEZONEs =
TIMEZONES.collect(&:downcase)
Instance Attribute Summary collapse
-
#frequency ⇒ Object
Returns the value of attribute frequency.
-
#max_work_threads ⇒ Object
attr_accessor :min_work_threads.
-
#mutexes ⇒ Object
readonly
Returns the value of attribute mutexes.
-
#started_at ⇒ Object
readonly
Returns the value of attribute started_at.
-
#stderr ⇒ Object
Returns the value of attribute stderr.
-
#thread ⇒ Object
readonly
Returns the value of attribute thread.
-
#thread_key ⇒ Object
readonly
Returns the value of attribute thread_key.
-
#work_queue ⇒ Object
readonly
Returns the value of attribute work_queue.
Class Method Summary collapse
-
.h_to_s(t = Time.now) ⇒ Object
Produces a hour/min/sec/milli string representation of Time instance.
-
.parse(o, opts = {}) ⇒ Object
– time and string methods ++.
- .parse_at(o, opts = {}) ⇒ Object
- .parse_cron(o, opts) ⇒ Object
-
.parse_duration(string, opts = {}) ⇒ Object
(also: parse_duration_string, parse_time_string)
Turns a string like ‘1m10s’ into a float like ‘70.0’, more formally, turns a time duration expressed as a string into a Float instance (millisecond count).
- .parse_in(o, opts = {}) ⇒ Object
- .parse_to_time(o) ⇒ Object
-
.s(opts = {}) ⇒ Object
Alias for Rufus::Scheduler.singleton.
-
.singleton(opts = {}) ⇒ Object
Returns a singleton Rufus::Scheduler instance.
-
.start_new ⇒ Object
Releasing the gem would probably require redirecting .start_new to .new and emit a simple deprecation message.
-
.to_duration(seconds, options = {}) ⇒ Object
(also: to_duration_string, to_time_string)
Turns a number of seconds into a a time string.
-
.to_duration_hash(seconds, options = {}) ⇒ Object
Turns a number of seconds (integer or Float) into a hash like in :.
-
.utc_to_s(t = Time.now) ⇒ Object
Produces the UTC string representation of a Time instance.
Instance Method Summary collapse
-
#at(time, callable = nil, opts = {}, &block) ⇒ Object
– scheduling methods ++.
- #at_jobs(opts = {}) ⇒ Object
-
#confirm_lock ⇒ Object
Callback called when a job is triggered.
- #cron(cronline, callable = nil, opts = {}, &block) ⇒ Object
- #cron_jobs(opts = {}) ⇒ Object
- #down? ⇒ Boolean
- #every(duration, callable = nil, opts = {}, &block) ⇒ Object
- #every_jobs(opts = {}) ⇒ Object
- #in(duration, callable = nil, opts = {}, &block) ⇒ Object
- #in_jobs(opts = {}) ⇒ Object
-
#initialize(opts = {}) ⇒ Scheduler
constructor
A new instance of Scheduler.
- #interval(duration, callable = nil, opts = {}, &block) ⇒ Object
- #interval_jobs(opts = {}) ⇒ Object
- #job(job_id) ⇒ Object
-
#jobs(opts = {}) ⇒ Object
Returns all the scheduled jobs (even those right before re-schedule).
- #join ⇒ Object
-
#lock ⇒ Object
Returns true if the scheduler has acquired the [exclusive] lock and thus may run.
- #occurrences(time0, time1, format = :per_job) ⇒ Object
- #on_error(job, err) ⇒ Object
- #pause ⇒ Object
- #paused? ⇒ Boolean
- #repeat(arg, callable = nil, opts = {}, &block) ⇒ Object
- #resume ⇒ Object
- #running_jobs(opts = {}) ⇒ Object
- #schedule(arg, callable = nil, opts = {}, &block) ⇒ Object
- #schedule_at(time, callable = nil, opts = {}, &block) ⇒ Object
- #schedule_cron(cronline, callable = nil, opts = {}, &block) ⇒ Object
- #schedule_every(duration, callable = nil, opts = {}, &block) ⇒ Object
- #schedule_in(duration, callable = nil, opts = {}, &block) ⇒ Object
- #schedule_interval(duration, callable = nil, opts = {}, &block) ⇒ Object
-
#scheduled?(job_or_job_id) ⇒ Boolean
Returns true if this job is currently scheduled.
- #shutdown(opt = nil) ⇒ Object (also: #stop)
-
#threads ⇒ Object
Lists all the threads associated with this scheduler.
- #timeline(time0, time1) ⇒ Object
-
#unlock ⇒ Object
Sister method to #lock, is called when the scheduler shuts down.
- #unschedule(job_or_job_id) ⇒ Object
- #up? ⇒ Boolean
- #uptime ⇒ Object
- #uptime_s ⇒ Object
-
#work_threads(query = :all) ⇒ Object
Lists all the work threads (the ones actually running the scheduled block code).
Constructor Details
#initialize(opts = {}) ⇒ Scheduler
Returns a new instance of Scheduler.
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 |
# File 'lib/rufus/scheduler.rb', line 76 def initialize(opts={}) @opts = opts @started_at = nil @paused = false @jobs = JobArray.new @frequency = Rufus::Scheduler.parse(opts[:frequency] || 0.300) @mutexes = {} @work_queue = Queue.new #@min_work_threads = opts[:min_work_threads] || MIN_WORK_THREADS @max_work_threads = opts[:max_work_threads] || MAX_WORK_THREADS @stderr = $stderr @thread_key = "rufus_scheduler_#{self.object_id}" @scheduler_lock = if lockfile = opts[:lockfile] Rufus::Scheduler::FileLock.new(lockfile) else opts[:scheduler_lock] || Rufus::Scheduler::NullLock.new end @trigger_lock = opts[:trigger_lock] || Rufus::Scheduler::NullLock.new # If we can't grab the @scheduler_lock, don't run. @scheduler_lock.lock || return start end |
Instance Attribute Details
#frequency ⇒ Object
Returns the value of attribute frequency.
63 64 65 |
# File 'lib/rufus/scheduler.rb', line 63 def frequency @frequency end |
#max_work_threads ⇒ Object
attr_accessor :min_work_threads
70 71 72 |
# File 'lib/rufus/scheduler.rb', line 70 def max_work_threads @max_work_threads end |
#mutexes ⇒ Object (readonly)
Returns the value of attribute mutexes.
67 68 69 |
# File 'lib/rufus/scheduler.rb', line 67 def mutexes @mutexes end |
#started_at ⇒ Object (readonly)
Returns the value of attribute started_at.
64 65 66 |
# File 'lib/rufus/scheduler.rb', line 64 def started_at @started_at end |
#stderr ⇒ Object
Returns the value of attribute stderr.
72 73 74 |
# File 'lib/rufus/scheduler.rb', line 72 def stderr @stderr end |
#thread ⇒ Object (readonly)
Returns the value of attribute thread.
65 66 67 |
# File 'lib/rufus/scheduler.rb', line 65 def thread @thread end |
#thread_key ⇒ Object (readonly)
Returns the value of attribute thread_key.
66 67 68 |
# File 'lib/rufus/scheduler.rb', line 66 def thread_key @thread_key end |
#work_queue ⇒ Object (readonly)
Returns the value of attribute work_queue.
74 75 76 |
# File 'lib/rufus/scheduler.rb', line 74 def work_queue @work_queue end |
Class Method Details
.h_to_s(t = Time.now) ⇒ Object
Produces a hour/min/sec/milli string representation of Time instance
293 294 295 296 |
# File 'lib/rufus/scheduler/util.rb', line 293 def self.h_to_s(t=Time.now) "#{t.strftime('%H:%M:%S')}.#{sprintf('%06d', t.usec)}" end |
.parse(o, opts = {}) ⇒ Object
– time and string methods ++
34 35 36 37 38 39 40 41 42 |
# File 'lib/rufus/scheduler/util.rb', line 34 def self.parse(o, opts={}) opts[:no_error] = true parse_cron(o, opts) || parse_in(o, opts) || # covers 'every' schedule strings parse_at(o, opts) || raise(ArgumentError.new("couldn't parse \"#{o}\"")) end |
.parse_at(o, opts = {}) ⇒ Object
49 50 51 52 53 54 55 56 57 |
# File 'lib/rufus/scheduler/util.rb', line 49 def self.parse_at(o, opts={}) Rufus::Scheduler::ZoTime.parse(o, opts).time rescue StandardError => se return nil if opts[:no_error] raise se end |
.parse_cron(o, opts) ⇒ Object
59 60 61 62 63 64 65 66 67 |
# File 'lib/rufus/scheduler/util.rb', line 59 def self.parse_cron(o, opts) CronLine.new(o) rescue ArgumentError => ae return nil if opts[:no_error] raise ae end |
.parse_duration(string, opts = {}) ⇒ Object Also known as: parse_duration_string, parse_time_string
Turns a string like ‘1m10s’ into a float like ‘70.0’, more formally, turns a time duration expressed as a string into a Float instance (millisecond count).
w -> week d -> day h -> hour m -> minute s -> second M -> month y -> year ‘nada’ -> millisecond
Some examples:
Rufus::Scheduler.parse_duration "0.5" # => 0.5
Rufus::Scheduler.parse_duration "500" # => 0.5
Rufus::Scheduler.parse_duration "1000" # => 1.0
Rufus::Scheduler.parse_duration "1h" # => 3600.0
Rufus::Scheduler.parse_duration "1h10s" # => 3610.0
Rufus::Scheduler.parse_duration "1w2d" # => 777600.0
Negative time strings are OK (Thanks Danny Fullerton):
Rufus::Scheduler.parse_duration "-0.5" # => -0.5
Rufus::Scheduler.parse_duration "-1h" # => -3600.0
126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
# File 'lib/rufus/scheduler/util.rb', line 126 def self.parse_duration(string, opts={}) string = string.to_s return 0.0 if string == '' m = string.match(/^(-?)([\d\.#{DURATION_LETTERS}]+)$/) return nil if m.nil? && opts[:no_error] raise ArgumentError.new("cannot parse '#{string}'") if m.nil? mod = m[1] == '-' ? -1.0 : 1.0 val = 0.0 s = m[2] while s.length > 0 m = nil if m = s.match(/^(\d+|\d+\.\d*|\d*\.\d+)([#{DURATION_LETTERS}])(.*)$/) val += m[1].to_f * DURATIONS[m[2]] elsif s.match(/^\d+$/) val += s.to_i elsif s.match(/^\d*\.\d*$/) val += s.to_f elsif opts[:no_error] return nil else raise ArgumentError.new( "cannot parse '#{string}' (especially '#{s}')" ) end break unless m && m[3] s = m[3] end mod * val end |
.parse_in(o, opts = {}) ⇒ Object
44 45 46 47 |
# File 'lib/rufus/scheduler/util.rb', line 44 def self.parse_in(o, opts={}) o.is_a?(String) ? parse_duration(o, opts) : o end |
.parse_to_time(o) ⇒ Object
69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/rufus/scheduler/util.rb', line 69 def self.parse_to_time(o) t = o t = parse(t) if t.is_a?(String) t = Time.now + t if t.is_a?(Numeric) raise ArgumentError.new( "cannot turn #{o.inspect} to a point in time, doesn't make sense" ) unless t.is_a?(Time) t end |
.s(opts = {}) ⇒ Object
Alias for Rufus::Scheduler.singleton
121 |
# File 'lib/rufus/scheduler.rb', line 121 def self.s(opts={}); singleton(opts); end |
.singleton(opts = {}) ⇒ Object
Returns a singleton Rufus::Scheduler instance
114 115 116 117 |
# File 'lib/rufus/scheduler.rb', line 114 def self.singleton(opts={}) @singleton ||= Rufus::Scheduler.new(opts) end |
.start_new ⇒ Object
Releasing the gem would probably require redirecting .start_new to .new and emit a simple deprecation message.
For now, let’s assume the people pointing at rufus-scheduler/master on GitHub know what they do…
129 130 131 132 |
# File 'lib/rufus/scheduler.rb', line 129 def self.start_new fail "this is rufus-scheduler 3.0, use .new instead of .start_new" end |
.to_duration(seconds, options = {}) ⇒ Object Also known as: to_duration_string, to_time_string
Turns a number of seconds into a a time string
Rufus.to_duration 0 # => '0s'
Rufus.to_duration 60 # => '1m'
Rufus.to_duration 3661 # => '1h1m1s'
Rufus.to_duration 7 * 24 * 3600 # => '1w'
Rufus.to_duration 30 * 24 * 3600 + 1 # => "4w2d1s"
It goes from seconds to the year. Months are not counted (as they are of variable length). Weeks are counted.
For 30 days months to be counted, the second parameter of this method can be set to true.
Rufus.to_duration 30 * 24 * 3600 + 1, true # => "1M1s"
If a Float value is passed, milliseconds will be displayed without ‘marker’
Rufus.to_duration 0.051 # => "51"
Rufus.to_duration 7.051 # => "7s51"
Rufus.to_duration 0.120 + 30 * 24 * 3600 + 1 # => "4w2d1s120"
(this behaviour mirrors the one found for parse_time_string()).
Options are :
-
:months, if set to true, months (M) of 30 days will be taken into account when building up the result
-
:drop_seconds, if set to true, seconds and milliseconds will be trimmed from the result
205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 |
# File 'lib/rufus/scheduler/util.rb', line 205 def self.to_duration(seconds, ={}) h = to_duration_hash(seconds, ) return ([:drop_seconds] ? '0m' : '0s') if h.empty? s = DU_KEYS.inject('') { |r, key| count = h[key] count = nil if count == 0 r << "#{count}#{key}" if count r } ms = h[:ms] s << ms.to_s if ms s end |
.to_duration_hash(seconds, options = {}) ⇒ Object
Turns a number of seconds (integer or Float) into a hash like in :
Rufus.to_duration_hash 0.051
# => { :ms => "51" }
Rufus.to_duration_hash 7.051
# => { :s => 7, :ms => "51" }
Rufus.to_duration_hash 0.120 + 30 * 24 * 3600 + 1
# => { :w => 4, :d => 2, :s => 1, :ms => "120" }
This method is used by to_duration behind the scenes.
Options are :
-
:months, if set to true, months (M) of 30 days will be taken into account when building up the result
-
:drop_seconds, if set to true, seconds and milliseconds will be trimmed from the result
251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 |
# File 'lib/rufus/scheduler/util.rb', line 251 def self.to_duration_hash(seconds, ={}) h = {} if seconds.is_a?(Float) h[:ms] = (seconds % 1 * 1000).to_i seconds = seconds.to_i end if [:drop_seconds] h.delete(:ms) seconds = (seconds - seconds % 60) end durations = [:months] ? DURATIONS2M : DURATIONS2 durations.each do |key, duration| count = seconds / duration seconds = seconds % duration h[key.to_sym] = count if count > 0 end h end |
.utc_to_s(t = Time.now) ⇒ Object
Produces the UTC string representation of a Time instance
like “2009/11/23 11:11:50.947109 UTC”
286 287 288 289 |
# File 'lib/rufus/scheduler/util.rb', line 286 def self.utc_to_s(t=Time.now) "#{t.utc.strftime('%Y-%m-%d %H:%M:%S')}.#{sprintf('%06d', t.usec)} UTC" end |
Instance Method Details
#at(time, callable = nil, opts = {}, &block) ⇒ Object
– scheduling methods ++
203 204 205 206 |
# File 'lib/rufus/scheduler.rb', line 203 def at(time, callable=nil, opts={}, &block) do_schedule(:once, time, callable, opts, opts[:job], block) end |
#at_jobs(opts = {}) ⇒ Object
308 309 310 311 |
# File 'lib/rufus/scheduler.rb', line 308 def at_jobs(opts={}) jobs(opts).select { |j| j.is_a?(Rufus::Scheduler::AtJob) } end |
#confirm_lock ⇒ Object
Callback called when a job is triggered. If the lock cannot be acquired, the job won’t run (though it’ll still be scheduled to run again if necessary).
376 377 378 379 |
# File 'lib/rufus/scheduler.rb', line 376 def confirm_lock @trigger_lock.lock end |
#cron(cronline, callable = nil, opts = {}, &block) ⇒ Object
243 244 245 246 |
# File 'lib/rufus/scheduler.rb', line 243 def cron(cronline, callable=nil, opts={}, &block) do_schedule(:cron, cronline, callable, opts, opts[:job], block) end |
#cron_jobs(opts = {}) ⇒ Object
328 329 330 331 |
# File 'lib/rufus/scheduler.rb', line 328 def cron_jobs(opts={}) jobs(opts).select { |j| j.is_a?(Rufus::Scheduler::CronJob) } end |
#down? ⇒ Boolean
174 175 176 177 |
# File 'lib/rufus/scheduler.rb', line 174 def down? ! @started_at end |
#every(duration, callable = nil, opts = {}, &block) ⇒ Object
223 224 225 226 |
# File 'lib/rufus/scheduler.rb', line 223 def every(duration, callable=nil, opts={}, &block) do_schedule(:every, duration, callable, opts, opts[:job], block) end |
#every_jobs(opts = {}) ⇒ Object
318 319 320 321 |
# File 'lib/rufus/scheduler.rb', line 318 def every_jobs(opts={}) jobs(opts).select { |j| j.is_a?(Rufus::Scheduler::EveryJob) } end |
#in(duration, callable = nil, opts = {}, &block) ⇒ Object
213 214 215 216 |
# File 'lib/rufus/scheduler.rb', line 213 def in(duration, callable=nil, opts={}, &block) do_schedule(:once, duration, callable, opts, opts[:job], block) end |
#in_jobs(opts = {}) ⇒ Object
313 314 315 316 |
# File 'lib/rufus/scheduler.rb', line 313 def in_jobs(opts={}) jobs(opts).select { |j| j.is_a?(Rufus::Scheduler::InJob) } end |
#interval(duration, callable = nil, opts = {}, &block) ⇒ Object
233 234 235 236 |
# File 'lib/rufus/scheduler.rb', line 233 def interval(duration, callable=nil, opts={}, &block) do_schedule(:interval, duration, callable, opts, opts[:job], block) end |
#interval_jobs(opts = {}) ⇒ Object
323 324 325 326 |
# File 'lib/rufus/scheduler.rb', line 323 def interval_jobs(opts={}) jobs(opts).select { |j| j.is_a?(Rufus::Scheduler::IntervalJob) } end |
#job(job_id) ⇒ Object
333 334 335 336 |
# File 'lib/rufus/scheduler.rb', line 333 def job(job_id) @jobs[job_id] end |
#jobs(opts = {}) ⇒ Object
Returns all the scheduled jobs (even those right before re-schedule).
290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 |
# File 'lib/rufus/scheduler.rb', line 290 def jobs(opts={}) opts = { opts => true } if opts.is_a?(Symbol) jobs = @jobs.to_a if opts[:running] jobs = jobs.select { |j| j.running? } elsif ! opts[:all] jobs = jobs.reject { |j| j.next_time.nil? || j.unscheduled_at } end = Array(opts[:tag] || opts[:tags]).collect { |t| t.to_s } jobs = jobs.reject { |j| .find { |t| ! j..include?(t) } } jobs end |
#join ⇒ Object
165 166 167 168 169 170 171 172 |
# File 'lib/rufus/scheduler.rb', line 165 def join fail NotRunningError.new( 'cannot join scheduler that is not running' ) unless @thread @thread.join end |
#lock ⇒ Object
Returns true if the scheduler has acquired the [exclusive] lock and thus may run.
Most of the time, a scheduler is run alone and this method should return true. It is useful in cases where among a group of applications only one of them should run the scheduler. For schedulers that should not run, the method should return false.
Out of the box, rufus-scheduler proposes the :lockfile => ‘path/to/lock/file’ scheduler start option. It makes it easy for schedulers on the same machine to determine which should run (the first to write the lockfile and lock it). It uses “man 2 flock” so it probably won’t work reliably on distributed file systems.
If one needs to use a special/different locking mechanism, the scheduler accepts :scheduler_lock => lock_object. lock_object only needs to respond to #lock and #unlock, and both of these methods should be idempotent.
Look at rufus/scheduler/locks.rb for an example.
359 360 361 362 |
# File 'lib/rufus/scheduler.rb', line 359 def lock @scheduler_lock.lock end |
#occurrences(time0, time1, format = :per_job) ⇒ Object
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 |
# File 'lib/rufus/scheduler.rb', line 432 def occurrences(time0, time1, format=:per_job) h = {} jobs.each do |j| os = j.occurrences(time0, time1) h[j] = os if os.any? end if format == :timeline a = [] h.each { |j, ts| ts.each { |t| a << [ t, j ] } } a.sort_by { |(t, j)| t } else h end end |
#on_error(job, err) ⇒ Object
455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 |
# File 'lib/rufus/scheduler.rb', line 455 def on_error(job, err) pre = err.object_id.to_s ms = {}; mutexes.each { |k, v| ms[k] = v.locked? } stderr.puts("{ #{pre} rufus-scheduler intercepted an error:") stderr.puts(" #{pre} job:") stderr.puts(" #{pre} #{job.class} #{job.original.inspect} #{job.opts.inspect}") # TODO: eventually use a Job#detail or something like that stderr.puts(" #{pre} error:") stderr.puts(" #{pre} #{err.object_id}") stderr.puts(" #{pre} #{err.class}") stderr.puts(" #{pre} #{err}") err.backtrace.each do |l| stderr.puts(" #{pre} #{l}") end stderr.puts(" #{pre} tz:") stderr.puts(" #{pre} ENV['TZ']: #{ENV['TZ']}") stderr.puts(" #{pre} Time.now: #{Time.now}") stderr.puts(" #{pre} scheduler:") stderr.puts(" #{pre} object_id: #{object_id}") stderr.puts(" #{pre} opts:") stderr.puts(" #{pre} #{@opts.inspect}") stderr.puts(" #{pre} frequency: #{self.frequency}") stderr.puts(" #{pre} scheduler_lock: #{@scheduler_lock.inspect}") stderr.puts(" #{pre} trigger_lock: #{@trigger_lock.inspect}") stderr.puts(" #{pre} uptime: #{uptime} (#{uptime_s})") stderr.puts(" #{pre} down?: #{down?}") stderr.puts(" #{pre} threads: #{self.threads.size}") stderr.puts(" #{pre} thread: #{self.thread}") stderr.puts(" #{pre} thread_key: #{self.thread_key}") stderr.puts(" #{pre} work_threads: #{work_threads.size}") stderr.puts(" #{pre} active: #{work_threads(:active).size}") stderr.puts(" #{pre} vacant: #{work_threads(:vacant).size}") stderr.puts(" #{pre} max_work_threads: #{max_work_threads}") stderr.puts(" #{pre} mutexes: #{ms.inspect}") stderr.puts(" #{pre} jobs: #{jobs.size}") stderr.puts(" #{pre} at_jobs: #{at_jobs.size}") stderr.puts(" #{pre} in_jobs: #{in_jobs.size}") stderr.puts(" #{pre} every_jobs: #{every_jobs.size}") stderr.puts(" #{pre} interval_jobs: #{interval_jobs.size}") stderr.puts(" #{pre} cron_jobs: #{cron_jobs.size}") stderr.puts(" #{pre} running_jobs: #{running_jobs.size}") stderr.puts(" #{pre} work_queue: #{work_queue.size}") stderr.puts("} #{pre} .") rescue => e stderr.puts("failure in #on_error itself:") stderr.puts(e.inspect) stderr.puts(e.backtrace) ensure stderr.flush end |
#pause ⇒ Object
189 190 191 192 |
# File 'lib/rufus/scheduler.rb', line 189 def pause @paused = true end |
#paused? ⇒ Boolean
184 185 186 187 |
# File 'lib/rufus/scheduler.rb', line 184 def paused? @paused end |
#repeat(arg, callable = nil, opts = {}, &block) ⇒ Object
264 265 266 267 268 269 270 271 272 |
# File 'lib/rufus/scheduler.rb', line 264 def repeat(arg, callable=nil, opts={}, &block) opts[:_t] = Scheduler.parse(arg, opts) case opts[:_t] when CronLine then schedule_cron(arg, callable, opts, &block) else schedule_every(arg, callable, opts, &block) end end |
#resume ⇒ Object
194 195 196 197 |
# File 'lib/rufus/scheduler.rb', line 194 def resume @paused = false end |
#running_jobs(opts = {}) ⇒ Object
427 428 429 430 |
# File 'lib/rufus/scheduler.rb', line 427 def running_jobs(opts={}) jobs(opts.merge(:running => true)) end |
#schedule(arg, callable = nil, opts = {}, &block) ⇒ Object
253 254 255 256 257 258 259 260 261 262 |
# File 'lib/rufus/scheduler.rb', line 253 def schedule(arg, callable=nil, opts={}, &block) opts[:_t] = Scheduler.parse(arg, opts) case opts[:_t] when CronLine then schedule_cron(arg, callable, opts, &block) when Time then schedule_at(arg, callable, opts, &block) else schedule_in(arg, callable, opts, &block) end end |
#schedule_at(time, callable = nil, opts = {}, &block) ⇒ Object
208 209 210 211 |
# File 'lib/rufus/scheduler.rb', line 208 def schedule_at(time, callable=nil, opts={}, &block) do_schedule(:once, time, callable, opts, true, block) end |
#schedule_cron(cronline, callable = nil, opts = {}, &block) ⇒ Object
248 249 250 251 |
# File 'lib/rufus/scheduler.rb', line 248 def schedule_cron(cronline, callable=nil, opts={}, &block) do_schedule(:cron, cronline, callable, opts, true, block) end |
#schedule_every(duration, callable = nil, opts = {}, &block) ⇒ Object
228 229 230 231 |
# File 'lib/rufus/scheduler.rb', line 228 def schedule_every(duration, callable=nil, opts={}, &block) do_schedule(:every, duration, callable, opts, true, block) end |
#schedule_in(duration, callable = nil, opts = {}, &block) ⇒ Object
218 219 220 221 |
# File 'lib/rufus/scheduler.rb', line 218 def schedule_in(duration, callable=nil, opts={}, &block) do_schedule(:once, duration, callable, opts, true, block) end |
#schedule_interval(duration, callable = nil, opts = {}, &block) ⇒ Object
238 239 240 241 |
# File 'lib/rufus/scheduler.rb', line 238 def schedule_interval(duration, callable=nil, opts={}, &block) do_schedule(:interval, duration, callable, opts, true, block) end |
#scheduled?(job_or_job_id) ⇒ Boolean
Returns true if this job is currently scheduled.
Takes extra care to answer true if the job is a repeat job currently firing.
386 387 388 389 390 391 |
# File 'lib/rufus/scheduler.rb', line 386 def scheduled?(job_or_job_id) job, job_id = fetch(job_or_job_id) !! (job && job.unscheduled_at.nil? && job.next_time != nil) end |
#shutdown(opt = nil) ⇒ Object Also known as: stop
134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/rufus/scheduler.rb', line 134 def shutdown(opt=nil) @started_at = nil #jobs.each { |j| j.unschedule } # provokes https://github.com/jmettraux/rufus-scheduler/issue/98 @jobs.array.each { |j| j.unschedule } @work_queue.clear if opt == :wait join_all_work_threads elsif opt == :kill kill_all_work_threads end unlock end |
#threads ⇒ Object
Lists all the threads associated with this scheduler.
395 396 397 398 |
# File 'lib/rufus/scheduler.rb', line 395 def threads Thread.list.select { |t| t[thread_key] } end |
#timeline(time0, time1) ⇒ Object
450 451 452 453 |
# File 'lib/rufus/scheduler.rb', line 450 def timeline(time0, time1) occurrences(time0, time1, :timeline) end |
#unlock ⇒ Object
Sister method to #lock, is called when the scheduler shuts down.
366 367 368 369 370 |
# File 'lib/rufus/scheduler.rb', line 366 def unlock @trigger_lock.unlock @scheduler_lock.unlock end |
#unschedule(job_or_job_id) ⇒ Object
274 275 276 277 278 279 280 281 |
# File 'lib/rufus/scheduler.rb', line 274 def unschedule(job_or_job_id) job, job_id = fetch(job_or_job_id) fail ArgumentError.new("no job found with id '#{job_id}'") unless job job.unschedule if job end |
#up? ⇒ Boolean
179 180 181 182 |
# File 'lib/rufus/scheduler.rb', line 179 def up? !! @started_at end |
#uptime ⇒ Object
155 156 157 158 |
# File 'lib/rufus/scheduler.rb', line 155 def uptime @started_at ? Time.now - @started_at : nil end |
#uptime_s ⇒ Object
160 161 162 163 |
# File 'lib/rufus/scheduler.rb', line 160 def uptime_s self.class.to_duration(uptime) end |
#work_threads(query = :all) ⇒ Object
Lists all the work threads (the ones actually running the scheduled block code)
Accepts a query option, which can be set to:
-
:all (default), returns all the threads that are work threads or are currently running a job
-
:active, returns all threads that are currenly running a job
-
:vacant, returns the threads that are not running a job
If, thanks to :blocking => true, a job is scheduled to monopolize the main scheduler thread, that thread will get returned when :active or :all.
413 414 415 416 417 418 419 420 421 422 423 424 425 |
# File 'lib/rufus/scheduler.rb', line 413 def work_threads(query=:all) ts = threads.select { |t| t[:rufus_scheduler_job] || t[:rufus_scheduler_work_thread] } case query when :active then ts.select { |t| t[:rufus_scheduler_job] } when :vacant then ts.reject { |t| t[:rufus_scheduler_job] } else ts end end |