Class: Scheduler

Inherits:
Object
  • Object
show all
Includes:
Enumerable, Log::Comfort
Defined in:
lib/scheduler.rb

Overview

Indexing

Author: Stefan Rusterholz Contact: [email protected]> Version: 1.0.0 Date: 2007-10-12

About

Provides methods to execute scheduled Events

Synopsis

scheduler = Dispatcher::Scheduled.new(*events)
scheduler.every 5.minutes do puts "Another 5 minutes wasted!" end
scheduler.add(event)
scheduler.delete(event)
scheduler.suspend
scheduler.resume
scheduler.terminate # important, else you'll have a forever sleeping thread left

Instance Attribute Summary

Attributes included from Log::Comfort

#logger

Instance Method Summary collapse

Methods included from Enumerable

#join

Methods included from Log::Comfort

#debug, #error, #exception, #fail, #info, #log, #warn

Constructor Details

#initialize(delete_finished = true, *events) ⇒ Scheduler

Arguments

  • delete_finished: if true, it will remove elements from #events once they’re done

  • *events: events to schedule



41
42
43
44
45
46
47
48
49
50
51
52
53
# File 'lib/scheduler.rb', line 41

def initialize(delete_finished=true, *events)
	events.each { |event| event.scheduler = self }
	@terminated   = false
	@instructions = Queue.new
	@mutex        = Mutex.new
	@events       = []
	@alarm        = Thread.new {} # dead thread
	@min_sleep    = 0.1
	@execute      = method(:execute)
	@sleeper      = Thread.new(&method(:sleeper))
	@auto_delete  = delete_finished
	add(*events)
end

Instance Method Details

#add(*events) ⇒ Object Also known as: <<

Adds the events to the scheduler



118
119
120
121
122
123
124
125
126
127
# File 'lib/scheduler.rb', line 118

def add(*events)
	events.each { |event| event.scheduler = self }
	@instructions.push(:reschedule) if @mutex.synchronize {
		first = @events.first
		@events.push(*events)
		@events.sort!
		first != @events.first
	}
	self
end

#at(*args, &block) ⇒ Object

Creates a new Dispatcher::Event.timed, adds it and returns the event



170
171
172
173
# File 'lib/scheduler.rb', line 170

def at(*args, &block)
	add(event = Event::At.new(*args, &block))
	event
end

#delete(event) ⇒ Object



130
131
132
133
134
135
136
137
# File 'lib/scheduler.rb', line 130

def delete(event)
	wakeup = false
	@mutex.synchronize {
		wakeup = @events.first == event
		@events.delete(event)
	}
	@instructions.push(:reschedule) if wakeup
end

#every(*args, &block) ⇒ Object

Creates a new Dispatcher::Event.every, adds it and returns the event



156
157
158
159
# File 'lib/scheduler.rb', line 156

def every(*args, &block)
	add(event = Event::Every.new(*args, &block))
	event
end

#execute(event) ⇒ Object



148
149
150
151
152
# File 'lib/scheduler.rb', line 148

def execute(event)
	event.call(event)
rescue Exception => e
	exception(e) # log it
end

#lengthObject

The amount of scheduled events



176
177
178
# File 'lib/scheduler.rb', line 176

def length
	@events.length
end

#reject!(&block) ⇒ Object



139
140
141
142
143
144
145
146
# File 'lib/scheduler.rb', line 139

def reject!(&block)
	@instructions.push(:reschedule) if @mutex.synchronize {
		first = @events.first
		@events.reject!(&block)
		@events.min
		first != @events.first
	}
end

#reschedule(event) ⇒ Object

Tell the Scheduler to update its scheduling regardings this event This should not be necessary if your event is properly linked to the scheduler (the event is supposed to do that by itself).



107
108
109
110
111
112
113
114
115
# File 'lib/scheduler.rb', line 107

def reschedule(event)
	@mutex.synchronize {
		#first = @events.first
		@events.sort!
		#first != @events.first
	}
	@instructions.push(:reschedule)
	self
end

#restartObject

not yet implemented



97
98
# File 'lib/scheduler.rb', line 97

def restart
end

#resumeObject

not yet implemented



93
94
# File 'lib/scheduler.rb', line 93

def resume
end

#sleeperObject

Handles the events and invokes them when due.



56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/scheduler.rb', line 56

def sleeper # :nodoc:
	while instr = @instructions.shift
		@alarm.kill # just overkill...

		now = Time.now+@min_sleep
		@mutex.synchronize {
			i = nil
			@events.each_with_index { |event,i|
				break unless event.due?(now)
				event.one_done
				Thread.new(event, &@execute)
			}
			@events.first(i+1).each { |event|
				@events.delete(event) if event.finished?
			} if (@auto_delete && i)
			unless @events.empty?
				@events.sort!
				if seconds = @events.first.seconds_left then
					if seconds < @min_sleep then
						@instructions.push(:wakeup)
					else
						@alarm = Thread.new {
							sleep(seconds)
							@instructions.push(:wakeup)
						}
					end
				end
			end
		}
	end
end

#suspendObject

not yet implemented



89
90
# File 'lib/scheduler.rb', line 89

def suspend
end

#terminateObject

not yet implemented



101
102
# File 'lib/scheduler.rb', line 101

def terminate
end

#timed(*args, &block) ⇒ Object

Creates a new Dispatcher::Event.timed, adds it and returns the event



163
164
165
166
# File 'lib/scheduler.rb', line 163

def timed(*args, &block)
	add(event = Event::Timed.new(*args, &block))
	event
end