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.
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