engineyard-serverside 1.5.23.ruby19.8 → 1.5.23.ruby19.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/lib/engineyard-serverside.rb +3 -1
  2. data/lib/engineyard-serverside/cli.rb +11 -19
  3. data/lib/engineyard-serverside/deploy.rb +3 -3
  4. data/lib/engineyard-serverside/future.rb +33 -0
  5. data/lib/engineyard-serverside/futures/celluloid.rb +25 -0
  6. data/lib/engineyard-serverside/futures/dataflow.rb +25 -0
  7. data/lib/engineyard-serverside/logged_output.rb +8 -3
  8. data/lib/engineyard-serverside/task.rb +9 -12
  9. data/lib/engineyard-serverside/version.rb +1 -1
  10. data/lib/vendor/celluloid/lib/celluloid.rb +261 -0
  11. data/lib/vendor/celluloid/lib/celluloid/actor.rb +242 -0
  12. data/lib/vendor/celluloid/lib/celluloid/actor_pool.rb +54 -0
  13. data/lib/vendor/celluloid/lib/celluloid/actor_proxy.rb +75 -0
  14. data/lib/vendor/celluloid/lib/celluloid/application.rb +78 -0
  15. data/lib/vendor/celluloid/lib/celluloid/calls.rb +94 -0
  16. data/lib/vendor/celluloid/lib/celluloid/core_ext.rb +14 -0
  17. data/lib/vendor/celluloid/lib/celluloid/events.rb +14 -0
  18. data/lib/vendor/celluloid/lib/celluloid/fiber.rb +33 -0
  19. data/lib/vendor/celluloid/lib/celluloid/fsm.rb +141 -0
  20. data/lib/vendor/celluloid/lib/celluloid/future.rb +60 -0
  21. data/lib/vendor/celluloid/lib/celluloid/links.rb +61 -0
  22. data/lib/vendor/celluloid/lib/celluloid/logger.rb +32 -0
  23. data/lib/vendor/celluloid/lib/celluloid/mailbox.rb +124 -0
  24. data/lib/vendor/celluloid/lib/celluloid/receivers.rb +66 -0
  25. data/lib/vendor/celluloid/lib/celluloid/registry.rb +33 -0
  26. data/lib/vendor/celluloid/lib/celluloid/responses.rb +26 -0
  27. data/lib/vendor/celluloid/lib/celluloid/rspec.rb +2 -0
  28. data/lib/vendor/celluloid/lib/celluloid/signals.rb +50 -0
  29. data/lib/vendor/celluloid/lib/celluloid/supervisor.rb +57 -0
  30. data/lib/vendor/celluloid/lib/celluloid/task.rb +73 -0
  31. data/lib/vendor/celluloid/lib/celluloid/tcp_server.rb +33 -0
  32. data/lib/vendor/celluloid/lib/celluloid/timers.rb +109 -0
  33. data/lib/vendor/celluloid/lib/celluloid/version.rb +4 -0
  34. data/lib/vendor/dataflow/dataflow.rb +124 -0
  35. data/lib/vendor/dataflow/dataflow/actor.rb +22 -0
  36. data/lib/vendor/dataflow/dataflow/equality.rb +44 -0
  37. data/lib/vendor/dataflow/dataflow/future_queue.rb +24 -0
  38. data/lib/vendor/dataflow/dataflow/port.rb +54 -0
  39. data/lib/vendor/open4/lib/open4.rb +432 -0
  40. data/lib/vendor/thor/lib/thor.rb +244 -0
  41. data/lib/vendor/thor/lib/thor/actions.rb +275 -0
  42. data/lib/vendor/thor/lib/thor/actions/create_file.rb +103 -0
  43. data/lib/vendor/thor/lib/thor/actions/directory.rb +91 -0
  44. data/lib/vendor/thor/lib/thor/actions/empty_directory.rb +134 -0
  45. data/lib/vendor/thor/lib/thor/actions/file_manipulation.rb +223 -0
  46. data/lib/vendor/thor/lib/thor/actions/inject_into_file.rb +104 -0
  47. data/lib/vendor/thor/lib/thor/base.rb +540 -0
  48. data/lib/vendor/thor/lib/thor/core_ext/file_binary_read.rb +9 -0
  49. data/lib/vendor/thor/lib/thor/core_ext/hash_with_indifferent_access.rb +75 -0
  50. data/lib/vendor/thor/lib/thor/core_ext/ordered_hash.rb +100 -0
  51. data/lib/vendor/thor/lib/thor/error.rb +30 -0
  52. data/lib/vendor/thor/lib/thor/group.rb +271 -0
  53. data/lib/vendor/thor/lib/thor/invocation.rb +180 -0
  54. data/lib/vendor/thor/lib/thor/parser.rb +4 -0
  55. data/lib/vendor/thor/lib/thor/parser/argument.rb +67 -0
  56. data/lib/vendor/thor/lib/thor/parser/arguments.rb +150 -0
  57. data/lib/vendor/thor/lib/thor/parser/option.rb +128 -0
  58. data/lib/vendor/thor/lib/thor/parser/options.rb +169 -0
  59. data/lib/vendor/thor/lib/thor/rake_compat.rb +66 -0
  60. data/lib/vendor/thor/lib/thor/runner.rb +314 -0
  61. data/lib/vendor/thor/lib/thor/shell.rb +83 -0
  62. data/lib/vendor/thor/lib/thor/shell/basic.rb +239 -0
  63. data/lib/vendor/thor/lib/thor/shell/color.rb +108 -0
  64. data/lib/vendor/thor/lib/thor/task.rb +102 -0
  65. data/lib/vendor/thor/lib/thor/util.rb +230 -0
  66. data/lib/vendor/thor/lib/thor/version.rb +3 -0
  67. 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