liebre 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|