liebre 0.1.3
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 +7 -0
- data/.gitignore +51 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +47 -0
- data/LICENSE +22 -0
- data/README.md +268 -0
- data/lib/liebre.rb +24 -0
- data/lib/liebre/common.rb +7 -0
- data/lib/liebre/common/utils.rb +24 -0
- data/lib/liebre/config.rb +48 -0
- data/lib/liebre/connection_manager.rb +64 -0
- data/lib/liebre/publisher.rb +88 -0
- data/lib/liebre/runner.rb +59 -0
- data/lib/liebre/runner/consumers.rb +36 -0
- data/lib/liebre/runner/starter.rb +40 -0
- data/lib/liebre/runner/starter/consumer.rb +91 -0
- data/lib/liebre/runner/starter/consumer/handler.rb +35 -0
- data/lib/liebre/runner/starter/resources.rb +39 -0
- data/lib/liebre/runner/starter/resources/queue_builder.rb +58 -0
- data/lib/liebre/runner/starter/rpc.rb +45 -0
- data/lib/liebre/tasks.rb +12 -0
- data/lib/liebre/version.rb +5 -0
- data/liebre.gemspec +26 -0
- data/spec/config/liebre.yml +47 -0
- data/spec/config/rabbitmq.yml +35 -0
- data/spec/integration_spec.rb +73 -0
- data/spec/liebre/config_spec.rb +62 -0
- data/spec/liebre/connection_manager_spec.rb +40 -0
- data/spec/liebre/publisher_spec.rb +86 -0
- data/spec/liebre/runner/consumers_spec.rb +59 -0
- data/spec/liebre/runner/starter/consumer_spec.rb +140 -0
- data/spec/liebre/runner/starter/resources/queue_builder_spec.rb +69 -0
- data/spec/liebre/runner/starter/resources_spec.rb +36 -0
- data/spec/liebre/runner/starter/rpc_spec.rb +92 -0
- data/spec/liebre/runner/starter_spec.rb +59 -0
- data/spec/liebre/runner_spec.rb +50 -0
- data/spec/spec_helper.rb +23 -0
- metadata +172 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
module Liebre
|
2
|
+
class Runner
|
3
|
+
class Starter
|
4
|
+
class Resources
|
5
|
+
autoload :QueueBuilder, "liebre/runner/starter/resources/queue_builder"
|
6
|
+
|
7
|
+
def initialize connection, config
|
8
|
+
@connection = connection
|
9
|
+
@config = config
|
10
|
+
end
|
11
|
+
|
12
|
+
def exchange
|
13
|
+
@exchange ||= queue_builder.exchange
|
14
|
+
end
|
15
|
+
|
16
|
+
def queue
|
17
|
+
@queue ||= queue_builder.queue
|
18
|
+
end
|
19
|
+
|
20
|
+
def channel
|
21
|
+
@channel ||= connection.create_channel(nil, pool_size)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def queue_builder
|
27
|
+
@queue_bilder ||= QueueBuilder.new(channel, config)
|
28
|
+
end
|
29
|
+
|
30
|
+
def pool_size
|
31
|
+
config.fetch("pool_size", 1)
|
32
|
+
end
|
33
|
+
|
34
|
+
attr_reader :connection, :config
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Liebre
|
2
|
+
class Runner
|
3
|
+
class Starter
|
4
|
+
class Resources
|
5
|
+
class QueueBuilder
|
6
|
+
|
7
|
+
def initialize channel, config
|
8
|
+
@channel = channel
|
9
|
+
@config = config
|
10
|
+
end
|
11
|
+
|
12
|
+
def queue
|
13
|
+
q = channel.queue(queue_name, queue_opts)
|
14
|
+
routing_keys.each do |key|
|
15
|
+
q.bind(exchange, bind_opts.merge(:routing_key => key))
|
16
|
+
end
|
17
|
+
q
|
18
|
+
end
|
19
|
+
|
20
|
+
def exchange
|
21
|
+
Liebre::Common::Utils.create_exchange channel, exchange_config
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def queue_name
|
27
|
+
queue_config.fetch("name")
|
28
|
+
end
|
29
|
+
|
30
|
+
def queue_opts
|
31
|
+
Liebre::Common::Utils.symbolize_keys queue_config.fetch("opts", {})
|
32
|
+
end
|
33
|
+
|
34
|
+
def exchange_config
|
35
|
+
config.fetch("exchange")
|
36
|
+
end
|
37
|
+
|
38
|
+
def queue_config
|
39
|
+
config.fetch("queue")
|
40
|
+
end
|
41
|
+
|
42
|
+
def routing_keys
|
43
|
+
bind_opts[:routing_key] ||= queue_name
|
44
|
+
bind_opts[:routing_key] = [*bind_opts[:routing_key]]
|
45
|
+
bind_opts.delete :routing_key
|
46
|
+
end
|
47
|
+
|
48
|
+
def bind_opts
|
49
|
+
@bind_opts ||= Liebre::Common::Utils.symbolize_keys config.fetch("bind", {})
|
50
|
+
end
|
51
|
+
|
52
|
+
attr_reader :channel, :config
|
53
|
+
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Liebre
|
2
|
+
class Runner
|
3
|
+
class Starter
|
4
|
+
class RPC < Consumer
|
5
|
+
|
6
|
+
def call
|
7
|
+
queue.subscribe(:manual_ack => false) do |_info, meta, payload|
|
8
|
+
begin
|
9
|
+
logger.debug "Received message for #{klass.name}: #{payload} - #{meta}"
|
10
|
+
consumer = klass.new(payload, meta, callback(meta))
|
11
|
+
consumer.call
|
12
|
+
rescue => e
|
13
|
+
logger.error e.inspect
|
14
|
+
logger.error e.backtrace.join("\n")
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def callback meta
|
22
|
+
opts = {
|
23
|
+
:routing_key => meta.reply_to,
|
24
|
+
:correlation_id => meta.correlation_id,
|
25
|
+
:headers => meta.headers
|
26
|
+
}
|
27
|
+
|
28
|
+
lambda do |response|
|
29
|
+
logger.debug "Responding with #{response}"
|
30
|
+
exchange.publish(response, opts)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def exchange
|
35
|
+
channel.default_exchange
|
36
|
+
end
|
37
|
+
|
38
|
+
def parse_config
|
39
|
+
config
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
data/lib/liebre/tasks.rb
ADDED
data/liebre.gemspec
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'liebre/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "liebre"
|
8
|
+
spec.version = Liebre::VERSION
|
9
|
+
spec.authors = ["jcabotc", "graimon"]
|
10
|
+
spec.email = ["jcabot@gmail.com"]
|
11
|
+
spec.summary = %q{A gem to consume and publish to RabbitMQ based on Bunny, creates a thread for every consumer}
|
12
|
+
spec.homepage = "https://github.com/qustodian/liebre"
|
13
|
+
spec.license = "MIT"
|
14
|
+
|
15
|
+
spec.files = `git ls-files -z`.split("\x0")
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ["lib"]
|
19
|
+
|
20
|
+
spec.add_runtime_dependency "bunny", '~> 2.5', '>= 2.5.1'
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", '~> 1.6'
|
23
|
+
spec.add_development_dependency "rspec"
|
24
|
+
spec.add_development_dependency "pry"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
rpc_request_timeout: 30
|
2
|
+
|
3
|
+
consumers:
|
4
|
+
some_consumer:
|
5
|
+
class_name: MyConsumer
|
6
|
+
rpc: false
|
7
|
+
pool_size: 1
|
8
|
+
num_threads: 3
|
9
|
+
exchange:
|
10
|
+
name: "consumer_exchange"
|
11
|
+
type: "fanout"
|
12
|
+
opts:
|
13
|
+
durable: false
|
14
|
+
queue:
|
15
|
+
name: "consumer_queue"
|
16
|
+
opts:
|
17
|
+
durable: false
|
18
|
+
|
19
|
+
some_rpc:
|
20
|
+
class_name: MyRPC
|
21
|
+
rpc: true
|
22
|
+
connection_name: rpc
|
23
|
+
pool_size: 1
|
24
|
+
exchange:
|
25
|
+
name: "rpc_exchange"
|
26
|
+
type: "fanout"
|
27
|
+
opts:
|
28
|
+
durable: false
|
29
|
+
queue:
|
30
|
+
name: "rpc_queue"
|
31
|
+
opts:
|
32
|
+
durable: false
|
33
|
+
|
34
|
+
publishers:
|
35
|
+
some_publisher:
|
36
|
+
exchange:
|
37
|
+
name: "consumer_exchange"
|
38
|
+
type: "fanout"
|
39
|
+
opts:
|
40
|
+
durable: false
|
41
|
+
rpc_publisher:
|
42
|
+
connection_name: rpc
|
43
|
+
exchange:
|
44
|
+
name: "rpc_exchange"
|
45
|
+
type: "fanout"
|
46
|
+
opts:
|
47
|
+
durable: false
|
@@ -0,0 +1,35 @@
|
|
1
|
+
development:
|
2
|
+
default:
|
3
|
+
:host: localhost
|
4
|
+
:port: 5672
|
5
|
+
:user: guest
|
6
|
+
:pass: guest
|
7
|
+
:vhost: /
|
8
|
+
:threaded: true
|
9
|
+
:heartbeat: 2
|
10
|
+
rpc:
|
11
|
+
:host: localhost
|
12
|
+
:port: 5672
|
13
|
+
:user: guest
|
14
|
+
:pass: guest
|
15
|
+
:vhost: /
|
16
|
+
:threaded: true
|
17
|
+
:heartbeat: 2
|
18
|
+
|
19
|
+
test:
|
20
|
+
default:
|
21
|
+
:host: localhost
|
22
|
+
:port: 5672
|
23
|
+
:user: guest
|
24
|
+
:pass: guest
|
25
|
+
:vhost: /
|
26
|
+
:threaded: true
|
27
|
+
:heartbeat: 2
|
28
|
+
rpc:
|
29
|
+
:host: localhost
|
30
|
+
:port: 5672
|
31
|
+
:user: guest
|
32
|
+
:pass: guest
|
33
|
+
:vhost: /
|
34
|
+
:threaded: true
|
35
|
+
:heartbeat: 2
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe "Integration" do
|
4
|
+
|
5
|
+
class MyConsumer
|
6
|
+
|
7
|
+
def initialize payload, meta
|
8
|
+
@payload = payload
|
9
|
+
@meta = meta
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
|
14
|
+
class MyRPC
|
15
|
+
|
16
|
+
def initialize payload, meta, callback
|
17
|
+
@payload = payload
|
18
|
+
@meta = meta
|
19
|
+
@callback = callback
|
20
|
+
end
|
21
|
+
|
22
|
+
def call
|
23
|
+
@callback.call(@payload)
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
let :config_path do
|
29
|
+
File.expand_path("../config/liebre.yml" ,__FILE__)
|
30
|
+
end
|
31
|
+
|
32
|
+
let :connection_path do
|
33
|
+
File.expand_path("../config/rabbitmq.yml" ,__FILE__)
|
34
|
+
end
|
35
|
+
|
36
|
+
before do
|
37
|
+
Liebre::Config.config_path = config_path
|
38
|
+
Liebre::Config.connection_path = connection_path
|
39
|
+
end
|
40
|
+
|
41
|
+
let(:consumer) { double 'consumer' }
|
42
|
+
|
43
|
+
it do
|
44
|
+
|
45
|
+
main_thread = Thread.new do
|
46
|
+
server = Liebre::Runner.new
|
47
|
+
server.start
|
48
|
+
end
|
49
|
+
|
50
|
+
publisher = Liebre::Publisher.new("some_publisher")
|
51
|
+
|
52
|
+
allow(MyConsumer).to receive(:new).with("hello", anything).and_return consumer
|
53
|
+
|
54
|
+
#the consumer returns first :ack, then :reject and the message gets requed, then :error, and the message turns dead-lettered
|
55
|
+
expect(consumer).to receive(:call).and_return :ack, :reject, :error
|
56
|
+
|
57
|
+
publisher.enqueue "hello", :routing_key => "consumer_queue" #:ack
|
58
|
+
publisher.enqueue "hello", :routing_key => "consumer_queue" #:reject then :error
|
59
|
+
|
60
|
+
|
61
|
+
|
62
|
+
rpc_publisher = Liebre::Publisher.new("rpc_publisher")
|
63
|
+
|
64
|
+
param = "return this string"
|
65
|
+
|
66
|
+
result = rpc_publisher.rpc param, :routing_key => "rpc_queue"
|
67
|
+
|
68
|
+
expect(result).to eq param
|
69
|
+
|
70
|
+
sleep 0.1
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Liebre::Config do
|
4
|
+
|
5
|
+
let :config_path do
|
6
|
+
File.expand_path("../../config/liebre.yml" ,__FILE__)
|
7
|
+
end
|
8
|
+
|
9
|
+
let :connection_path do
|
10
|
+
File.expand_path("../../config/rabbitmq.yml" ,__FILE__)
|
11
|
+
end
|
12
|
+
|
13
|
+
before do
|
14
|
+
described_class.config_path = config_path
|
15
|
+
described_class.connection_path = connection_path
|
16
|
+
described_class.env = "some_env"
|
17
|
+
end
|
18
|
+
|
19
|
+
subject { described_class.new }
|
20
|
+
|
21
|
+
describe '.config_path and .connection_path and .env' do
|
22
|
+
|
23
|
+
it do
|
24
|
+
expect(described_class.config_path).to eq config_path
|
25
|
+
expect(described_class.connection_path).to eq connection_path
|
26
|
+
expect(described_class.env).to eq "some_env"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#consumers' do
|
31
|
+
|
32
|
+
let(:consumer_names) { %w{ some_consumer some_rpc } }
|
33
|
+
|
34
|
+
let(:consumer_config) do
|
35
|
+
{
|
36
|
+
'class_name' => "MyConsumer",
|
37
|
+
'rpc' => false
|
38
|
+
}
|
39
|
+
end
|
40
|
+
|
41
|
+
let(:rpc_config) do
|
42
|
+
{
|
43
|
+
'class_name' => "MyRPC",
|
44
|
+
'rpc' => true
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
it do
|
49
|
+
|
50
|
+
expect(subject.consumers.keys).to eq consumer_names
|
51
|
+
|
52
|
+
expect(subject.consumers['some_consumer']['class_name']).to eq consumer_config['class_name']
|
53
|
+
expect(subject.consumers['some_consumer']['rpc']).to eq consumer_config['rpc']
|
54
|
+
|
55
|
+
expect(subject.consumers['some_rpc']['class_name']).to eq rpc_config['class_name']
|
56
|
+
expect(subject.consumers['some_rpc']['rpc']).to eq rpc_config['rpc']
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Liebre::ConnectionManager do
|
4
|
+
|
5
|
+
let :connection_path do
|
6
|
+
File.expand_path("../../config/rabbitmq.yml" ,__FILE__)
|
7
|
+
end
|
8
|
+
|
9
|
+
subject { described_class.new connection_path }
|
10
|
+
|
11
|
+
describe '.start and .get' do
|
12
|
+
|
13
|
+
it do
|
14
|
+
subject.start
|
15
|
+
|
16
|
+
bunny = subject.get :default
|
17
|
+
|
18
|
+
expect(bunny.connected?).to be true
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '.restart' do
|
24
|
+
|
25
|
+
before do
|
26
|
+
subject.start
|
27
|
+
end
|
28
|
+
|
29
|
+
it do
|
30
|
+
|
31
|
+
subject.restart
|
32
|
+
|
33
|
+
bunny = subject.get :rpc
|
34
|
+
|
35
|
+
expect(bunny.connected?).to be true
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|