celluloid 0.18.0.pre → 0.18.0

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 (177) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGES.md +258 -39
  3. data/CONDUCT.md +13 -0
  4. data/CONTRIBUTING.md +39 -0
  5. data/README.md +54 -165
  6. data/REFACTOR.md +1 -0
  7. data/architecture.md +120 -0
  8. data/examples/basic_usage.rb +1 -1
  9. data/examples/configurations.rb +78 -0
  10. data/examples/futures.rb +1 -1
  11. data/examples/ring.rb +5 -4
  12. data/examples/simple_pmap.rb +1 -1
  13. data/examples/stack.rb +2 -2
  14. data/examples/supervisors_and_registry.rb +82 -0
  15. data/examples/timers.rb +2 -2
  16. data/lib/celluloid.rb +72 -47
  17. data/lib/celluloid/actor.rb +27 -17
  18. data/lib/celluloid/actor/system.rb +13 -29
  19. data/lib/celluloid/autostart.rb +5 -5
  20. data/lib/celluloid/call/async.rb +2 -0
  21. data/lib/celluloid/call/sync.rb +10 -3
  22. data/lib/celluloid/calls.rb +5 -12
  23. data/lib/celluloid/cell.rb +5 -9
  24. data/lib/celluloid/condition.rb +3 -3
  25. data/lib/celluloid/core_ext.rb +0 -2
  26. data/lib/celluloid/debug.rb +3 -0
  27. data/lib/celluloid/exceptions.rb +2 -2
  28. data/lib/celluloid/future.rb +7 -9
  29. data/lib/celluloid/group.rb +12 -8
  30. data/lib/celluloid/group/pool.rb +1 -3
  31. data/lib/celluloid/group/spawner.rb +2 -6
  32. data/lib/celluloid/internals/call_chain.rb +15 -0
  33. data/lib/celluloid/internals/cpu_counter.rb +62 -0
  34. data/lib/celluloid/internals/handlers.rb +42 -0
  35. data/lib/celluloid/internals/links.rb +38 -0
  36. data/lib/celluloid/internals/logger.rb +104 -0
  37. data/lib/celluloid/internals/method.rb +34 -0
  38. data/lib/celluloid/internals/properties.rb +32 -0
  39. data/lib/celluloid/internals/receivers.rb +64 -0
  40. data/lib/celluloid/internals/registry.rb +102 -0
  41. data/lib/celluloid/internals/responses.rb +46 -0
  42. data/lib/celluloid/internals/signals.rb +24 -0
  43. data/lib/celluloid/internals/stack.rb +74 -0
  44. data/lib/celluloid/internals/stack/dump.rb +12 -0
  45. data/lib/celluloid/internals/stack/states.rb +72 -0
  46. data/lib/celluloid/internals/stack/summary.rb +12 -0
  47. data/lib/celluloid/internals/task_set.rb +51 -0
  48. data/lib/celluloid/internals/thread_handle.rb +52 -0
  49. data/lib/celluloid/internals/uuid.rb +40 -0
  50. data/lib/celluloid/logging/incident.rb +21 -0
  51. data/lib/celluloid/logging/incident_logger.rb +147 -0
  52. data/lib/celluloid/logging/incident_reporter.rb +49 -0
  53. data/lib/celluloid/logging/log_event.rb +20 -0
  54. data/lib/celluloid/logging/ring_buffer.rb +64 -0
  55. data/lib/celluloid/mailbox.rb +22 -9
  56. data/lib/celluloid/mailbox/evented.rb +13 -5
  57. data/lib/celluloid/notifications.rb +95 -0
  58. data/lib/celluloid/pool.rb +6 -0
  59. data/lib/celluloid/probe.rb +81 -0
  60. data/lib/celluloid/proxy/abstract.rb +9 -9
  61. data/lib/celluloid/proxy/async.rb +1 -1
  62. data/lib/celluloid/proxy/block.rb +2 -2
  63. data/lib/celluloid/proxy/cell.rb +1 -1
  64. data/lib/celluloid/proxy/future.rb +2 -4
  65. data/lib/celluloid/proxy/sync.rb +1 -3
  66. data/lib/celluloid/rspec.rb +22 -33
  67. data/lib/celluloid/supervision.rb +17 -0
  68. data/lib/celluloid/supervision/configuration.rb +169 -0
  69. data/lib/celluloid/supervision/configuration/injections.rb +8 -0
  70. data/lib/celluloid/supervision/configuration/instance.rb +113 -0
  71. data/lib/celluloid/supervision/constants.rb +123 -0
  72. data/lib/celluloid/supervision/container.rb +144 -0
  73. data/lib/celluloid/supervision/container/behavior.rb +89 -0
  74. data/lib/celluloid/supervision/container/behavior/pool.rb +71 -0
  75. data/lib/celluloid/supervision/container/behavior/tree.rb +23 -0
  76. data/lib/celluloid/supervision/container/injections.rb +8 -0
  77. data/lib/celluloid/supervision/container/instance.rb +116 -0
  78. data/lib/celluloid/supervision/container/pool.rb +210 -0
  79. data/lib/celluloid/supervision/service.rb +27 -0
  80. data/lib/celluloid/supervision/supervise.rb +34 -0
  81. data/lib/celluloid/supervision/validation.rb +40 -0
  82. data/lib/celluloid/supervision/version.rb +5 -0
  83. data/lib/celluloid/system_events.rb +11 -6
  84. data/lib/celluloid/task.rb +25 -12
  85. data/lib/celluloid/task/fibered.rb +2 -0
  86. data/lib/celluloid/task/threaded.rb +3 -3
  87. data/lib/celluloid/test.rb +5 -2
  88. data/lib/celluloid/thread.rb +0 -2
  89. data/lib/celluloid/version.rb +1 -1
  90. data/spec/celluloid/block_spec.rb +29 -32
  91. data/spec/celluloid/calls_spec.rb +5 -15
  92. data/spec/celluloid/future_spec.rb +2 -2
  93. data/spec/celluloid/internals/cpu_counter_spec.rb +129 -0
  94. data/spec/celluloid/internals/links_spec.rb +43 -0
  95. data/spec/celluloid/internals/properties_spec.rb +40 -0
  96. data/spec/celluloid/internals/registry_spec.rb +62 -0
  97. data/spec/celluloid/internals/stack/dump_spec.rb +4 -0
  98. data/spec/celluloid/internals/stack/summary_spec.rb +4 -0
  99. data/spec/celluloid/internals/thread_handle_spec.rb +60 -0
  100. data/spec/celluloid/internals/uuid_spec.rb +9 -0
  101. data/spec/celluloid/logging/ring_buffer_spec.rb +36 -0
  102. data/spec/celluloid/mailbox/evented_spec.rb +11 -22
  103. data/spec/celluloid/misc/leak_spec.rb +3 -4
  104. data/spec/celluloid/notifications_spec.rb +140 -0
  105. data/spec/celluloid/probe_spec.rb +102 -0
  106. data/spec/celluloid/proxy_spec.rb +30 -30
  107. data/spec/celluloid/supervision/behavior_spec.rb +74 -0
  108. data/spec/celluloid/supervision/configuration_spec.rb +181 -0
  109. data/spec/celluloid/supervision/container_spec.rb +72 -0
  110. data/spec/celluloid/supervision/instance_spec.rb +13 -0
  111. data/spec/celluloid/supervision/root_spec.rb +28 -0
  112. data/spec/celluloid/supervision/supervisor_spec.rb +93 -0
  113. data/spec/celluloid/task/fibered_spec.rb +1 -3
  114. data/spec/celluloid/task/threaded_spec.rb +1 -3
  115. data/spec/shared/actor_examples.rb +58 -33
  116. data/spec/shared/group_examples.rb +2 -2
  117. data/spec/shared/mailbox_examples.rb +1 -1
  118. data/spec/shared/stack_examples.rb +87 -0
  119. data/spec/shared/task_examples.rb +2 -3
  120. data/spec/spec_helper.rb +2 -4
  121. data/spec/support/configure_rspec.rb +2 -3
  122. data/spec/support/coverage.rb +2 -4
  123. data/spec/support/crash_checking.rb +2 -2
  124. data/spec/support/examples/actor_class.rb +3 -8
  125. data/spec/support/examples/call_class.rb +2 -2
  126. data/spec/support/examples/container_class.rb +35 -0
  127. data/spec/support/examples/evented_mailbox_class.rb +1 -2
  128. data/spec/support/examples/stack_classes.rb +58 -0
  129. data/spec/support/examples/stack_methods.rb +23 -0
  130. data/spec/support/examples/subordinate_class.rb +19 -0
  131. data/spec/support/logging.rb +2 -34
  132. data/spec/support/loose_threads.rb +3 -16
  133. data/spec/support/reset_class_variables.rb +5 -1
  134. data/spec/support/stubbing.rb +1 -1
  135. metadata +91 -323
  136. data/culture/CONDUCT.md +0 -38
  137. data/culture/GSoC/1010-why_we_will_participate.md +0 -17
  138. data/culture/GSoC/1020-how_mentors_stay_engaged.md +0 -7
  139. data/culture/GSoC/1030-keeping_students_on_schedule.md +0 -9
  140. data/culture/GSoC/1040-getting_students_involved.md +0 -5
  141. data/culture/GSoC/1050-student_involvement_after.md +0 -5
  142. data/culture/GSoC/README.md +0 -16
  143. data/culture/Gemfile +0 -9
  144. data/culture/LICENSE.txt +0 -22
  145. data/culture/README.md +0 -22
  146. data/culture/Rakefile +0 -5
  147. data/culture/SYNC.md +0 -70
  148. data/culture/celluloid-culture.gemspec +0 -18
  149. data/culture/gems/README.md +0 -39
  150. data/culture/gems/dependencies.yml +0 -93
  151. data/culture/gems/loader.rb +0 -101
  152. data/culture/rubocop/README.md +0 -38
  153. data/culture/rubocop/lint.yml +0 -8
  154. data/culture/rubocop/metrics.yml +0 -15
  155. data/culture/rubocop/perf.yml +0 -0
  156. data/culture/rubocop/rubocop.yml +0 -5
  157. data/culture/rubocop/style.yml +0 -61
  158. data/culture/spec/gems_spec.rb +0 -2
  159. data/culture/spec/spec_helper.rb +0 -0
  160. data/culture/spec/sync_spec.rb +0 -2
  161. data/culture/sync.rb +0 -56
  162. data/culture/tasks/rspec.rake +0 -5
  163. data/culture/tasks/rubocop.rake +0 -2
  164. data/lib/celluloid/actor/manager.rb +0 -7
  165. data/lib/celluloid/backported.rb +0 -2
  166. data/lib/celluloid/current.rb +0 -2
  167. data/lib/celluloid/deprecate.rb +0 -34
  168. data/lib/celluloid/fiber.rb +0 -32
  169. data/lib/celluloid/managed.rb +0 -3
  170. data/lib/celluloid/notices.rb +0 -15
  171. data/spec/deprecate/actor_system_spec.rb +0 -72
  172. data/spec/deprecate/block_spec.rb +0 -52
  173. data/spec/deprecate/calls_spec.rb +0 -39
  174. data/spec/deprecate/evented_mailbox_spec.rb +0 -34
  175. data/spec/deprecate/future_spec.rb +0 -32
  176. data/spec/deprecate/internal_pool_spec.rb +0 -4
  177. data/spec/support/env.rb +0 -21
@@ -0,0 +1,49 @@
1
+ require "logger"
2
+
3
+ module Celluloid
4
+ # Subscribes to log incident topics to report on them.
5
+ class IncidentReporter
6
+ include Celluloid
7
+ include Celluloid::Notifications
8
+
9
+ # get the time from the event
10
+ class Formatter < ::Logger::Formatter
11
+ def call(severity, _time, progname, msg)
12
+ super(severity, msg.time, progname, msg.message)
13
+ end
14
+ end
15
+
16
+ def initialize(*args)
17
+ subscribe(/log\.incident/, :report)
18
+ @logger = ::Logger.new(*args)
19
+ @logger.formatter = Formatter.new
20
+ @silenced = false
21
+ end
22
+
23
+ def report(_topic, incident)
24
+ return if @silenced
25
+
26
+ header = "INCIDENT"
27
+ header << " AT #{incident.triggering_event.time}" if incident.triggering_event
28
+ @logger << header
29
+ @logger << "\n"
30
+ @logger << "====================\n"
31
+ incident.events.each do |event|
32
+ @logger.add(event.severity, event, event.progname)
33
+ end
34
+ @logger << "====================\n"
35
+ end
36
+
37
+ def silence
38
+ @silenced = true
39
+ end
40
+
41
+ def unsilence
42
+ @silenced = false
43
+ end
44
+
45
+ def silenced?
46
+ @silenced
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,20 @@
1
+ module Celluloid
2
+ # Wraps a single log event.
3
+ class LogEvent
4
+ attr_accessor :id, :severity, :message, :progname, :time
5
+
6
+ def initialize(severity, message, progname, time = Time.now, &_block)
7
+ # This id should be ordered. For now relies on Celluloid::UUID to be ordered.
8
+ # May want to use a generation/counter strategy for independence of uuid.
9
+ @id = Internals::UUID.generate
10
+ @severity = severity
11
+ @message = block_given? ? yield : message
12
+ @progname = progname
13
+ @time = time
14
+ end
15
+
16
+ def <=>(other)
17
+ @id <=> other.id
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,64 @@
1
+ module Celluloid
2
+ class RingBuffer
3
+ def initialize(size)
4
+ @size = size
5
+ @start = 0
6
+ @count = 0
7
+ @buffer = Array.new(size)
8
+ @mutex = Mutex.new
9
+ end
10
+
11
+ def full?
12
+ @count == @size
13
+ end
14
+
15
+ def empty?
16
+ @count == 0
17
+ end
18
+
19
+ def push(value)
20
+ @mutex.synchronize do
21
+ stop = (@start + @count) % @size
22
+ @buffer[stop] = value
23
+ if full?
24
+ @start = (@start + 1) % @size
25
+ else
26
+ @count += 1
27
+ end
28
+ value
29
+ end
30
+ end
31
+ alias << push
32
+
33
+ def shift
34
+ @mutex.synchronize do
35
+ remove_element
36
+ end
37
+ end
38
+
39
+ def flush
40
+ values = []
41
+ @mutex.synchronize do
42
+ values << remove_element until empty?
43
+ end
44
+ values
45
+ end
46
+
47
+ def clear
48
+ @buffer = Array.new(@size)
49
+ @start = 0
50
+ @count = 0
51
+ end
52
+
53
+ private
54
+
55
+ def remove_element
56
+ return nil if empty?
57
+ value = @buffer[@start]
58
+ @buffer[@start] = nil
59
+ @start = (@start + 1) % @size
60
+ @count -= 1
61
+ value
62
+ end
63
+ end
64
+ end
@@ -1,5 +1,3 @@
1
- require "thread"
2
-
3
1
  module Celluloid
4
2
  class MailboxDead < Celluloid::Error; end # you can't receive from the dead
5
3
  class MailboxShutdown < Celluloid::Error; end # raised if the mailbox can no longer be used
@@ -41,7 +39,11 @@ module Celluloid
41
39
  @condition.signal
42
40
  nil
43
41
  ensure
44
- @mutex.unlock rescue nil
42
+ begin
43
+ @mutex.unlock
44
+ rescue
45
+ nil
46
+ end
45
47
  end
46
48
  end
47
49
 
@@ -52,7 +54,7 @@ module Celluloid
52
54
 
53
55
  @mutex.lock
54
56
  begin
55
- fail MailboxDead, "attempted to receive from a dead mailbox" if @dead
57
+ raise MailboxDead, "attempted to receive from a dead mailbox" if @dead
56
58
 
57
59
  message = nil
58
60
  Timers::Wait.for(timeout) do |remaining|
@@ -63,7 +65,11 @@ module Celluloid
63
65
  @condition.wait(@mutex, remaining)
64
66
  end
65
67
  ensure
66
- @mutex.unlock rescue nil
68
+ begin
69
+ @mutex.unlock
70
+ rescue
71
+ nil
72
+ end
67
73
  end
68
74
 
69
75
  message
@@ -73,17 +79,17 @@ module Celluloid
73
79
  # timeout is exceeded, raise a TaskTimeout.
74
80
  def receive(timeout = nil, &block)
75
81
  message = nil
76
- Timers::Wait.for(timeout) do |remaining|
82
+ Timers::Wait.for(timeout) do |_remaining|
77
83
  message = check(timeout, &block)
78
84
  break if message
79
85
  end
80
86
  return message if message
81
- fail TaskTimeout.new("receive timeout exceeded")
87
+ raise TaskTimeout, "receive timeout exceeded"
82
88
  end
83
89
 
84
90
  # Shut down this mailbox and clean up its contents
85
91
  def shutdown
86
- fail MailboxDead, "mailbox already shutdown" if @dead
92
+ raise MailboxDead, "mailbox already shutdown" if @dead
87
93
 
88
94
  @mutex.lock
89
95
  begin
@@ -92,7 +98,11 @@ module Celluloid
92
98
  @messages = []
93
99
  @dead = true
94
100
  ensure
95
- @mutex.unlock rescue nil
101
+ begin
102
+ @mutex.unlock
103
+ rescue
104
+ nil
105
+ end
96
106
  end
97
107
 
98
108
  messages.each do |msg|
@@ -147,7 +157,10 @@ module Celluloid
147
157
  end
148
158
 
149
159
  def dead_letter(message)
160
+ # !!! DO NOT INTRODUCE ADDITIONAL GLOBAL VARIABLES !!!
161
+ # rubocop:disable Style/GlobalVars
150
162
  Internals::Logger.debug "Discarded message (mailbox is dead): #{message}" if $CELLULOID_DEBUG
163
+ # rubocop:enable Style/GlobalVars
151
164
  end
152
165
 
153
166
  def mailbox_full
@@ -26,13 +26,17 @@ module Celluloid
26
26
  @messages << message
27
27
  end
28
28
  ensure
29
- @mutex.unlock rescue nil
29
+ begin
30
+ @mutex.unlock
31
+ rescue
32
+ nil
33
+ end
30
34
  end
31
35
  begin
32
36
  current_actor = Thread.current[:celluloid_actor]
33
37
  @reactor.wakeup unless current_actor && current_actor.mailbox == self
34
- rescue
35
- Internals::Logger.crash "reactor crashed", $ERROR_INFO
38
+ rescue => ex
39
+ Internals::Logger.crash "reactor crashed", ex
36
40
  dead_letter(message)
37
41
  end
38
42
  nil
@@ -50,7 +54,7 @@ module Celluloid
50
54
  @reactor.run_once(timeout)
51
55
 
52
56
  # No message was received:
53
- return nil
57
+ nil
54
58
  end
55
59
 
56
60
  # Obtain the next message from the mailbox that matches the given block
@@ -59,7 +63,11 @@ module Celluloid
59
63
  begin
60
64
  super(&block)
61
65
  ensure
62
- @mutex.unlock rescue nil
66
+ begin
67
+ @mutex.unlock
68
+ rescue
69
+ nil
70
+ end
63
71
  end
64
72
  end
65
73
 
@@ -0,0 +1,95 @@
1
+ module Celluloid
2
+ module Notifications
3
+ def self.notifier
4
+ Actor[:notifications_fanout] || raise(DeadActorError, "notifications fanout actor not running")
5
+ end
6
+
7
+ def publish(pattern, *args)
8
+ Celluloid::Notifications.notifier.publish(pattern, *args)
9
+ rescue DeadActorError
10
+ # Bad shutdown logic. Oh well....
11
+ # TODO: needs a tests
12
+ end
13
+
14
+ module_function :publish
15
+
16
+ def subscribe(pattern, method)
17
+ Celluloid::Notifications.notifier.subscribe(Actor.current, pattern, method)
18
+ end
19
+
20
+ def unsubscribe(*args)
21
+ Celluloid::Notifications.notifier.unsubscribe(*args)
22
+ end
23
+
24
+ class Fanout
25
+ include Celluloid
26
+ trap_exit :prune
27
+
28
+ def initialize
29
+ @subscribers = []
30
+ @listeners_for = {}
31
+ end
32
+
33
+ def subscribe(actor, pattern, method)
34
+ subscriber = Subscriber.new(actor, pattern, method).tap do |s|
35
+ @subscribers << s
36
+ end
37
+ link actor
38
+ @listeners_for.clear
39
+ subscriber
40
+ end
41
+
42
+ def unsubscribe(subscriber)
43
+ @subscribers.reject! { |s| s.matches?(subscriber) }
44
+ @listeners_for.clear
45
+ end
46
+
47
+ def publish(pattern, *args)
48
+ listeners_for(pattern).each { |s| s.publish(pattern, *args) }
49
+ end
50
+
51
+ def listeners_for(pattern)
52
+ @listeners_for[pattern] ||= @subscribers.select { |s| s.subscribed_to?(pattern) }
53
+ end
54
+
55
+ def listening?(pattern)
56
+ listeners_for(pattern).any?
57
+ end
58
+
59
+ def prune(actor, _reason = nil)
60
+ @subscribers.reject! { |s| s.actor == actor }
61
+ @listeners_for.clear
62
+ end
63
+ end
64
+
65
+ class Subscriber
66
+ attr_accessor :actor, :pattern, :method
67
+
68
+ def initialize(actor, pattern, method)
69
+ @actor = actor
70
+ @pattern = pattern
71
+ @method = method
72
+ end
73
+
74
+ def publish(pattern, *args)
75
+ actor.async method, pattern, *args
76
+ rescue DeadActorError
77
+ # TODO: needs a tests
78
+ # Bad shutdown logic. Oh well....
79
+ end
80
+
81
+ def subscribed_to?(pattern)
82
+ !pattern || @pattern === pattern.to_s || @pattern === pattern
83
+ end
84
+
85
+ def matches?(subscriber_or_pattern)
86
+ self === subscriber_or_pattern ||
87
+ @pattern && @pattern === subscriber_or_pattern
88
+ end
89
+ end
90
+ end
91
+
92
+ def self.publish(*args)
93
+ Notifications.publish(*args)
94
+ end
95
+ end
@@ -0,0 +1,6 @@
1
+ require "celluloid" unless defined? Celluloid
2
+
3
+ require "celluloid/supervision"
4
+
5
+ require "celluloid/supervision/container/pool"
6
+ require "celluloid/supervision/container/behavior/pool"
@@ -0,0 +1,81 @@
1
+ require "celluloid"
2
+
3
+ # !!! DO NOT INTRODUCE ADDITIONAL GLOBAL VARIABLES !!!
4
+ # rubocop:disable Style/GlobalVars
5
+ $CELLULOID_MONITORING = true
6
+ # rubocop:enable Style/GlobalVars
7
+
8
+ module Celluloid
9
+ class Probe
10
+ include Celluloid
11
+ include Celluloid::Notifications
12
+
13
+ NOTIFICATIONS_TOPIC_BASE = "celluloid.events.%s".freeze
14
+ EVENTS_BUFFER = Queue.new
15
+
16
+ class << self
17
+ def run
18
+ # spawn the actor if not found
19
+ supervise_as(:probe_actor) unless Actor[:probe_actor] && Actor[:probe_actor].alive?
20
+ end
21
+
22
+ def run_without_supervision
23
+ Actor[:probe_actor] = Celluloid::Probe.new
24
+ end
25
+
26
+ def actor_created(actor)
27
+ trigger_event(:actor_created, actor)
28
+ end
29
+
30
+ def actor_named(actor)
31
+ trigger_event(:actor_named, actor)
32
+ end
33
+
34
+ def actor_died(actor)
35
+ trigger_event(:actor_died, actor)
36
+ end
37
+
38
+ def actors_linked(a, b)
39
+ a = find_actor(a)
40
+ b = find_actor(b)
41
+ trigger_event(:actors_linked, a, b)
42
+ end
43
+
44
+ private
45
+
46
+ def trigger_event(name, *args)
47
+ # !!! DO NOT INTRODUCE ADDITIONAL GLOBAL VARIABLES !!!
48
+ # rubocop:disable Style/GlobalVars
49
+ return unless $CELLULOID_MONITORING
50
+ # rubocop:enable Style/GlobalVars
51
+
52
+ EVENTS_BUFFER << [name, args]
53
+ probe_actor = Actor[:probe_actor]
54
+ probe_actor.async.process_queue if probe_actor
55
+ end
56
+
57
+ def find_actor(obj)
58
+ if obj.__send__(:class) == Actor
59
+ obj
60
+ elsif owner = obj.instance_variable_get(OWNER_IVAR)
61
+ owner
62
+ end
63
+ end
64
+ end
65
+
66
+ def initialize
67
+ async.process_queue
68
+ end
69
+
70
+ def process_queue
71
+ until EVENTS_BUFFER.empty?
72
+ event = EVENTS_BUFFER.pop
73
+ dispatch_event(*event)
74
+ end
75
+ end
76
+
77
+ def dispatch_event(cmd, args)
78
+ publish(NOTIFICATIONS_TOPIC_BASE % cmd, args)
79
+ end
80
+ end
81
+ end