proletariat 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +12 -0
- data/README.md +1 -2
- data/lib/proletariat/concurrency/actor.rb +71 -0
- data/lib/proletariat/concurrency/supervisor.rb +31 -0
- data/lib/proletariat/configuration.rb +131 -0
- data/lib/proletariat/cucumber.rb +6 -2
- data/lib/proletariat/manager.rb +20 -66
- data/lib/proletariat/publisher.rb +27 -51
- data/lib/proletariat/queue_config.rb +1 -5
- data/lib/proletariat/runner.rb +10 -106
- data/lib/proletariat/subscriber.rb +6 -8
- data/lib/proletariat/testing/expectation_guarantor.rb +5 -9
- data/lib/proletariat/testing.rb +1 -1
- data/lib/proletariat/util/worker_description_parser.rb +37 -0
- data/lib/proletariat/version.rb +1 -1
- data/lib/proletariat/worker.rb +17 -41
- data/lib/proletariat.rb +24 -51
- data/spec/lib/configuration_spec.rb +85 -0
- data/spec/lib/proletariat_spec.rb +5 -4
- data/spec/lib/publisher_spec.rb +36 -0
- data/spec/lib/queue_config_spec.rb +12 -0
- data/spec/lib/testing/expectation_guarantor_spec.rb +55 -0
- data/spec/lib/testing/expectation_spec.rb +15 -0
- data/spec/lib/util/worker_description_parser_spec.rb +42 -0
- data/spec/lib/worker_spec.rb +83 -0
- metadata +34 -25
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 49905f9a8ecb2a3b12f565f7b6c7e07c7cac6e39
|
4
|
+
data.tar.gz: 76771f1121f542f06a8ee2d9f6f7ffcf07982404
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5a1e573f1fd1028068f5f91dcd5625d4ddf90052d9711b8c8a85d810db0ea4b0440cb51384040c865eea540cbbf48368dc7b2dacdc770e85fa0430b5f63f887d
|
7
|
+
data.tar.gz: 193ecfabdc6bb3c0d25bda8a8e57a66a77aa6ab830a552f395acc626a88803ef556019556a950201a302089a830d8328fa42690943dca4a9376a345c98200217
|
data/.rubocop.yml
ADDED
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
## 0.0.3
|
2
|
+
|
3
|
+
Features:
|
4
|
+
|
5
|
+
- Overhauled configuration (breaking change)
|
6
|
+
- Queues now purged before first cucumber scenario
|
7
|
+
|
8
|
+
Code gardening:
|
9
|
+
|
10
|
+
- Decoupling logic from concurrency for better testability
|
11
|
+
- Added tests
|
12
|
+
|
1
13
|
## 0.0.2
|
2
14
|
|
3
15
|
Features:
|
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
Lightweight background processing in Ruby powered by RabbitMQ and the excellent concurrent-ruby gem.
|
4
4
|
|
5
|
-
[![Code Climate](https://codeclimate.com/
|
5
|
+
[![Code Climate](https://codeclimate.com/github/SebastianEdwards/proletariat.png)](https://codeclimate.com/github/SebastianEdwards/proletariat)
|
6
6
|
|
7
7
|
### Warning!
|
8
8
|
|
@@ -100,6 +100,5 @@ Use the provided helpers in your step definitions to synchronize your test suite
|
|
100
100
|
I wanted a library which shared one RabbitMQ connection across all of the workers on a given process. Many hosted RabbitMQ platforms tightly limit the max number of connections.
|
101
101
|
|
102
102
|
## TODO
|
103
|
-
- Improve test suite :(
|
104
103
|
- Add command line interface
|
105
104
|
- Abstract retry strategies
|
@@ -0,0 +1,71 @@
|
|
1
|
+
module Proletariat
|
2
|
+
# Public: Interface abstraction for Concurrent::Actor. Creates a delegate
|
3
|
+
# instance from given class and arguments and delegates events to it.
|
4
|
+
class Actor < Concurrent::Actor
|
5
|
+
# Public: Creates a new Actor instance.
|
6
|
+
#
|
7
|
+
# delegate_class - The class to instantiate as a delegate.
|
8
|
+
# *arguments - The arguments to pass to delegate_class.new
|
9
|
+
def initialize(delegate_class, *arguments)
|
10
|
+
@delegate = delegate_class.new(*arguments)
|
11
|
+
end
|
12
|
+
|
13
|
+
# Internal: Called by the Concurrent framework to handle new mailbox
|
14
|
+
# messages. Overridden in this subclass to call the #work method
|
15
|
+
# with the given arguments on the delegate.
|
16
|
+
#
|
17
|
+
# *arguments - The arguments to pass to delegate#work
|
18
|
+
#
|
19
|
+
# Returns nil.
|
20
|
+
def act(*arguments)
|
21
|
+
delegate.work(*arguments)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Internal: Called by the Concurrent framework on actor start. Overridden
|
25
|
+
# in this subclass to call the #starting and #started methods on
|
26
|
+
# the delegate.
|
27
|
+
#
|
28
|
+
# Returns nil.
|
29
|
+
def on_run
|
30
|
+
delegate.starting if delegate.respond_to?(:starting)
|
31
|
+
|
32
|
+
super
|
33
|
+
|
34
|
+
delegate.started if delegate.respond_to?(:started)
|
35
|
+
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
|
39
|
+
# Internal: Called by the Concurrent framework on actor start. Overridden
|
40
|
+
# in this subclass to call the #stopping and #stopped methods on
|
41
|
+
# the delegate. Ensures queue is drained before calling #stopped.
|
42
|
+
#
|
43
|
+
# Returns nil.
|
44
|
+
def on_stop
|
45
|
+
delegate.stopping if delegate.respond_to?(:stopping)
|
46
|
+
|
47
|
+
wait_for_queue_to_drain unless queue.empty?
|
48
|
+
|
49
|
+
super
|
50
|
+
|
51
|
+
delegate.stopped if delegate.respond_to?(:stopped)
|
52
|
+
|
53
|
+
nil
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
# Internal: Returns the delegate instance.
|
59
|
+
attr_reader :delegate
|
60
|
+
|
61
|
+
# Internal: Blocks until each queued message has been handled by the
|
62
|
+
# delegate #work method.
|
63
|
+
#
|
64
|
+
# Returns nil.
|
65
|
+
def wait_for_queue_to_drain
|
66
|
+
delegate.work(*queue.pop.message) until queue.empty?
|
67
|
+
|
68
|
+
nil
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Proletariat
|
2
|
+
class Supervisor
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
def_delegators :true_supervisor, :run, :run!, :stop, :running?, :add_worker
|
6
|
+
|
7
|
+
def [](mailbox_name)
|
8
|
+
mailboxes[mailbox_name]
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_supervisor(supervisor, opts = {})
|
12
|
+
true_supervisor.add_worker supervisor, opts.merge(type: :supervisor)
|
13
|
+
end
|
14
|
+
|
15
|
+
def supervise_pool(mailbox_name, threads, actor_class, *arguments)
|
16
|
+
mailboxes[mailbox_name], workers = Actor.pool(threads, actor_class,
|
17
|
+
*arguments)
|
18
|
+
true_supervisor.add_workers workers
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def mailboxes
|
24
|
+
@mailboxes ||= {}
|
25
|
+
end
|
26
|
+
|
27
|
+
def true_supervisor
|
28
|
+
@true_supervisor ||= Concurrent::Supervisor.new
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
module Proletariat
|
2
|
+
# Public: Global configuration object. Provides sensible defaults.
|
3
|
+
class Configuration
|
4
|
+
# Public: The default name used for the RabbitMQ topic exchange.
|
5
|
+
DEFAULT_EXCHANGE_NAME = 'proletariat'
|
6
|
+
|
7
|
+
# Public: The default number of threads to use for publishers.
|
8
|
+
DEFAULT_PUBLISHER_THREADS = 2
|
9
|
+
|
10
|
+
# Public: The default number of threads to use for each worker class.
|
11
|
+
DEFAULT_WORKER_THREADS = 3
|
12
|
+
|
13
|
+
# Internal: Sets the RabbitMQ connection.
|
14
|
+
attr_writer :connection
|
15
|
+
|
16
|
+
# Internal: Sets the RabbitMQ topic exchange name.
|
17
|
+
attr_writer :exchange_name
|
18
|
+
|
19
|
+
# Internal: Sets the logger.
|
20
|
+
attr_writer :logger
|
21
|
+
|
22
|
+
# Internal: Sets the number of threads to use for publishers.
|
23
|
+
attr_writer :publisher_threads
|
24
|
+
|
25
|
+
# Internal: Sets the Array of Worker classes to use for background
|
26
|
+
# processing.
|
27
|
+
attr_writer :worker_classes
|
28
|
+
|
29
|
+
# Internal: Sets the number of threads to use for each Worker class.
|
30
|
+
attr_writer :worker_threads
|
31
|
+
|
32
|
+
# Public: Allows setting of the config attributes via a block.
|
33
|
+
#
|
34
|
+
# block - Block which modifies attributes by accessing them via #config.
|
35
|
+
#
|
36
|
+
# Returns nil.
|
37
|
+
def configure_with_block(&block)
|
38
|
+
ConfigurationDSL.new(self, &block).set_config
|
39
|
+
|
40
|
+
nil
|
41
|
+
end
|
42
|
+
|
43
|
+
# Public: Returns the set connection or defaults to a new, open
|
44
|
+
# Bunny::Session
|
45
|
+
#
|
46
|
+
# Returns a Bunny::Session.
|
47
|
+
def connection
|
48
|
+
@connection ||= begin
|
49
|
+
new_connection = Bunny.new
|
50
|
+
new_connection.start
|
51
|
+
|
52
|
+
new_connection
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Public: Returns the set name of the exchange or a default.
|
57
|
+
#
|
58
|
+
# Returns a String.
|
59
|
+
def exchange_name
|
60
|
+
@exchange_name ||= DEFAULT_EXCHANGE_NAME
|
61
|
+
end
|
62
|
+
|
63
|
+
# Public: Returns the set logger or a default standard output logger.
|
64
|
+
#
|
65
|
+
# Returns a logger.
|
66
|
+
def logger
|
67
|
+
@logger ||= Logger.new(STDOUT)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Public: Returns the set number of publisher threads or a default.
|
71
|
+
#
|
72
|
+
# Returns a Fixnum.
|
73
|
+
def publisher_threads
|
74
|
+
@publisher_threads ||= DEFAULT_PUBLISHER_THREADS
|
75
|
+
end
|
76
|
+
|
77
|
+
# Public: Returns the set worker classes or a default pulled from the
|
78
|
+
# WORKERS env variable.
|
79
|
+
#
|
80
|
+
# Returns an array of Worker classes.
|
81
|
+
def worker_classes
|
82
|
+
@worker_classes ||= begin
|
83
|
+
if ENV['WORKERS']
|
84
|
+
WorkerDescriptionParser.parse ENV['WORKERS']
|
85
|
+
else
|
86
|
+
[]
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
# Public: Returns the set number of worker threads or a default.
|
92
|
+
#
|
93
|
+
# Returns a Fixnum.
|
94
|
+
def worker_threads
|
95
|
+
@worker_threads ||= DEFAULT_WORKER_THREADS
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
# Internal: Handles running a configuration block in a context to allow
|
101
|
+
# access to the configuration object via a call to #config.
|
102
|
+
class ConfigurationDSL
|
103
|
+
# Public: Creates a new ConfigurationDSL instance.
|
104
|
+
#
|
105
|
+
# configuration - The Configuration instance you intend to update.
|
106
|
+
# block - The block containing the config settings.
|
107
|
+
def initialize(configuration, &block)
|
108
|
+
@config = configuration
|
109
|
+
@block = block
|
110
|
+
end
|
111
|
+
|
112
|
+
# Public: Runs the configuration block, exposing the configuration
|
113
|
+
# instance via the #config method.
|
114
|
+
#
|
115
|
+
# Returns nil.
|
116
|
+
def set_config
|
117
|
+
instance_eval(&block)
|
118
|
+
|
119
|
+
nil
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
# Internal: Returns the config block.
|
125
|
+
attr_reader :block
|
126
|
+
|
127
|
+
# Internal: Returns the Configuration instance.
|
128
|
+
attr_reader :config
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
data/lib/proletariat/cucumber.rb
CHANGED
@@ -4,8 +4,12 @@ require 'proletariat/testing'
|
|
4
4
|
World(Proletariat::Testing)
|
5
5
|
|
6
6
|
# Hide logs by default.
|
7
|
-
AfterConfiguration do |
|
8
|
-
Proletariat.
|
7
|
+
AfterConfiguration do |_|
|
8
|
+
Proletariat.configure do
|
9
|
+
config.logger = Logger.new('/dev/null')
|
10
|
+
end
|
11
|
+
|
12
|
+
Proletariat.purge
|
9
13
|
end
|
10
14
|
|
11
15
|
# Ensure Proletariat running before each test.
|
data/lib/proletariat/manager.rb
CHANGED
@@ -2,27 +2,26 @@ module Proletariat
|
|
2
2
|
# Public: Maintains a pool of worker threads and a RabbitMQ subscriber
|
3
3
|
# thread. Uses information from the worker class to generate queue
|
4
4
|
# config.
|
5
|
-
class Manager
|
5
|
+
class Manager
|
6
6
|
# Public: Creates a new Manager instance.
|
7
7
|
#
|
8
|
-
# connection - An open Bunny::Session object.
|
9
|
-
# exchange_name - A String of the RabbitMQ topic exchange.
|
10
8
|
# worker_class - A subclass of Proletariat::Worker to handle messages.
|
11
|
-
|
12
|
-
|
13
|
-
def initialize(connection, exchange_name, worker_class, options = {})
|
14
|
-
super()
|
9
|
+
def initialize(worker_class)
|
10
|
+
@supervisor = Supervisor.new
|
15
11
|
|
16
|
-
|
17
|
-
|
18
|
-
@worker_class = worker_class
|
19
|
-
@worker_threads = options.fetch :worker_threads, 3
|
12
|
+
supervisor.supervise_pool('workers', Proletariat.worker_threads,
|
13
|
+
worker_class)
|
20
14
|
|
21
|
-
|
22
|
-
|
15
|
+
@subscriber = Subscriber.new(supervisor['workers'],
|
16
|
+
generate_queue_config(worker_class))
|
23
17
|
|
24
|
-
|
25
|
-
|
18
|
+
supervisor.add_worker subscriber
|
19
|
+
end
|
20
|
+
|
21
|
+
# Delegate lifecycle calls to supervisor. Cannot use Forwardable due to
|
22
|
+
# concurrent-ruby API checking implementation.
|
23
|
+
%w(run stop running?).each do |method|
|
24
|
+
define_method(method) { supervisor.send method }
|
26
25
|
end
|
27
26
|
|
28
27
|
# Public: Purge the RabbitMQ queue.
|
@@ -36,64 +35,19 @@ module Proletariat
|
|
36
35
|
|
37
36
|
private
|
38
37
|
|
39
|
-
# Internal: Returns an open Bunny::Session object.
|
40
|
-
attr_reader :connection
|
41
|
-
|
42
|
-
# Internal: Returns the name of the RabbitMQ topic exchange.
|
43
|
-
attr_reader :exchange_name
|
44
|
-
|
45
38
|
# Internal: Returns the Subscriber actor for this Manager.
|
46
39
|
attr_reader :subscriber
|
47
40
|
|
48
|
-
# Internal:
|
49
|
-
attr_reader :
|
50
|
-
|
51
|
-
# Internal: Returns the pool of initialized workers.
|
52
|
-
attr_reader :worker_pool
|
53
|
-
|
54
|
-
# Internal: Returns a shared mailbox for the pool of workers.
|
55
|
-
attr_reader :workers_mailbox
|
56
|
-
|
57
|
-
# Internal: Returns the number of worker threads in the worker pool.
|
58
|
-
attr_reader :worker_threads
|
59
|
-
|
60
|
-
# Internal: Assign a new Subscriber instance (configured for the current
|
61
|
-
# worker type) to the manager's subscriber property.
|
62
|
-
#
|
63
|
-
# Returns nil.
|
64
|
-
def create_subscriber
|
65
|
-
@subscriber = Subscriber.new(
|
66
|
-
connection,
|
67
|
-
workers_mailbox,
|
68
|
-
generate_queue_config
|
69
|
-
)
|
70
|
-
|
71
|
-
nil
|
72
|
-
end
|
41
|
+
# Internal: The supervisor used to manage the Workers and Subscriber
|
42
|
+
attr_reader :supervisor
|
73
43
|
|
74
|
-
# Internal:
|
75
|
-
# manager's workers_mailbox and worker_pool properties
|
76
|
-
# respectively.
|
44
|
+
# Internal: Builds a new QueueConfig from a given Worker subclass.
|
77
45
|
#
|
78
|
-
#
|
79
|
-
def create_worker_pool
|
80
|
-
@workers_mailbox, @worker_pool = worker_class.pool(worker_threads)
|
81
|
-
|
82
|
-
nil
|
83
|
-
end
|
84
|
-
|
85
|
-
# Internal: Builds a new QueueConfig object passing in some settings from
|
86
|
-
# worker_class.
|
46
|
+
# worker_class - The Worker subclass to base settings on.
|
87
47
|
#
|
88
48
|
# Returns a new QueueConfig instance.
|
89
|
-
def generate_queue_config
|
90
|
-
QueueConfig.new(
|
91
|
-
worker_class.name,
|
92
|
-
exchange_name,
|
93
|
-
worker_class.routing_keys,
|
94
|
-
worker_threads,
|
95
|
-
false
|
96
|
-
)
|
49
|
+
def generate_queue_config(worker_class)
|
50
|
+
QueueConfig.new(worker_class.name, worker_class.routing_keys, false)
|
97
51
|
end
|
98
52
|
end
|
99
53
|
end
|
@@ -1,87 +1,63 @@
|
|
1
|
+
require 'proletariat/concerns/logging'
|
2
|
+
|
1
3
|
module Proletariat
|
2
|
-
# Public:
|
3
|
-
|
4
|
-
class Publisher < Concurrent::Actor
|
4
|
+
# Public: Receives messages and publishes them to a RabbitMQ topic exchange.
|
5
|
+
class Publisher
|
5
6
|
include Concerns::Logging
|
6
7
|
|
7
8
|
# Public: Creates a new Publisher instance.
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
def initialize(connection, exchange_name)
|
12
|
-
@channel = connection.create_channel
|
13
|
-
@exchange = channel.topic(exchange_name, durable: true)
|
9
|
+
def initialize
|
10
|
+
@channel = Proletariat.connection.create_channel
|
11
|
+
@exchange = channel.topic(Proletariat.exchange_name, durable: true)
|
14
12
|
end
|
15
13
|
|
16
|
-
# Public:
|
17
|
-
# messages. Overridden in this subclass to push messages to a
|
18
|
-
# RabbitMQ topic exchange.
|
19
|
-
#
|
20
|
-
# to - The routing key for the message to as a String. In accordance
|
21
|
-
# with the RabbitMQ convention you can use the '*' character to
|
22
|
-
# replace one word and the '#' to replace many words.
|
23
|
-
# message - The message as a String.
|
14
|
+
# Public: Logs the 'online' status of the publisher.
|
24
15
|
#
|
25
16
|
# Returns nil.
|
26
|
-
def
|
27
|
-
|
17
|
+
def started
|
18
|
+
log_info 'Now online'
|
28
19
|
|
29
20
|
nil
|
30
21
|
end
|
31
22
|
|
32
|
-
# Public:
|
33
|
-
# this subclass to log the status of the publisher.
|
23
|
+
# Public: Logs the 'offline' status of the publisher.
|
34
24
|
#
|
35
25
|
# Returns nil.
|
36
|
-
def
|
37
|
-
|
38
|
-
log_info 'Now online'
|
26
|
+
def stopped
|
27
|
+
log_info 'Now offline'
|
39
28
|
|
40
29
|
nil
|
41
30
|
end
|
42
31
|
|
43
|
-
# Public:
|
44
|
-
#
|
45
|
-
|
32
|
+
# Public: Logs the 'shutting down' status of the publisher.
|
33
|
+
#
|
34
|
+
# Returns nil.
|
35
|
+
def stopping
|
46
36
|
log_info 'Attempting graceful shutdown.'
|
47
|
-
wait_for_publish_queue unless queue.empty?
|
48
|
-
|
49
|
-
super
|
50
|
-
|
51
|
-
log_info 'Now offline'
|
52
37
|
|
53
38
|
nil
|
54
39
|
end
|
55
40
|
|
56
|
-
|
57
|
-
|
58
|
-
# Internal: Returns the Bunny::Channel in use.
|
59
|
-
attr_reader :channel
|
60
|
-
|
61
|
-
# Internal: Returns the Bunny::Exchange in use.
|
62
|
-
attr_reader :exchange
|
63
|
-
|
64
|
-
# Internal: Handles the actual message send to the exchange.
|
41
|
+
# Public: Push a message to a RabbitMQ topic exchange.
|
65
42
|
#
|
66
|
-
# to - The routing key.
|
43
|
+
# to - The routing key for the message to as a String. In accordance
|
44
|
+
# with the RabbitMQ convention you can use the '*' character to
|
45
|
+
# replace one word and the '#' to replace many words.
|
67
46
|
# message - The message as a String.
|
68
47
|
#
|
69
48
|
# Returns nil.
|
70
|
-
def
|
49
|
+
def work(to, message)
|
71
50
|
exchange.publish message, routing_key: to, persistent: true
|
72
51
|
|
73
52
|
nil
|
74
53
|
end
|
75
54
|
|
76
|
-
|
77
|
-
#
|
78
|
-
# Returns nil.
|
79
|
-
def wait_for_publish_queue
|
80
|
-
log_info 'Waiting for work queue to drain.'
|
55
|
+
private
|
81
56
|
|
82
|
-
|
57
|
+
# Internal: Returns the Bunny::Channel in use.
|
58
|
+
attr_reader :channel
|
83
59
|
|
84
|
-
|
85
|
-
|
60
|
+
# Internal: Returns the Bunny::Exchange in use.
|
61
|
+
attr_reader :exchange
|
86
62
|
end
|
87
63
|
end
|
@@ -1,9 +1,5 @@
|
|
1
1
|
# Internal: Value object to hold RabbitMQ settings.
|
2
|
-
class QueueConfig < Struct.new(:worker_name,
|
3
|
-
:exchange_name,
|
4
|
-
:routing_keys,
|
5
|
-
:prefetch,
|
6
|
-
:auto_delete)
|
2
|
+
class QueueConfig < Struct.new(:worker_name, :routing_keys, :auto_delete)
|
7
3
|
# Public: Create an underscored RabbitMQ queue name from the worker_name.
|
8
4
|
#
|
9
5
|
# Examples
|
data/lib/proletariat/runner.rb
CHANGED
@@ -7,37 +7,16 @@ module Proletariat
|
|
7
7
|
# Public: Delegate lifecycle calls to the supervisor.
|
8
8
|
def_delegators :supervisor, :run, :run!, :stop, :running?
|
9
9
|
|
10
|
-
# Public:
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
# Public: Creates a new Runner instance. Default options should be fine for
|
17
|
-
# most scenarios.
|
18
|
-
#
|
19
|
-
# options - A Hash of options (default: {}):
|
20
|
-
# :connection - An open RabbitMQ::Session object.
|
21
|
-
# :exchange_name - The RabbitMQ topic exchange name as a
|
22
|
-
# String.
|
23
|
-
# :publisher_threads - The size of the publisher thread pool.
|
24
|
-
# :supervisor - A Supervisor instance.
|
25
|
-
# :worker_classes - An Array of Worker subclasses.
|
26
|
-
# :worker_threads - The size of the worker thread pool.
|
27
|
-
def initialize(options = {})
|
28
|
-
@connection = options.fetch :connection, create_connection
|
29
|
-
@exchange_name = options.fetch :exchange_name, DEFAULT_EXCHANGE_NAME
|
30
|
-
@publisher_threads = options.fetch :publisher_threads, 2
|
31
|
-
@supervisor = options.fetch :supervisor, create_supervisor
|
32
|
-
@worker_classes = options.fetch :worker_classes, []
|
33
|
-
@worker_threads = options.fetch :worker_threads, 3
|
34
|
-
|
35
|
-
@managers = []
|
36
|
-
|
37
|
-
create_publisher_pool
|
10
|
+
# Public: Creates a new Runner instance.
|
11
|
+
def initialize
|
12
|
+
@supervisor = Supervisor.new
|
13
|
+
@managers = Proletariat.worker_classes.map do |worker_class|
|
14
|
+
Manager.new(worker_class)
|
15
|
+
end
|
38
16
|
|
39
|
-
|
40
|
-
|
17
|
+
supervisor.supervise_pool('publishers', Proletariat.publisher_threads,
|
18
|
+
Publisher)
|
19
|
+
managers.each { |manager| supervisor.add_supervisor manager }
|
41
20
|
end
|
42
21
|
|
43
22
|
# Public: Publishes a message to RabbitMQ via the publisher pool.
|
@@ -49,7 +28,7 @@ module Proletariat
|
|
49
28
|
#
|
50
29
|
# Returns nil.
|
51
30
|
def publish(to, message)
|
52
|
-
|
31
|
+
supervisor['publishers'].post to, message
|
53
32
|
|
54
33
|
nil
|
55
34
|
end
|
@@ -68,82 +47,7 @@ module Proletariat
|
|
68
47
|
# Internal: Returns an Array of the currently supervised Managers.
|
69
48
|
attr_reader :managers
|
70
49
|
|
71
|
-
# Internal: Returns the pool of initialized publishers.
|
72
|
-
attr_reader :publisher_pool
|
73
|
-
|
74
|
-
# Internal: Returns a shared mailbox for the pool of publishers.
|
75
|
-
attr_reader :publishers_mailbox
|
76
|
-
|
77
|
-
# Internal: Returns the number of publisher threads in the publisher pool.
|
78
|
-
attr_reader :publisher_threads
|
79
|
-
|
80
50
|
# Internal: Returns the supervisor instance.
|
81
51
|
attr_reader :supervisor
|
82
|
-
|
83
|
-
# Internal: Returns an Array of Worker subclasses.
|
84
|
-
attr_reader :worker_classes
|
85
|
-
|
86
|
-
# Internal: Returns the number of worker threads per manager.
|
87
|
-
attr_reader :worker_threads
|
88
|
-
|
89
|
-
# Internal: Adds each publisher in the publisher_pool to the supervisor.
|
90
|
-
#
|
91
|
-
# Returns nil.
|
92
|
-
def add_publishers_to_supervisor
|
93
|
-
publisher_pool.each { |publisher| supervisor.add_worker publisher }
|
94
|
-
|
95
|
-
nil
|
96
|
-
end
|
97
|
-
|
98
|
-
# Internal: Creates a Manager per worker_class and adds these to the
|
99
|
-
# supervisor.
|
100
|
-
#
|
101
|
-
# Returns nil.
|
102
|
-
def add_workers_to_supervisor
|
103
|
-
worker_classes.each do |worker_class|
|
104
|
-
manager = create_manager(worker_class)
|
105
|
-
@managers << manager
|
106
|
-
supervisor.add_worker manager
|
107
|
-
end
|
108
|
-
|
109
|
-
nil
|
110
|
-
end
|
111
|
-
|
112
|
-
# Internal: Creates a new Bunny::Session and opens it.
|
113
|
-
#
|
114
|
-
# Returns an open Bunny::Session instance.
|
115
|
-
def create_connection
|
116
|
-
new_connection = Bunny.new
|
117
|
-
new_connection.start
|
118
|
-
|
119
|
-
new_connection
|
120
|
-
end
|
121
|
-
|
122
|
-
# Internal: Assign new Concurrent::Poolbox and Array[Publisher] to the
|
123
|
-
# manager's publishers_mailbox and publisher_pool properties
|
124
|
-
# respectively.
|
125
|
-
#
|
126
|
-
# Returns nil.
|
127
|
-
def create_publisher_pool
|
128
|
-
@publishers_mailbox, @publisher_pool = Publisher.pool(publisher_threads,
|
129
|
-
connection,
|
130
|
-
exchange_name)
|
131
|
-
end
|
132
|
-
|
133
|
-
# Internal: Creates a new Concurrent::Supervisor.
|
134
|
-
#
|
135
|
-
# Returns a Concurrent::Supervisor instance.
|
136
|
-
def create_supervisor
|
137
|
-
Concurrent::Supervisor.new
|
138
|
-
end
|
139
|
-
|
140
|
-
# Internal: Creates a Manager for a given Worker subclass adding relevant
|
141
|
-
# arguments from Runner properties.
|
142
|
-
#
|
143
|
-
# Returns a Manager instance.
|
144
|
-
def create_manager(worker_class)
|
145
|
-
Manager.new(connection, exchange_name, worker_class,
|
146
|
-
worker_threads: worker_threads)
|
147
|
-
end
|
148
52
|
end
|
149
53
|
end
|