engineyard-serverside 1.5.23.ruby19.8 → 1.5.23.ruby19.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/engineyard-serverside.rb +3 -1
- data/lib/engineyard-serverside/cli.rb +11 -19
- data/lib/engineyard-serverside/deploy.rb +3 -3
- data/lib/engineyard-serverside/future.rb +33 -0
- data/lib/engineyard-serverside/futures/celluloid.rb +25 -0
- data/lib/engineyard-serverside/futures/dataflow.rb +25 -0
- data/lib/engineyard-serverside/logged_output.rb +8 -3
- data/lib/engineyard-serverside/task.rb +9 -12
- data/lib/engineyard-serverside/version.rb +1 -1
- data/lib/vendor/celluloid/lib/celluloid.rb +261 -0
- data/lib/vendor/celluloid/lib/celluloid/actor.rb +242 -0
- data/lib/vendor/celluloid/lib/celluloid/actor_pool.rb +54 -0
- data/lib/vendor/celluloid/lib/celluloid/actor_proxy.rb +75 -0
- data/lib/vendor/celluloid/lib/celluloid/application.rb +78 -0
- data/lib/vendor/celluloid/lib/celluloid/calls.rb +94 -0
- data/lib/vendor/celluloid/lib/celluloid/core_ext.rb +14 -0
- data/lib/vendor/celluloid/lib/celluloid/events.rb +14 -0
- data/lib/vendor/celluloid/lib/celluloid/fiber.rb +33 -0
- data/lib/vendor/celluloid/lib/celluloid/fsm.rb +141 -0
- data/lib/vendor/celluloid/lib/celluloid/future.rb +60 -0
- data/lib/vendor/celluloid/lib/celluloid/links.rb +61 -0
- data/lib/vendor/celluloid/lib/celluloid/logger.rb +32 -0
- data/lib/vendor/celluloid/lib/celluloid/mailbox.rb +124 -0
- data/lib/vendor/celluloid/lib/celluloid/receivers.rb +66 -0
- data/lib/vendor/celluloid/lib/celluloid/registry.rb +33 -0
- data/lib/vendor/celluloid/lib/celluloid/responses.rb +26 -0
- data/lib/vendor/celluloid/lib/celluloid/rspec.rb +2 -0
- data/lib/vendor/celluloid/lib/celluloid/signals.rb +50 -0
- data/lib/vendor/celluloid/lib/celluloid/supervisor.rb +57 -0
- data/lib/vendor/celluloid/lib/celluloid/task.rb +73 -0
- data/lib/vendor/celluloid/lib/celluloid/tcp_server.rb +33 -0
- data/lib/vendor/celluloid/lib/celluloid/timers.rb +109 -0
- data/lib/vendor/celluloid/lib/celluloid/version.rb +4 -0
- data/lib/vendor/dataflow/dataflow.rb +124 -0
- data/lib/vendor/dataflow/dataflow/actor.rb +22 -0
- data/lib/vendor/dataflow/dataflow/equality.rb +44 -0
- data/lib/vendor/dataflow/dataflow/future_queue.rb +24 -0
- data/lib/vendor/dataflow/dataflow/port.rb +54 -0
- data/lib/vendor/open4/lib/open4.rb +432 -0
- data/lib/vendor/thor/lib/thor.rb +244 -0
- data/lib/vendor/thor/lib/thor/actions.rb +275 -0
- data/lib/vendor/thor/lib/thor/actions/create_file.rb +103 -0
- data/lib/vendor/thor/lib/thor/actions/directory.rb +91 -0
- data/lib/vendor/thor/lib/thor/actions/empty_directory.rb +134 -0
- data/lib/vendor/thor/lib/thor/actions/file_manipulation.rb +223 -0
- data/lib/vendor/thor/lib/thor/actions/inject_into_file.rb +104 -0
- data/lib/vendor/thor/lib/thor/base.rb +540 -0
- data/lib/vendor/thor/lib/thor/core_ext/file_binary_read.rb +9 -0
- data/lib/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +75 -0
- data/lib/vendor/thor/lib/thor/core_ext/ordered_hash.rb +100 -0
- data/lib/vendor/thor/lib/thor/error.rb +30 -0
- data/lib/vendor/thor/lib/thor/group.rb +271 -0
- data/lib/vendor/thor/lib/thor/invocation.rb +180 -0
- data/lib/vendor/thor/lib/thor/parser.rb +4 -0
- data/lib/vendor/thor/lib/thor/parser/argument.rb +67 -0
- data/lib/vendor/thor/lib/thor/parser/arguments.rb +150 -0
- data/lib/vendor/thor/lib/thor/parser/option.rb +128 -0
- data/lib/vendor/thor/lib/thor/parser/options.rb +169 -0
- data/lib/vendor/thor/lib/thor/rake_compat.rb +66 -0
- data/lib/vendor/thor/lib/thor/runner.rb +314 -0
- data/lib/vendor/thor/lib/thor/shell.rb +83 -0
- data/lib/vendor/thor/lib/thor/shell/basic.rb +239 -0
- data/lib/vendor/thor/lib/thor/shell/color.rb +108 -0
- data/lib/vendor/thor/lib/thor/task.rb +102 -0
- data/lib/vendor/thor/lib/thor/util.rb +230 -0
- data/lib/vendor/thor/lib/thor/version.rb +3 -0
- metadata +70 -10
@@ -0,0 +1,242 @@
|
|
1
|
+
module Celluloid
|
2
|
+
# Don't do Actor-like things outside Actor scope
|
3
|
+
class NotActorError < StandardError; end
|
4
|
+
|
5
|
+
# Trying to do something to a dead actor
|
6
|
+
class DeadActorError < StandardError; end
|
7
|
+
|
8
|
+
# The caller made an error, not the current actor
|
9
|
+
class AbortError < StandardError
|
10
|
+
attr_reader :cause
|
11
|
+
|
12
|
+
def initialize(cause)
|
13
|
+
@cause = cause
|
14
|
+
super "caused by #{cause.inspect}: #{cause.to_s}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Actors are Celluloid's concurrency primitive. They're implemented as
|
19
|
+
# normal Ruby objects wrapped in threads which communicate with asynchronous
|
20
|
+
# messages.
|
21
|
+
class Actor
|
22
|
+
extend Registry
|
23
|
+
|
24
|
+
attr_reader :proxy
|
25
|
+
attr_reader :links
|
26
|
+
attr_reader :mailbox
|
27
|
+
|
28
|
+
# Invoke a method on the given actor via its mailbox
|
29
|
+
def self.call(mailbox, meth, *args, &block)
|
30
|
+
call = SyncCall.new(Thread.mailbox, meth, args, block)
|
31
|
+
|
32
|
+
begin
|
33
|
+
mailbox << call
|
34
|
+
rescue MailboxError
|
35
|
+
raise DeadActorError, "attempted to call a dead actor"
|
36
|
+
end
|
37
|
+
|
38
|
+
if Celluloid.actor?
|
39
|
+
response = Thread.current[:actor].wait [:call, call.id]
|
40
|
+
else
|
41
|
+
# Otherwise we're inside a normal thread, so block
|
42
|
+
response = Thread.mailbox.receive do |msg|
|
43
|
+
msg.respond_to?(:call_id) and msg.call_id == call.id
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
response.value
|
48
|
+
end
|
49
|
+
|
50
|
+
# Invoke a method asynchronously on an actor via its mailbox
|
51
|
+
def self.async(mailbox, meth, *args, &block)
|
52
|
+
begin
|
53
|
+
mailbox << AsyncCall.new(Thread.mailbox, meth, args, block)
|
54
|
+
rescue MailboxError
|
55
|
+
# Silently swallow asynchronous calls to dead actors. There's no way
|
56
|
+
# to reliably generate DeadActorErrors for async calls, so users of
|
57
|
+
# async calls should find other ways to deal with actors dying
|
58
|
+
# during an async call (i.e. linking/supervisors)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Wrap the given subject with an Actor
|
63
|
+
def initialize(subject)
|
64
|
+
@subject = subject
|
65
|
+
|
66
|
+
if subject.respond_to? :mailbox_factory
|
67
|
+
@mailbox = subject.mailbox_factory
|
68
|
+
else
|
69
|
+
@mailbox = Mailbox.new
|
70
|
+
end
|
71
|
+
|
72
|
+
@links = Links.new
|
73
|
+
@signals = Signals.new
|
74
|
+
@receivers = Receivers.new
|
75
|
+
@timers = Timers.new
|
76
|
+
@proxy = ActorProxy.new(@mailbox, self.class.to_s)
|
77
|
+
@running = true
|
78
|
+
|
79
|
+
@thread = Pool.get do
|
80
|
+
Thread.current[:actor] = self
|
81
|
+
Thread.current[:mailbox] = @mailbox
|
82
|
+
|
83
|
+
run
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
# Is this actor alive?
|
88
|
+
def alive?
|
89
|
+
@running
|
90
|
+
end
|
91
|
+
|
92
|
+
# Terminate this actor
|
93
|
+
def terminate
|
94
|
+
@running = false
|
95
|
+
nil
|
96
|
+
end
|
97
|
+
|
98
|
+
# Send a signal with the given name to all waiting methods
|
99
|
+
def signal(name, value = nil)
|
100
|
+
@signals.send name, value
|
101
|
+
end
|
102
|
+
|
103
|
+
# Wait for the given signal
|
104
|
+
def wait(name)
|
105
|
+
@signals.wait name
|
106
|
+
end
|
107
|
+
|
108
|
+
# Receive an asynchronous message
|
109
|
+
def receive(timeout = nil, &block)
|
110
|
+
@receivers.receive(timeout, &block)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Run the actor loop
|
114
|
+
def run
|
115
|
+
while @running
|
116
|
+
begin
|
117
|
+
message = @mailbox.receive(timeout)
|
118
|
+
rescue ExitEvent => exit_event
|
119
|
+
Task.new(:exit_handler) { handle_exit_event exit_event }.resume
|
120
|
+
retry
|
121
|
+
end
|
122
|
+
|
123
|
+
if message
|
124
|
+
handle_message message
|
125
|
+
else
|
126
|
+
# No message indicates a timeout
|
127
|
+
@timers.fire
|
128
|
+
@receivers.fire_timers
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
cleanup ExitEvent.new(@proxy)
|
133
|
+
rescue MailboxShutdown
|
134
|
+
# If the mailbox detects shutdown, exit the actor
|
135
|
+
@running = false
|
136
|
+
rescue Exception => ex
|
137
|
+
@running = false
|
138
|
+
handle_crash(ex)
|
139
|
+
ensure
|
140
|
+
Pool.put @thread
|
141
|
+
end
|
142
|
+
|
143
|
+
# How long to wait until the next timer fires
|
144
|
+
def timeout
|
145
|
+
i1 = @timers.wait_interval
|
146
|
+
i2 = @receivers.wait_interval
|
147
|
+
|
148
|
+
if i1 and i2
|
149
|
+
i1 < i2 ? i1 : i2
|
150
|
+
elsif i1
|
151
|
+
i1
|
152
|
+
else
|
153
|
+
i2
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
# Obtain a hash of tasks that are currently waiting
|
158
|
+
def tasks
|
159
|
+
# A hash of tasks to what they're waiting on is more meaningful to the
|
160
|
+
# end-user, and lets us make a copy of the tasks table, rather than
|
161
|
+
# handing them the one we're using internally across threads, a definite
|
162
|
+
# thread safety shared state no-no
|
163
|
+
tasks = {}
|
164
|
+
current_task = Task.current rescue nil
|
165
|
+
tasks[current_task] = :running if current_task
|
166
|
+
|
167
|
+
@signals.waiting.each do |waitable, waiters|
|
168
|
+
if waiters.is_a? Enumerable
|
169
|
+
waiters.each { |waiter| tasks[waiter] = waitable }
|
170
|
+
else
|
171
|
+
tasks[waiters] = waitable
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
tasks
|
176
|
+
end
|
177
|
+
|
178
|
+
# Schedule a block to run at the given time
|
179
|
+
def after(interval)
|
180
|
+
@timers.add(interval) do
|
181
|
+
Task.new(:timer) { yield }.resume
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
# Sleep for the given amount of time
|
186
|
+
def sleep(interval)
|
187
|
+
task = Task.current
|
188
|
+
@timers.add(interval) { task.resume }
|
189
|
+
Task.suspend
|
190
|
+
end
|
191
|
+
|
192
|
+
# Handle an incoming message
|
193
|
+
def handle_message(message)
|
194
|
+
case message
|
195
|
+
when Call
|
196
|
+
Task.new(:message_handler) { message.dispatch(@subject) }.resume
|
197
|
+
when Response
|
198
|
+
handled_successfully = signal [:call, message.call_id], message
|
199
|
+
|
200
|
+
unless handled_successfully
|
201
|
+
Logger.debug("anomalous message! spurious response to call #{message.call_id}")
|
202
|
+
end
|
203
|
+
else
|
204
|
+
@receivers.handle_message(message)
|
205
|
+
end
|
206
|
+
message
|
207
|
+
end
|
208
|
+
|
209
|
+
# Handle exit events received by this actor
|
210
|
+
def handle_exit_event(exit_event)
|
211
|
+
exit_handler = @subject.class.exit_handler
|
212
|
+
if exit_handler
|
213
|
+
return @subject.send(exit_handler, exit_event.actor, exit_event.reason)
|
214
|
+
end
|
215
|
+
|
216
|
+
# Reraise exceptions from linked actors
|
217
|
+
# If no reason is given, actor terminated cleanly
|
218
|
+
raise exit_event.reason if exit_event.reason
|
219
|
+
end
|
220
|
+
|
221
|
+
# Handle any exceptions that occur within a running actor
|
222
|
+
def handle_crash(exception)
|
223
|
+
Logger.crash("#{@subject.class} crashed!", exception)
|
224
|
+
cleanup ExitEvent.new(@proxy, exception)
|
225
|
+
rescue Exception => ex
|
226
|
+
Logger.crash("#{@subject.class}: ERROR HANDLER CRASHED!", ex)
|
227
|
+
end
|
228
|
+
|
229
|
+
# Handle cleaning up this actor after it exits
|
230
|
+
def cleanup(exit_event)
|
231
|
+
@mailbox.shutdown
|
232
|
+
@links.send_event exit_event
|
233
|
+
tasks.each { |task, _| task.terminate }
|
234
|
+
|
235
|
+
begin
|
236
|
+
@subject.finalize if @subject.respond_to? :finalize
|
237
|
+
rescue Exception => ex
|
238
|
+
Logger.crash("#{@subject.class}#finalize crashed!", ex)
|
239
|
+
end
|
240
|
+
end
|
241
|
+
end
|
242
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'thread'
|
2
|
+
|
3
|
+
module Celluloid
|
4
|
+
class Actor
|
5
|
+
# Maintain a thread pool of actors FOR SPEED!!
|
6
|
+
class Pool
|
7
|
+
@pool = []
|
8
|
+
@lock = Mutex.new
|
9
|
+
@max_idle = 16
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_accessor :max_idle
|
13
|
+
|
14
|
+
def get(&block)
|
15
|
+
@lock.synchronize do
|
16
|
+
if @pool.empty?
|
17
|
+
thread = create
|
18
|
+
else
|
19
|
+
thread = @pool.shift
|
20
|
+
end
|
21
|
+
|
22
|
+
thread[:queue] << block
|
23
|
+
thread
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def put(thread)
|
28
|
+
@lock.synchronize do
|
29
|
+
if @pool.size >= @max_idle
|
30
|
+
thread[:queue] << nil
|
31
|
+
else
|
32
|
+
@pool << thread
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def create
|
38
|
+
queue = Queue.new
|
39
|
+
thread = Thread.new do
|
40
|
+
begin
|
41
|
+
while func = queue.pop
|
42
|
+
func.call
|
43
|
+
end
|
44
|
+
rescue Exception => ex
|
45
|
+
Logger.crash("#{self} internal failure", ex)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
thread[:queue] = queue
|
49
|
+
thread
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module Celluloid
|
2
|
+
# A proxy object returned from Celluloid::Actor.spawn/spawn_link which
|
3
|
+
# dispatches calls and casts to normal Ruby objects which are running inside
|
4
|
+
# of their own threads.
|
5
|
+
class ActorProxy
|
6
|
+
attr_reader :mailbox
|
7
|
+
|
8
|
+
def initialize(mailbox, klass = "Object")
|
9
|
+
@mailbox, @klass = mailbox, klass
|
10
|
+
end
|
11
|
+
|
12
|
+
def send(meth, *args, &block)
|
13
|
+
Actor.call @mailbox, :send, meth, *args, &block
|
14
|
+
end
|
15
|
+
|
16
|
+
def class
|
17
|
+
Actor.call @mailbox, :send, :class
|
18
|
+
end
|
19
|
+
|
20
|
+
def respond_to?(meth)
|
21
|
+
Actor.call @mailbox, :respond_to?, meth
|
22
|
+
end
|
23
|
+
|
24
|
+
def methods(include_ancestors = true)
|
25
|
+
Actor.call @mailbox, :methods, include_ancestors
|
26
|
+
end
|
27
|
+
|
28
|
+
def alive?
|
29
|
+
@mailbox.alive?
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_s
|
33
|
+
Actor.call @mailbox, :to_s
|
34
|
+
end
|
35
|
+
|
36
|
+
def inspect
|
37
|
+
Actor.call @mailbox, :inspect
|
38
|
+
rescue DeadActorError
|
39
|
+
"#<Celluloid::Actor(#{@klass}) dead>"
|
40
|
+
end
|
41
|
+
|
42
|
+
# Create a Celluloid::Future which calls a given method
|
43
|
+
def future(method_name, *args, &block)
|
44
|
+
Future.new { Actor.call @mailbox, method_name, *args, &block }
|
45
|
+
end
|
46
|
+
|
47
|
+
# Terminate the associated actor
|
48
|
+
def terminate
|
49
|
+
raise DeadActorError, "actor already terminated" unless alive?
|
50
|
+
|
51
|
+
begin
|
52
|
+
send :terminate
|
53
|
+
rescue DeadActorError
|
54
|
+
# In certain cases this is thrown during termination. This is likely
|
55
|
+
# a bug in Celluloid's internals, but it shouldn't affect the caller.
|
56
|
+
# FIXME: track this down and fix it, or at the very least log it
|
57
|
+
end
|
58
|
+
|
59
|
+
# Always return nil until a dependable exit value can be obtained
|
60
|
+
nil
|
61
|
+
end
|
62
|
+
|
63
|
+
# method_missing black magic to call bang predicate methods asynchronously
|
64
|
+
def method_missing(meth, *args, &block)
|
65
|
+
# bang methods are async calls
|
66
|
+
if meth.to_s.match(/!$/)
|
67
|
+
unbanged_meth = meth.to_s.sub(/!$/, '')
|
68
|
+
Actor.async @mailbox, unbanged_meth, *args, &block
|
69
|
+
return
|
70
|
+
end
|
71
|
+
|
72
|
+
Actor.call @mailbox, meth, *args, &block
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
module Celluloid
|
2
|
+
# Applications describe and manage networks of Celluloid actors
|
3
|
+
class Application
|
4
|
+
include Celluloid
|
5
|
+
trap_exit :restart_supervisor
|
6
|
+
|
7
|
+
class << self
|
8
|
+
# Actors or sub-applications to be supervised
|
9
|
+
def supervisables
|
10
|
+
@supervisables ||= []
|
11
|
+
end
|
12
|
+
|
13
|
+
# Start this application (and watch it with a supervisor)
|
14
|
+
alias_method :run!, :supervise
|
15
|
+
|
16
|
+
# Run the application in the foreground with a simple watchdog
|
17
|
+
def run
|
18
|
+
loop do
|
19
|
+
supervisor = run!
|
20
|
+
|
21
|
+
# Take five, toplevel supervisor
|
22
|
+
sleep 5 while supervisor.alive?
|
23
|
+
|
24
|
+
Logger.error "!!! Celluloid::Application #{self} crashed. Restarting..."
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# Register an actor class or a sub-application class to be launched and
|
29
|
+
# supervised while this application is running. Available options are:
|
30
|
+
#
|
31
|
+
# * as: register this application in the Celluloid::Actor[] directory
|
32
|
+
# * args: start the actor with the given arguments
|
33
|
+
def supervise(klass, options = {})
|
34
|
+
supervisables << Supervisable.new(klass, options)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Start the application
|
39
|
+
def initialize
|
40
|
+
@supervisors = {}
|
41
|
+
|
42
|
+
# This is some serious lolcode, but like... start the supervisors for
|
43
|
+
# this application
|
44
|
+
self.class.supervisables.each do |supervisable|
|
45
|
+
supervisor = supervisable.supervise
|
46
|
+
@supervisors[supervisor] = supervisable
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Restart a crashed supervisor
|
51
|
+
def restart_supervisor(supervisor, reason)
|
52
|
+
supervisable = @supervisors.delete supervisor
|
53
|
+
raise "a supervisable went missing. This shouldn't be!" unless supervisable
|
54
|
+
|
55
|
+
supervisor = supervisable.supervise
|
56
|
+
@supervisors[supervisor] = supervisable
|
57
|
+
end
|
58
|
+
|
59
|
+
# A subcomponent of an application to be supervised
|
60
|
+
class Supervisable
|
61
|
+
attr_reader :klass, :as, :args
|
62
|
+
|
63
|
+
def initialize(klass, options = {})
|
64
|
+
@klass = klass
|
65
|
+
|
66
|
+
# Stringify keys :/
|
67
|
+
options = options.inject({}) { |h,(k,v)| h[k.to_s] = v; h }
|
68
|
+
|
69
|
+
@as = options['as']
|
70
|
+
@args = options['args'] || []
|
71
|
+
end
|
72
|
+
|
73
|
+
def supervise
|
74
|
+
Supervisor.new_link(@as, @klass, *@args)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|