liebre 0.1.21 → 0.2.1
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.
- checksums.yaml +4 -4
- data/.rspec +2 -0
- data/Gemfile.lock +9 -7
- data/{LICENSE → LICENSE.txt} +1 -1
- data/README.md +492 -195
- data/Rakefile +2 -0
- data/lib/liebre.rb +27 -16
- data/lib/liebre/actor.rb +11 -0
- data/lib/liebre/actor/consumer.rb +80 -0
- data/lib/liebre/actor/consumer/callback.rb +34 -0
- data/lib/liebre/actor/consumer/core.rb +80 -0
- data/lib/liebre/actor/consumer/reporter.rb +84 -0
- data/lib/liebre/actor/consumer/resources.rb +47 -0
- data/lib/liebre/actor/consumer/resources/config.rb +65 -0
- data/lib/liebre/actor/context.rb +40 -0
- data/lib/liebre/actor/context/declare.rb +44 -0
- data/lib/liebre/actor/context/handler.rb +44 -0
- data/lib/liebre/actor/publisher.rb +58 -0
- data/lib/liebre/actor/publisher/core.rb +42 -0
- data/lib/liebre/actor/publisher/reporter.rb +55 -0
- data/lib/liebre/actor/publisher/resources.rb +33 -0
- data/lib/liebre/actor/rpc/client.rb +88 -0
- data/lib/liebre/actor/rpc/client/core.rb +75 -0
- data/lib/liebre/actor/rpc/client/pending.rb +65 -0
- data/lib/liebre/actor/rpc/client/reporter.rb +71 -0
- data/lib/liebre/actor/rpc/client/resources.rb +62 -0
- data/lib/liebre/actor/rpc/client/task.rb +33 -0
- data/lib/liebre/actor/rpc/server.rb +74 -0
- data/lib/liebre/actor/rpc/server/callback.rb +28 -0
- data/lib/liebre/actor/rpc/server/core.rb +75 -0
- data/lib/liebre/actor/rpc/server/reporter.rb +72 -0
- data/lib/liebre/actor/rpc/server/resources.rb +53 -0
- data/lib/liebre/adapter.rb +8 -0
- data/lib/liebre/adapter/bunny.rb +23 -0
- data/lib/liebre/adapter/bunny/chan.rb +38 -0
- data/lib/liebre/adapter/bunny/conn.rb +32 -0
- data/lib/liebre/adapter/bunny/exchange.rb +20 -0
- data/lib/liebre/adapter/bunny/queue.rb +59 -0
- data/lib/liebre/adapter/interface.rb +26 -0
- data/lib/liebre/adapter/interface/chan.rb +29 -0
- data/lib/liebre/adapter/interface/conn.rb +21 -0
- data/lib/liebre/adapter/interface/exchange.rb +13 -0
- data/lib/liebre/adapter/interface/queue.rb +37 -0
- data/lib/liebre/bridge.rb +72 -0
- data/lib/liebre/bridge/channel_builder.rb +36 -0
- data/lib/liebre/config.rb +8 -38
- data/lib/liebre/engine.rb +61 -0
- data/lib/liebre/engine/builder.rb +48 -0
- data/lib/liebre/engine/repository.rb +56 -0
- data/lib/liebre/engine/state.rb +49 -0
- data/lib/liebre/runner.rb +15 -47
- data/lib/liebre/version.rb +1 -1
- data/liebre.gemspec +9 -7
- data/spec/integration/publish_and_consume_spec.rb +71 -0
- data/spec/integration/rpc_communication_spec.rb +81 -0
- data/spec/integration/start_twice_spec.rb +63 -0
- data/spec/liebre/actor/consumer_spec.rb +169 -0
- data/spec/liebre/actor/context/declare_spec.rb +69 -0
- data/spec/liebre/actor/context/handler_spec.rb +65 -0
- data/spec/liebre/actor/publisher_spec.rb +58 -0
- data/spec/liebre/actor/rpc/client_spec.rb +126 -0
- data/spec/liebre/actor/rpc/server_spec.rb +141 -0
- data/spec/liebre/adapter/bunny_spec.rb +66 -0
- data/spec/liebre/bridge_spec.rb +54 -0
- data/spec/liebre/engine/builder_spec.rb +42 -0
- data/spec/liebre/engine_spec.rb +90 -0
- data/spec/liebre/version_spec.rb +10 -0
- data/spec/spec_helper.rb +2 -9
- metadata +97 -58
- data/lib/liebre/common.rb +0 -7
- data/lib/liebre/common/utils.rb +0 -37
- data/lib/liebre/connection_manager.rb +0 -85
- data/lib/liebre/publisher.rb +0 -113
- data/lib/liebre/runner/consumers.rb +0 -46
- data/lib/liebre/runner/starter.rb +0 -44
- data/lib/liebre/runner/starter/consumer.rb +0 -129
- data/lib/liebre/runner/starter/consumer/handler.rb +0 -35
- data/lib/liebre/runner/starter/resources.rb +0 -45
- data/lib/liebre/runner/starter/resources/queue_builder.rb +0 -63
- data/lib/liebre/runner/starter/rpc.rb +0 -59
- data/lib/liebre/tasks.rb +0 -12
- data/spec/config/liebre.yml +0 -48
- data/spec/config/rabbitmq.yml +0 -35
- data/spec/integration_spec.rb +0 -76
- data/spec/liebre/config_spec.rb +0 -63
- data/spec/liebre/connection_manager_spec.rb +0 -44
- data/spec/liebre/publisher_spec.rb +0 -92
- data/spec/liebre/runner/consumers_spec.rb +0 -59
- data/spec/liebre/runner/starter/consumer_spec.rb +0 -145
- data/spec/liebre/runner/starter/resources/queue_builder_spec.rb +0 -69
- data/spec/liebre/runner/starter/resources_spec.rb +0 -38
- data/spec/liebre/runner/starter/rpc_spec.rb +0 -100
- data/spec/liebre/runner/starter_spec.rb +0 -70
- data/spec/liebre/runner_spec.rb +0 -54
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d8d00979bc470fd55b7dce291b96658266ea74ac
|
4
|
+
data.tar.gz: 48dff8d83158aa0a84f74a5aaac36e1f86de64b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b4d5fe0344c0cecf9ff3313ff58521406d20b9f6df88aae242bcfc450860f8dabd1180a3f0ec11371297fa2a1792508d279fd7d1b4bbc03dfcafc303dc9631bf
|
7
|
+
data.tar.gz: 20f95bcd2593a5bf0ef664f242fb3d53a7d429d785b83106643eafec38afaee2e021a512f4deb4b442a3f03ecae3f3fae0c9e623e4df0bf6bd1306fdad3e3b2c
|
data/.rspec
ADDED
data/Gemfile.lock
CHANGED
@@ -1,28 +1,29 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
liebre (0.
|
5
|
-
|
4
|
+
liebre (0.2.0)
|
5
|
+
concurrent-ruby
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
10
|
amq-protocol (2.0.1)
|
11
|
-
bunny (2.
|
11
|
+
bunny (2.2.2)
|
12
12
|
amq-protocol (>= 2.0.1)
|
13
13
|
coderay (1.1.1)
|
14
|
-
|
14
|
+
concurrent-ruby (1.0.5)
|
15
|
+
diff-lcs (1.3)
|
15
16
|
method_source (0.8.2)
|
16
17
|
pry (0.10.4)
|
17
18
|
coderay (~> 1.1.0)
|
18
19
|
method_source (~> 0.8.1)
|
19
20
|
slop (~> 3.4)
|
20
|
-
rake (
|
21
|
+
rake (12.0.0)
|
21
22
|
rspec (3.5.0)
|
22
23
|
rspec-core (~> 3.5.0)
|
23
24
|
rspec-expectations (~> 3.5.0)
|
24
25
|
rspec-mocks (~> 3.5.0)
|
25
|
-
rspec-core (3.5.
|
26
|
+
rspec-core (3.5.4)
|
26
27
|
rspec-support (~> 3.5.0)
|
27
28
|
rspec-expectations (3.5.0)
|
28
29
|
diff-lcs (>= 1.2.0, < 2.0)
|
@@ -38,10 +39,11 @@ PLATFORMS
|
|
38
39
|
|
39
40
|
DEPENDENCIES
|
40
41
|
bundler (~> 1.6)
|
42
|
+
bunny
|
41
43
|
liebre!
|
42
44
|
pry
|
43
45
|
rake
|
44
46
|
rspec
|
45
47
|
|
46
48
|
BUNDLED WITH
|
47
|
-
1.
|
49
|
+
1.14.6
|
data/{LICENSE → LICENSE.txt}
RENAMED
data/README.md
CHANGED
@@ -1,268 +1,565 @@
|
|
1
1
|
# Liebre
|
2
2
|
|
3
|
-
|
3
|
+
A library to interact with AMQP servers.
|
4
4
|
|
5
|
-
|
5
|
+
Liebre stands for hare in spanish.
|
6
6
|
|
7
|
-
|
7
|
+
## Installation
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'liebre'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install liebre
|
20
|
+
|
21
|
+
## Introduction
|
22
|
+
|
23
|
+
The Liebre library provides 4 abstractions, or **actors**, to interact with the server:
|
24
|
+
|
25
|
+
* **Publisher**: Publishes messages to an exchange
|
26
|
+
* **Consumer**: Binds a queue to an exchange, and consumes messages
|
27
|
+
* **RPC Client**: Publishes messages to an exchange and blocks until a response is received through an exclusive queue
|
28
|
+
* **RPC Server**: Binds a queue to an exchange, consumes messages, and replies the caller by putting a message at the specified queue
|
29
|
+
|
30
|
+
Each actor has its own thread and its own channel. Some actors (Consumer and RPC Server)
|
31
|
+
also have their own thread pool in order to be able to handle messages concurrently.
|
32
|
+
|
33
|
+
It leverages [concurrent-ruby](https://github.com/ruby-concurrency/concurrent-ruby) `Concurrent::Async` mixin to
|
34
|
+
implement the actors.
|
13
35
|
|
14
36
|
## Configuration
|
15
|
-
It is based on 2 config files:
|
16
37
|
|
17
|
-
|
18
|
-
|
38
|
+
Liebre accepts the following configuration options:
|
39
|
+
|
40
|
+
```ruby
|
41
|
+
Liebre.configure do |config|
|
42
|
+
config.logger = $logger
|
43
|
+
config.adapter = Liebre::Adapter::Bunny
|
44
|
+
config.connections = connections_config
|
45
|
+
config.actors = actors_config
|
46
|
+
end
|
19
47
|
```
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
48
|
+
|
49
|
+
### Logger
|
50
|
+
|
51
|
+
The logger configuration option is optional and defaults to `Logger.new(nil)`.
|
52
|
+
Liebre will log in the following events:
|
53
|
+
|
54
|
+
* An actor is started
|
55
|
+
* An actor is stopped
|
56
|
+
* Some error happened on the actor's thread
|
57
|
+
|
58
|
+
Any other logging should be done from the application.
|
59
|
+
|
60
|
+
### Adapter
|
61
|
+
|
62
|
+
It specifies the adapter to use to interact with the server. The only adapter that ships with
|
63
|
+
the library is the `Liebre::Adapter::Bunny` adapter that uses the `bunny` gem.
|
64
|
+
|
65
|
+
**IMPORTANT**: Note that you should have the `bunny` gem available to use the
|
66
|
+
`Liebre::Adapter::Bunny` adapter.
|
67
|
+
|
68
|
+
### Connections
|
69
|
+
|
70
|
+
On startup Liebre will establish a set of connections with one or more AMQP servers. Actors can be
|
71
|
+
started on any of this connections.
|
72
|
+
|
73
|
+
```ruby
|
74
|
+
{one: {host: "foo.com", port: 123},
|
75
|
+
other: {}}
|
28
76
|
```
|
29
|
-
|
77
|
+
|
78
|
+
The example above will establish two connections, the configuration for each connection
|
79
|
+
will be given with no modification to the adapter.
|
80
|
+
|
81
|
+
### Actors
|
82
|
+
|
83
|
+
The configuration of all actors:
|
84
|
+
|
85
|
+
```ruby
|
86
|
+
{
|
87
|
+
publishers: {
|
88
|
+
my_publisher: {connection: :one,
|
89
|
+
resources: {
|
90
|
+
exchange: {name: "foo", type: "fanout"}}},
|
91
|
+
my_other_pub: {connection: :other,
|
92
|
+
resources: {
|
93
|
+
exchange: {name: "bar", type: "direct", opts: {durable: true}}}}
|
94
|
+
},
|
95
|
+
consumers: {
|
96
|
+
my_consumer: {connection: :one,
|
97
|
+
handler: MyApp::Consumer,
|
98
|
+
prefetch_count: 10,
|
99
|
+
pool_size: 10,
|
100
|
+
resources: {
|
101
|
+
exchange: {name: "baz", type: "fanout"},
|
102
|
+
queue: {name: "baz_queue"},
|
103
|
+
bind: [{routing_key: "a_key"}, {routing_key: "another"}]}},
|
104
|
+
},
|
105
|
+
rpc_clients: {
|
106
|
+
my_rpc_client: {connection: :other,
|
107
|
+
resources: {
|
108
|
+
exchange: {name: "qux", type: "fanout"}}},
|
109
|
+
},
|
110
|
+
rpc_servers: {
|
111
|
+
my_rpc_server: {connection: :one,
|
112
|
+
handler: MyApp::RPCServer,
|
113
|
+
prefetch_count: 5,
|
114
|
+
pool_size: 5,
|
115
|
+
resources: {
|
116
|
+
exchange: {name: "quux", type: "fanout"},
|
117
|
+
queue: {name: "quux_queue"}}}
|
118
|
+
}
|
119
|
+
}
|
30
120
|
```
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
121
|
+
|
122
|
+
The example above will start 5 actors:
|
123
|
+
|
124
|
+
* A publisher to the `"foo"` exchange over the connection `:one`
|
125
|
+
* A publisher to the `"bar"` exchange over the connection `:other`
|
126
|
+
* A consumer of the "baz" queue that will consume messages over the connection `:one` and process them by running `MyApp::Consumer` handler on a pool of 10 dedicated threads
|
127
|
+
* A rpc client to the `"qux"` exchange over the connection `:other`
|
128
|
+
* A rpc server of the "quux" queue that will consume messages over the connection `:one` and process them by running `MyApp::RPCServer` handler on a pool of 5 dedicated threads
|
129
|
+
|
130
|
+
Common options:
|
131
|
+
|
132
|
+
* `:connection` - The name of the connection to open the channel over
|
133
|
+
* `:resources` - Configuration about queues and exchanges. Depends on the actor
|
134
|
+
|
135
|
+
Options for message handlers (Consumer and RPC Server):
|
136
|
+
|
137
|
+
* `:handler` - The class to use to handle messages. Its interface depends on the actor
|
138
|
+
* `:prefetch_count` - The prefetch count of the actor's channel
|
139
|
+
* `:pool_size` - The number of dedicated threads that will be used to handle messages concurrently
|
140
|
+
|
141
|
+
## Start the engine
|
142
|
+
|
143
|
+
### On an existing service
|
144
|
+
|
145
|
+
A `Liebre::Engine` is an object that is able to start and stop a given configuration.
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
require 'yaml'
|
149
|
+
require 'liebre'
|
150
|
+
|
151
|
+
config = Liebre::Config.new
|
152
|
+
|
153
|
+
config.adapter = Liebre::Adapter::Bunny
|
154
|
+
config.connections = YAML.load_file("config/rabbitmq.yml")
|
155
|
+
config.actors = YAML.load_file("config/liebre.yml")
|
156
|
+
|
157
|
+
engine = Liebre::Engine.new(config)
|
158
|
+
engine.start
|
68
159
|
```
|
69
160
|
|
70
|
-
|
161
|
+
The example above will establish the specified connections and start all actors with
|
162
|
+
their own threads and thread pools.
|
163
|
+
|
164
|
+
Usually only one engine is required per application. To simplify the process, a default
|
165
|
+
engine that uses the default config is provided.
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
require 'liebre'
|
169
|
+
|
170
|
+
Liebre.configure do |config|
|
171
|
+
config.adapter = Liebre::Adapter::Bunny
|
172
|
+
config.connections = YAML.load_file("config/rabbitmq.yml")
|
173
|
+
config.actors = YAML.load_file("config/liebre.yml")
|
174
|
+
end
|
175
|
+
|
176
|
+
Liebre.engine.start
|
177
|
+
```
|
178
|
+
|
179
|
+
This kind of startup is commonly used on rack applications. The previous code
|
180
|
+
can be called from a Rails initializer.
|
181
|
+
|
182
|
+
### As a standalone application
|
183
|
+
|
184
|
+
If you wish to start Liebre as a standalone application `Liebre::Runner` is provided.
|
185
|
+
|
186
|
+
```ruby
|
187
|
+
require 'liebre'
|
188
|
+
|
189
|
+
Liebre.configure do |config|
|
190
|
+
# some config
|
191
|
+
end
|
192
|
+
|
193
|
+
runner = Liebre::Runner.new(engine: Liebre.engine)
|
194
|
+
runner.run
|
71
195
|
```
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
durable: false
|
89
|
-
bind:
|
90
|
-
routing_key: #key a string or an array of strings
|
91
|
-
- key_1
|
92
|
-
- key_2
|
93
|
-
|
94
|
-
some_rpc:
|
95
|
-
class_name: MyRPC
|
96
|
-
rpc: true
|
97
|
-
connection_name: rpc
|
98
|
-
pool_size: 1
|
99
|
-
exchange:
|
100
|
-
name: "rpc_exchange"
|
101
|
-
type: "fanout"
|
102
|
-
opts:
|
103
|
-
durable: false
|
104
|
-
queue:
|
105
|
-
name: "rpc_queue"
|
106
|
-
opts:
|
107
|
-
durable: false
|
108
|
-
|
109
|
-
publishers:
|
110
|
-
some_publisher:
|
111
|
-
exchange:
|
112
|
-
name: "consumer_exchange"
|
113
|
-
type: "fanout"
|
114
|
-
opts:
|
115
|
-
durable: false
|
116
|
-
rpc_publisher:
|
117
|
-
connection_name: rpc
|
118
|
-
exchange:
|
119
|
-
name: "rpc_exchange"
|
120
|
-
type: "fanout"
|
121
|
-
opts:
|
122
|
-
durable: false
|
196
|
+
|
197
|
+
The example above starts the runner with the default engine
|
198
|
+
|
199
|
+
It sets up some system signals in order to respond gracefully to unix `kill`
|
200
|
+
and sleeps the main thread forever.
|
201
|
+
|
202
|
+
The previous pattern is so common that a shortcut is provided:
|
203
|
+
|
204
|
+
```ruby
|
205
|
+
require 'liebre'
|
206
|
+
|
207
|
+
Liebre.configure do |config|
|
208
|
+
# some config
|
209
|
+
end
|
210
|
+
|
211
|
+
Liebre.start
|
123
212
|
```
|
124
213
|
|
125
|
-
###
|
214
|
+
### Start partially
|
126
215
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
* `connection_name`: the name of the connection to use (default `default`)
|
131
|
-
* `pool_size` of the connection channel (default 1)
|
132
|
-
* `num_threads`: number of consumers of the queue (default 1)
|
133
|
-
* `exchange` a hash of options:
|
134
|
-
* `name`: the exchange name
|
135
|
-
* `type`: the exchange type (fanout, direct or topic)
|
136
|
-
* `opts`: options hash to pass to bunny exchange function
|
137
|
-
* `queue` a hash of options:
|
138
|
-
* `name`: the queue name
|
139
|
-
* `opts`: options hash to pass to bunny queue function
|
140
|
-
* `bind` a hash of options (optional):
|
141
|
-
* `routing_key`: the binding routing key, it can be a single string or an array of strings
|
216
|
+
Imagine the following setup: You have an application that may be started as a rack
|
217
|
+
application and also as a worker with no rack interface to consume from rabbitmq as
|
218
|
+
a background tasks system.
|
142
219
|
|
143
|
-
|
220
|
+
When you start the application with rack you may use publishers or rpc clients, but
|
221
|
+
you don't want to start the consumers and rpc servers.
|
144
222
|
|
145
|
-
|
146
|
-
* `connection_name`: the name of the connection to use (default `default`)
|
147
|
-
* `exchange` a hash of options:
|
148
|
-
* `name`: the exchange name
|
149
|
-
* `type`: the exchange type (fanout, direct or topic)
|
150
|
-
* `opts`: options hash to pass to bunny exchange function
|
223
|
+
When you start the application with `Liebre::Runner` you want all actors to start.
|
151
224
|
|
152
|
-
|
225
|
+
To handle this kind of scenarios `Liebre` keeps track of the already started actors
|
226
|
+
and prevents them to start twice on a given engine.
|
153
227
|
|
154
|
-
|
228
|
+
A solution to this case may be the following:
|
155
229
|
|
156
|
-
|
230
|
+
Start all publishers and consumers on an initialized that will be shared between
|
231
|
+
both ways to start the application:
|
157
232
|
|
158
|
-
|
233
|
+
```ruby
|
234
|
+
require 'liebre'
|
159
235
|
|
236
|
+
Liebre.configure do |config|
|
237
|
+
# some config
|
238
|
+
end
|
239
|
+
|
240
|
+
Liebre.engine.start(only: [:publishers, :rpc_clients])
|
160
241
|
```
|
161
|
-
Liebre::Config.config_path = "your/custom/path"
|
162
|
-
Liebre::Config.connection_path = "your/custom/path"
|
163
242
|
|
164
|
-
Liebre
|
165
|
-
|
243
|
+
This code will configure `Liebre` and starts all publishers and rpc clients.
|
244
|
+
|
245
|
+
When you start your application with `Liebre::Runner` you can do the following:
|
246
|
+
|
247
|
+
```ruby
|
248
|
+
# run all your initializers including the one above
|
166
249
|
|
250
|
+
require 'liebre'
|
251
|
+
Liebre.start
|
167
252
|
```
|
168
253
|
|
169
|
-
|
254
|
+
This code will start all actors, and publishers and rpc clients will only be started
|
255
|
+
once.
|
170
256
|
|
171
|
-
|
257
|
+
## Actors
|
172
258
|
|
173
|
-
|
259
|
+
Once a liebre engine has been started a `Liebre::Repository` has been populated with all actors
|
260
|
+
that can be fetched by name.
|
174
261
|
|
175
|
-
|
262
|
+
```ruby
|
263
|
+
# ... start the engine
|
264
|
+
repo = engine.repo
|
176
265
|
|
266
|
+
publisher_1 = repo.publisher(:my_publisher)
|
267
|
+
publisher_2 = repo.publisher(:my_other_pub)
|
268
|
+
consumer = repo.consumer(:my_consumer)
|
269
|
+
rpc_client = repo.rpc_server(:my_rpc_server)
|
270
|
+
rpc_server = repo.rpc_server(:my_rpc_server)
|
177
271
|
```
|
178
|
-
class MyConsumer
|
179
|
-
|
180
|
-
def initialize payload, meta
|
181
|
-
@payload = payload #the content of the message
|
182
|
-
@meta = meta #the meta information (also called properties)
|
183
|
-
end
|
184
272
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
273
|
+
### Publisher
|
274
|
+
|
275
|
+
A publisher is an actor that declares an exchange on startup and provides a method to publish
|
276
|
+
messages to that exchange.
|
277
|
+
|
278
|
+
The `:resources` section of the actor's configuration requires the exchange specification:
|
279
|
+
|
280
|
+
```ruby
|
281
|
+
require 'liebre'
|
192
282
|
|
283
|
+
Liebre.configure do |config|
|
284
|
+
config.adapter = Liebre::Adapter::Bunny
|
285
|
+
config.connections = {default: {}}
|
286
|
+
|
287
|
+
config.actors = {
|
288
|
+
publishers: {
|
289
|
+
my_pub: {
|
290
|
+
connection: :default,
|
291
|
+
resources: {
|
292
|
+
exchange: {name: "foo",
|
293
|
+
type: "direct",
|
294
|
+
opts: {durable: true}}
|
295
|
+
}
|
296
|
+
}
|
297
|
+
}
|
298
|
+
}
|
193
299
|
end
|
300
|
+
|
301
|
+
Liebre.engine.start
|
302
|
+
|
303
|
+
publisher = Liebre.repo.publisher(:my_pub)
|
304
|
+
publisher.publish("some_data")
|
305
|
+
publisher.publish("more_data", :routing_key => "my_key")
|
194
306
|
```
|
195
307
|
|
196
|
-
|
308
|
+
The exchange specification:
|
197
309
|
|
198
|
-
|
310
|
+
* `:name` - The name of the exchange
|
311
|
+
* `:type` - The exchange type (`"direct"`, `"fanout"`, etc)
|
312
|
+
* `:opts` - (defaults to `{}`) The exchange options
|
199
313
|
|
200
|
-
|
314
|
+
Once started the `#publish` method can be used to send messages to the configured
|
315
|
+
exchange.
|
316
|
+
|
317
|
+
### Consumer
|
318
|
+
|
319
|
+
A consumer is an actor that declares an exchange, a queue and binds them on startup.
|
320
|
+
It owns a thread pool to handle consumed messages.
|
321
|
+
|
322
|
+
After declaration it subscribes to the queue and starts consuming messages. Once a message
|
323
|
+
is consumed a handler for that message is started in a thread of the pool.
|
324
|
+
|
325
|
+
The handler class must implement the following interface:
|
326
|
+
|
327
|
+
* `#initialize` receives 3 arguments: `payload`, `meta`, and `callback`.
|
328
|
+
* `#call`
|
329
|
+
|
330
|
+
The handler class is initialized with that 3 arguments:
|
331
|
+
|
332
|
+
* `payload` - The actual content of the message
|
333
|
+
* `meta` - Message metadata that includes the headers and other information (depends on the adapter)
|
334
|
+
* `callback` - An object that responds to `#ack`, `#nack`, and `#reject`
|
335
|
+
|
336
|
+
```ruby
|
337
|
+
class MyHandler
|
201
338
|
|
202
|
-
```
|
203
|
-
class MyRPC
|
204
|
-
|
205
339
|
def initialize payload, meta, callback
|
206
|
-
@payload
|
207
|
-
@
|
208
|
-
@callback = callback #a Proc that will publish an answer
|
340
|
+
@payload = payload
|
341
|
+
@callback = callback
|
209
342
|
end
|
210
343
|
|
211
344
|
def call
|
212
|
-
|
213
|
-
|
345
|
+
case payload
|
346
|
+
when "0" then zero()
|
347
|
+
when "1" then one()
|
348
|
+
else raise "unknown!"
|
349
|
+
end
|
214
350
|
end
|
215
351
|
|
352
|
+
private
|
353
|
+
|
354
|
+
def zero
|
355
|
+
puts "yay!"
|
356
|
+
callback.ack()
|
357
|
+
end
|
358
|
+
|
359
|
+
def one
|
360
|
+
puts "wtf!"
|
361
|
+
callback.reject(requeue: false)
|
362
|
+
end
|
363
|
+
|
364
|
+
attr_reader :payload, :callback
|
365
|
+
|
216
366
|
end
|
217
367
|
```
|
218
368
|
|
219
|
-
|
369
|
+
The handler above will print `"yay!"` and ack the message when the payload is `"0"`,
|
370
|
+
print `"wtf!"` and reject the message when the payload is `"1"`, and will raise (and therefore
|
371
|
+
will be rejected by liebre) when the handler raises an error.
|
220
372
|
|
221
|
-
|
373
|
+
The `:resources` section of the actor's configuration requires the exchange and the queue,
|
374
|
+
and may include binding options.
|
222
375
|
|
223
|
-
|
376
|
+
```ruby
|
377
|
+
require 'liebre'
|
378
|
+
|
379
|
+
Liebre.configure do |config|
|
380
|
+
config.adapter = Liebre::Adapter::Bunny
|
381
|
+
config.connections = {default: {}}
|
382
|
+
|
383
|
+
config.actors = {
|
384
|
+
consumers: {
|
385
|
+
my_con: {
|
386
|
+
connection: :default,
|
387
|
+
handler: MyHandler,
|
388
|
+
prefetch_count: 5,
|
389
|
+
pool_size: 5,
|
390
|
+
resources: {
|
391
|
+
exchange: {name: "foo",
|
392
|
+
type: "direct",
|
393
|
+
opts: {durable: true}},
|
394
|
+
queue: {name: "bar",
|
395
|
+
opts: {durable: true}},
|
396
|
+
bind: [{routing_key: "one"},
|
397
|
+
{routing_key: "other"}]
|
398
|
+
}
|
399
|
+
}
|
400
|
+
}
|
401
|
+
}
|
402
|
+
end
|
224
403
|
|
404
|
+
Liebre.engine.start
|
225
405
|
```
|
226
|
-
publisher = Liebre::Publisher.new("some_publisher_name")
|
227
406
|
|
228
|
-
|
407
|
+
The exchange specification is the same as for the publisher.
|
229
408
|
|
230
|
-
|
409
|
+
The queue specification:
|
231
410
|
|
232
|
-
|
411
|
+
* `:name` - The name of the queue
|
412
|
+
* `:opts` - (defaults to `{}`) The queue options
|
233
413
|
|
234
|
-
|
414
|
+
The bind specification is optional and defaults to `{}`. `:bind` value may be:
|
235
415
|
|
236
|
-
|
237
|
-
|
416
|
+
* not present - the queue is bound to the exchange once with `{}` as options
|
417
|
+
* a hash - the queues is bound once to the exchange with that options
|
418
|
+
* a list of hashes - the queues is bound to the exchange once per hash of options
|
238
419
|
|
239
|
-
|
420
|
+
The example above declares the exchange `"foo"`, declares the queue `"bar"`,
|
421
|
+
binds the queue to the exchange twice: one with the `"one"` routing key and
|
422
|
+
another with the `"other"` routing key).
|
240
423
|
|
241
|
-
|
424
|
+
It starts a thread pool of 5 threads and starts consuming messages.
|
242
425
|
|
243
|
-
|
426
|
+
For each message the consumer receives a handler is instantiated and `#call` is called on
|
427
|
+
it in one of the threads of its pool.
|
244
428
|
|
245
|
-
###
|
429
|
+
### RPC Client
|
246
430
|
|
247
|
-
|
248
|
-
|
249
|
-
gem "liebre", ">~ 0.1"
|
250
|
-
```
|
431
|
+
A RPC client is an actor that declares an exchange, and declares a temporary queue with
|
432
|
+
the options `exclusive`, and `auto_delete`.
|
251
433
|
|
252
|
-
|
434
|
+
After declaration it subscribes to the queue.
|
253
435
|
|
254
|
-
|
255
|
-
require "liebre/tasks"
|
256
|
-
```
|
436
|
+
The `:resources` section of the rpc client configuration must specify the exchange.
|
257
437
|
|
258
|
-
|
259
|
-
|
260
|
-
|
438
|
+
```ruby
|
439
|
+
require 'liebre'
|
440
|
+
|
441
|
+
Liebre.configure do |config|
|
442
|
+
config.adapter = Liebre::Adapter::Bunny
|
443
|
+
config.connections = {default: {}}
|
444
|
+
|
445
|
+
config.actors = {
|
446
|
+
rpc_client: {
|
447
|
+
my_client: {
|
448
|
+
connection: :default,
|
449
|
+
resources: {
|
450
|
+
exchange: {name: "foo",
|
451
|
+
type: "direct",
|
452
|
+
opts: {durable: true}},
|
453
|
+
queue: {prefix: "client_responses"}
|
454
|
+
}
|
455
|
+
}
|
456
|
+
}
|
457
|
+
}
|
458
|
+
end
|
459
|
+
|
460
|
+
Liebre.engine.start
|
461
|
+
|
462
|
+
client = Liebre.repo.rpc_client(:my_pub)
|
463
|
+
client.request("data") # => rpc server response (or nil on timeout, 5 seconds by default)
|
464
|
+
client.request("data", routing_key: "bar") # => rpc server response (or nil on timeout, 5 seconds by default)
|
465
|
+
client.request("data", {}, 15) # => rpc server response (or nil on timeout after 15 seconds)
|
261
466
|
```
|
262
467
|
|
263
|
-
|
468
|
+
The exchange specification is the same as for the publisher.
|
469
|
+
|
470
|
+
The queue specification is optional and includes a prefix for the queue's name. The name of the
|
471
|
+
queue will be that prefix followed by a random token, for example: `"client_responses_q23jrefdzXw"`.
|
472
|
+
|
473
|
+
When a request is performed the client will block until the response is received or the timeout is reached.
|
474
|
+
|
475
|
+
### RPC Server
|
476
|
+
|
477
|
+
A rpc server is an actor that declares an exchange, a queue and binds them on startup.
|
478
|
+
It owns a thread pool to handle requests.
|
479
|
+
|
480
|
+
After declaration it subscribes to the queue and starts consuming messages. Once a message
|
481
|
+
is consumed a handler for that message is started in a thread of the pool.
|
482
|
+
|
483
|
+
The handler class must implement the following interface:
|
484
|
+
|
485
|
+
* `#initialize` receives 3 arguments: `payload`, `meta`, and `callback`.
|
486
|
+
* `#call`
|
487
|
+
|
488
|
+
The handler class is initialized with that 3 arguments:
|
489
|
+
|
490
|
+
* `payload` - The actual content of the message
|
491
|
+
* `meta` - Message metadata that includes the headers and other information (depends on the adapter)
|
492
|
+
* `callback` - An object that responds to `#reply`
|
493
|
+
|
494
|
+
```ruby
|
495
|
+
class MyHandler
|
496
|
+
|
497
|
+
def initialize payload, meta, callback
|
498
|
+
@payload = payload
|
499
|
+
@callback = callback
|
500
|
+
end
|
501
|
+
|
502
|
+
def call
|
503
|
+
case payload
|
504
|
+
when "0" then callback.reply("zero")
|
505
|
+
when "1" then callback.reply("one")
|
506
|
+
else raise "unknown!"
|
507
|
+
end
|
508
|
+
end
|
509
|
+
|
510
|
+
private
|
511
|
+
|
512
|
+
attr_reader :payload, :callback
|
513
|
+
|
514
|
+
end
|
264
515
|
```
|
516
|
+
|
517
|
+
The handler above will reply to the client with "zero" when payload is "0",
|
518
|
+
reply with "one" when the payload is "1", and will raise (and therefore not reply)
|
519
|
+
when the handler raises error.
|
520
|
+
|
521
|
+
The `:resources` section of the actor's configuration requires the exchange and the queue,
|
522
|
+
and may include binding options.
|
523
|
+
|
524
|
+
```ruby
|
265
525
|
require 'liebre'
|
266
526
|
|
267
|
-
Liebre
|
268
|
-
|
527
|
+
Liebre.configure do |config|
|
528
|
+
config.adapter = Liebre::Adapter::Bunny
|
529
|
+
config.connections = {default: {}}
|
530
|
+
|
531
|
+
config.actors = {
|
532
|
+
rpc_servers: {
|
533
|
+
my_rpc_server: {
|
534
|
+
connection: :default,
|
535
|
+
handler: MyHandler,
|
536
|
+
prefetch_count: 5,
|
537
|
+
pool_size: 5,
|
538
|
+
resources: {
|
539
|
+
exchange: {name: "foo",
|
540
|
+
type: "direct",
|
541
|
+
opts: {durable: true}},
|
542
|
+
queue: {name: "bar",
|
543
|
+
opts: {durable: true}},
|
544
|
+
bind: [{routing_key: "one"},
|
545
|
+
{routing_key: "other"}]
|
546
|
+
}
|
547
|
+
}
|
548
|
+
}
|
549
|
+
}
|
550
|
+
end
|
551
|
+
|
552
|
+
Liebre.engine.start
|
553
|
+
```
|
554
|
+
|
555
|
+
The exchange specification is the same as for the publisher.
|
556
|
+
The queue and bind specifications are the same as for the consumer.
|
557
|
+
|
558
|
+
The example above declares the exchange `"foo"`, declares the queue `"bar"`,
|
559
|
+
binds the queue to the exchange twice: one with the `"one"` routing key and
|
560
|
+
another with the `"other"` routing key).
|
561
|
+
|
562
|
+
It starts a thread pool of 5 threads and starts consuming requests.
|
563
|
+
|
564
|
+
For each message the consumer receives it instantiates and runs `#call` on
|
565
|
+
the new handler in one of the threads of its pool.
|