liebre 0.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +51 -0
  3. data/Gemfile +4 -0
  4. data/Gemfile.lock +47 -0
  5. data/LICENSE +22 -0
  6. data/README.md +268 -0
  7. data/lib/liebre.rb +24 -0
  8. data/lib/liebre/common.rb +7 -0
  9. data/lib/liebre/common/utils.rb +24 -0
  10. data/lib/liebre/config.rb +48 -0
  11. data/lib/liebre/connection_manager.rb +64 -0
  12. data/lib/liebre/publisher.rb +88 -0
  13. data/lib/liebre/runner.rb +59 -0
  14. data/lib/liebre/runner/consumers.rb +36 -0
  15. data/lib/liebre/runner/starter.rb +40 -0
  16. data/lib/liebre/runner/starter/consumer.rb +91 -0
  17. data/lib/liebre/runner/starter/consumer/handler.rb +35 -0
  18. data/lib/liebre/runner/starter/resources.rb +39 -0
  19. data/lib/liebre/runner/starter/resources/queue_builder.rb +58 -0
  20. data/lib/liebre/runner/starter/rpc.rb +45 -0
  21. data/lib/liebre/tasks.rb +12 -0
  22. data/lib/liebre/version.rb +5 -0
  23. data/liebre.gemspec +26 -0
  24. data/spec/config/liebre.yml +47 -0
  25. data/spec/config/rabbitmq.yml +35 -0
  26. data/spec/integration_spec.rb +73 -0
  27. data/spec/liebre/config_spec.rb +62 -0
  28. data/spec/liebre/connection_manager_spec.rb +40 -0
  29. data/spec/liebre/publisher_spec.rb +86 -0
  30. data/spec/liebre/runner/consumers_spec.rb +59 -0
  31. data/spec/liebre/runner/starter/consumer_spec.rb +140 -0
  32. data/spec/liebre/runner/starter/resources/queue_builder_spec.rb +69 -0
  33. data/spec/liebre/runner/starter/resources_spec.rb +36 -0
  34. data/spec/liebre/runner/starter/rpc_spec.rb +92 -0
  35. data/spec/liebre/runner/starter_spec.rb +59 -0
  36. data/spec/liebre/runner_spec.rb +50 -0
  37. data/spec/spec_helper.rb +23 -0
  38. 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
@@ -0,0 +1,12 @@
1
+ require 'liebre'
2
+
3
+ task :environment
4
+
5
+ namespace :liebre do
6
+
7
+ desc "Starts Liebre:Runner"
8
+ task :run => :environment do
9
+ Liebre::Runner.new.start
10
+ end
11
+
12
+ end
@@ -0,0 +1,5 @@
1
+ module Liebre
2
+
3
+ VERSION = "0.1.3"
4
+
5
+ end
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