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.
Files changed (94) hide show
  1. checksums.yaml +4 -4
  2. data/.rspec +2 -0
  3. data/Gemfile.lock +9 -7
  4. data/{LICENSE → LICENSE.txt} +1 -1
  5. data/README.md +492 -195
  6. data/Rakefile +2 -0
  7. data/lib/liebre.rb +27 -16
  8. data/lib/liebre/actor.rb +11 -0
  9. data/lib/liebre/actor/consumer.rb +80 -0
  10. data/lib/liebre/actor/consumer/callback.rb +34 -0
  11. data/lib/liebre/actor/consumer/core.rb +80 -0
  12. data/lib/liebre/actor/consumer/reporter.rb +84 -0
  13. data/lib/liebre/actor/consumer/resources.rb +47 -0
  14. data/lib/liebre/actor/consumer/resources/config.rb +65 -0
  15. data/lib/liebre/actor/context.rb +40 -0
  16. data/lib/liebre/actor/context/declare.rb +44 -0
  17. data/lib/liebre/actor/context/handler.rb +44 -0
  18. data/lib/liebre/actor/publisher.rb +58 -0
  19. data/lib/liebre/actor/publisher/core.rb +42 -0
  20. data/lib/liebre/actor/publisher/reporter.rb +55 -0
  21. data/lib/liebre/actor/publisher/resources.rb +33 -0
  22. data/lib/liebre/actor/rpc/client.rb +88 -0
  23. data/lib/liebre/actor/rpc/client/core.rb +75 -0
  24. data/lib/liebre/actor/rpc/client/pending.rb +65 -0
  25. data/lib/liebre/actor/rpc/client/reporter.rb +71 -0
  26. data/lib/liebre/actor/rpc/client/resources.rb +62 -0
  27. data/lib/liebre/actor/rpc/client/task.rb +33 -0
  28. data/lib/liebre/actor/rpc/server.rb +74 -0
  29. data/lib/liebre/actor/rpc/server/callback.rb +28 -0
  30. data/lib/liebre/actor/rpc/server/core.rb +75 -0
  31. data/lib/liebre/actor/rpc/server/reporter.rb +72 -0
  32. data/lib/liebre/actor/rpc/server/resources.rb +53 -0
  33. data/lib/liebre/adapter.rb +8 -0
  34. data/lib/liebre/adapter/bunny.rb +23 -0
  35. data/lib/liebre/adapter/bunny/chan.rb +38 -0
  36. data/lib/liebre/adapter/bunny/conn.rb +32 -0
  37. data/lib/liebre/adapter/bunny/exchange.rb +20 -0
  38. data/lib/liebre/adapter/bunny/queue.rb +59 -0
  39. data/lib/liebre/adapter/interface.rb +26 -0
  40. data/lib/liebre/adapter/interface/chan.rb +29 -0
  41. data/lib/liebre/adapter/interface/conn.rb +21 -0
  42. data/lib/liebre/adapter/interface/exchange.rb +13 -0
  43. data/lib/liebre/adapter/interface/queue.rb +37 -0
  44. data/lib/liebre/bridge.rb +72 -0
  45. data/lib/liebre/bridge/channel_builder.rb +36 -0
  46. data/lib/liebre/config.rb +8 -38
  47. data/lib/liebre/engine.rb +61 -0
  48. data/lib/liebre/engine/builder.rb +48 -0
  49. data/lib/liebre/engine/repository.rb +56 -0
  50. data/lib/liebre/engine/state.rb +49 -0
  51. data/lib/liebre/runner.rb +15 -47
  52. data/lib/liebre/version.rb +1 -1
  53. data/liebre.gemspec +9 -7
  54. data/spec/integration/publish_and_consume_spec.rb +71 -0
  55. data/spec/integration/rpc_communication_spec.rb +81 -0
  56. data/spec/integration/start_twice_spec.rb +63 -0
  57. data/spec/liebre/actor/consumer_spec.rb +169 -0
  58. data/spec/liebre/actor/context/declare_spec.rb +69 -0
  59. data/spec/liebre/actor/context/handler_spec.rb +65 -0
  60. data/spec/liebre/actor/publisher_spec.rb +58 -0
  61. data/spec/liebre/actor/rpc/client_spec.rb +126 -0
  62. data/spec/liebre/actor/rpc/server_spec.rb +141 -0
  63. data/spec/liebre/adapter/bunny_spec.rb +66 -0
  64. data/spec/liebre/bridge_spec.rb +54 -0
  65. data/spec/liebre/engine/builder_spec.rb +42 -0
  66. data/spec/liebre/engine_spec.rb +90 -0
  67. data/spec/liebre/version_spec.rb +10 -0
  68. data/spec/spec_helper.rb +2 -9
  69. metadata +97 -58
  70. data/lib/liebre/common.rb +0 -7
  71. data/lib/liebre/common/utils.rb +0 -37
  72. data/lib/liebre/connection_manager.rb +0 -85
  73. data/lib/liebre/publisher.rb +0 -113
  74. data/lib/liebre/runner/consumers.rb +0 -46
  75. data/lib/liebre/runner/starter.rb +0 -44
  76. data/lib/liebre/runner/starter/consumer.rb +0 -129
  77. data/lib/liebre/runner/starter/consumer/handler.rb +0 -35
  78. data/lib/liebre/runner/starter/resources.rb +0 -45
  79. data/lib/liebre/runner/starter/resources/queue_builder.rb +0 -63
  80. data/lib/liebre/runner/starter/rpc.rb +0 -59
  81. data/lib/liebre/tasks.rb +0 -12
  82. data/spec/config/liebre.yml +0 -48
  83. data/spec/config/rabbitmq.yml +0 -35
  84. data/spec/integration_spec.rb +0 -76
  85. data/spec/liebre/config_spec.rb +0 -63
  86. data/spec/liebre/connection_manager_spec.rb +0 -44
  87. data/spec/liebre/publisher_spec.rb +0 -92
  88. data/spec/liebre/runner/consumers_spec.rb +0 -59
  89. data/spec/liebre/runner/starter/consumer_spec.rb +0 -145
  90. data/spec/liebre/runner/starter/resources/queue_builder_spec.rb +0 -69
  91. data/spec/liebre/runner/starter/resources_spec.rb +0 -38
  92. data/spec/liebre/runner/starter/rpc_spec.rb +0 -100
  93. data/spec/liebre/runner/starter_spec.rb +0 -70
  94. data/spec/liebre/runner_spec.rb +0 -54
@@ -0,0 +1,36 @@
1
+ module Liebre
2
+ class Bridge
3
+ class ChannelBuilder
4
+
5
+ DEFAULT_PREFETCH = 10
6
+
7
+ def initialize connections, opts
8
+ @connections = connections
9
+ @opts = opts
10
+ end
11
+
12
+ def call
13
+ connection.open_channel.tap do |channel|
14
+ channel.set_prefetch(prefetch_count)
15
+ end
16
+ end
17
+
18
+ private
19
+
20
+ def connection
21
+ connections.fetch(conn_name)
22
+ end
23
+
24
+ def conn_name
25
+ opts.fetch(:connection)
26
+ end
27
+
28
+ def prefetch_count
29
+ opts.fetch(:prefetch_count, DEFAULT_PREFETCH)
30
+ end
31
+
32
+ attr_reader :connections, :opts
33
+
34
+ end
35
+ end
36
+ end
@@ -1,47 +1,17 @@
1
- require "yaml"
2
-
3
1
  module Liebre
4
2
  class Config
5
3
 
6
- CONFIG_PATH = File.expand_path("config/liebre.yml")
7
- CONNECTION_PATH = File.expand_path("config/rabbitmq.yml")
8
- DEFAULT_LOGGER = Logger.new STDOUT
9
- DEFAULT_RPC_TIMEOUT = 5
10
-
11
- class << self
12
- attr_accessor :env
13
- attr_writer :config_path, :connection_path, :logger
14
-
15
- def config_path
16
- @config_path || CONFIG_PATH
17
- end
18
-
19
- def connection_path
20
- @connection_path || CONNECTION_PATH
21
- end
22
-
23
- def logger
24
- @logger || DEFAULT_LOGGER
25
- end
26
-
27
- end
28
-
29
- def consumers
30
- config.fetch 'consumers', {}
31
- end
32
-
33
- def publishers
34
- config.fetch 'publishers', {}
35
- end
36
-
37
- def rpc_request_timeout
38
- config.fetch 'rpc_request_timeout', DEFAULT_RPC_TIMEOUT
4
+ attr_accessor :adapter, :connections, :actors
5
+ attr_writer :logger
6
+
7
+ def logger
8
+ @logger || null_logger
39
9
  end
40
10
 
41
- private
11
+ private
42
12
 
43
- def config
44
- @config ||= YAML.load_file self.class.config_path
13
+ def null_logger
14
+ @null_logger ||= Logger.new(nil)
45
15
  end
46
16
 
47
17
  end
@@ -0,0 +1,61 @@
1
+ require "liebre/engine/state"
2
+ require "liebre/engine/builder"
3
+
4
+ require "liebre/engine/repository"
5
+
6
+ module Liebre
7
+ class Engine
8
+
9
+ def initialize config
10
+ @config = config
11
+ end
12
+
13
+ def start only: nil
14
+ bridge.start
15
+
16
+ state.to_start(only: only) do |type, name, opts|
17
+ actor = build(type, name, opts)
18
+ actor.start
19
+
20
+ repo.insert(type, name, actor)
21
+ end
22
+ end
23
+
24
+ def clean only: nil
25
+ bridge.start
26
+
27
+ state.to_clean(only: only) do |type, name, opts|
28
+ actor = build(type, name, opts)
29
+ actor.clean
30
+ end
31
+ end
32
+
33
+ def stop
34
+ repo.each(&:stop)
35
+ repo.clear
36
+ bridge.stop
37
+ end
38
+
39
+ def repo
40
+ @repo ||= Repository.new
41
+ end
42
+
43
+ private
44
+
45
+ def build type, name, opts
46
+ builder = Builder.new(bridge, type, name, opts, config)
47
+ builder.call
48
+ end
49
+
50
+ def state
51
+ @state ||= State.new(config.actors)
52
+ end
53
+
54
+ def bridge
55
+ @bridge ||= Bridge.new(config)
56
+ end
57
+
58
+ attr_reader :config
59
+
60
+ end
61
+ end
@@ -0,0 +1,48 @@
1
+ module Liebre
2
+ class Engine
3
+ class Builder
4
+
5
+ CONTEXT = Actor::Context
6
+
7
+ ACTORS = {
8
+ :publishers => Actor::Publisher,
9
+ :consumers => Actor::Consumer,
10
+ :rpc_clients => Actor::RPC::Client,
11
+ :rpc_servers => Actor::RPC::Server
12
+ }
13
+
14
+ def initialize bridge, type, name, opts, config, context: CONTEXT, actors: ACTORS
15
+ @bridge = bridge
16
+ @type = type
17
+ @name = name
18
+ @opts = opts
19
+ @config = config
20
+
21
+ @context_class = context
22
+ @actor_classes = actors
23
+ end
24
+
25
+ def call
26
+ actor_class.new(context)
27
+ end
28
+
29
+ private
30
+
31
+ def actor_class
32
+ actor_classes.fetch(type)
33
+ end
34
+
35
+ def context
36
+ context_class.new(chan, name, opts, config)
37
+ end
38
+
39
+ def chan
40
+ bridge.open_channel(opts)
41
+ end
42
+
43
+ attr_reader :bridge, :type, :name, :opts, :config,
44
+ :context_class, :actor_classes
45
+
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,56 @@
1
+ module Liebre
2
+ class Engine
3
+ class Repository
4
+
5
+ def initialize
6
+ @publishers = {}
7
+ @consumers = {}
8
+ @rpc_clients = {}
9
+ @rpc_servers = {}
10
+ end
11
+
12
+ def insert type, name, resource
13
+ case type
14
+ when :publishers then publishers[name] = resource
15
+ when :consumers then consumers[name] = resource
16
+ when :rpc_clients then rpc_clients[name] = resource
17
+ when :rpc_servers then rpc_servers[name] = resource
18
+ end
19
+ end
20
+
21
+ def all
22
+ publishers.values + consumers.values + rpc_clients.values + rpc_servers.values
23
+ end
24
+
25
+ def each &block
26
+ all.each(&block)
27
+ end
28
+
29
+ def clear
30
+ publishers.clear
31
+ consumers.clear
32
+ rpc_clients.clear
33
+ rpc_servers.clear
34
+ end
35
+
36
+ def publisher name
37
+ publishers.fetch(name)
38
+ end
39
+
40
+ def consumer name
41
+ consumers.fetch(name)
42
+ end
43
+
44
+ def rpc_client name
45
+ rpc_clients.fetch(name)
46
+ end
47
+
48
+ def rpc_server name
49
+ rpc_servers.fetch(name)
50
+ end
51
+
52
+ attr_reader :publishers, :consumers, :rpc_clients, :rpc_servers
53
+
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,49 @@
1
+ module Liebre
2
+ class Engine
3
+ class State
4
+
5
+ def initialize config
6
+ @config = config
7
+ @started = Hash.new { |hash, key| hash[key] = {} }
8
+ end
9
+
10
+ def to_start only: nil
11
+ all do |type, name, opts|
12
+ if has_to_start?(type, name, only)
13
+ yield(type, name, opts)
14
+ set_started(type, name)
15
+ end
16
+ end
17
+ end
18
+
19
+ def to_clean only: nil
20
+ all do |type, name, opts|
21
+ yield(type, name, opts) if match?(type, only)
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def has_to_start? type, name, only
28
+ started[type][name].nil? and match?(type, only)
29
+ end
30
+
31
+ def match? type, only
32
+ only.nil? or only.include?(type)
33
+ end
34
+
35
+ def set_started type, name
36
+ started[type][name] = true
37
+ end
38
+
39
+ def all
40
+ config.each do |type, specs|
41
+ specs.each { |name, opts| yield(type, name, opts) }
42
+ end
43
+ end
44
+
45
+ attr_reader :config, :started
46
+
47
+ end
48
+ end
49
+ end
@@ -1,65 +1,33 @@
1
1
  module Liebre
2
2
  class Runner
3
-
4
- autoload :Consumers, 'liebre/runner/consumers'
5
- autoload :Starter, 'liebre/runner/starter'
6
-
3
+
7
4
  RETRY_INTERVAL = 5
8
5
 
9
- def initialize retry_interval = RETRY_INTERVAL
10
- @retry_interval = retry_interval
6
+ def initialize engine: Liebre.engine
7
+ @engine = engine
11
8
  end
12
9
 
13
- def start
14
- setup_shutdown
15
- connection_manager.restart
16
- start_consumers
10
+ def run only: nil
11
+ setup_signals
12
+ engine.start(only: only)
17
13
  sleep
18
- rescue StandardError => e
19
- log_and_wait(e)
14
+ rescue => e
15
+ sleep(RETRY_INTERVAL)
20
16
  retry
21
17
  end
22
18
 
23
- private
24
-
25
- def setup_shutdown
26
- Signal.trap("TERM") { do_shutdown; exit }
27
- Signal.trap("USR1") { do_shutdown; exit }
28
- end
29
-
30
- def do_shutdown
31
- Thread.start do
32
- logger.info("Liebre# Closing AMQP connection...")
33
- consumers.stop
34
- connection_manager.stop
35
- logger.info("Liebre# AMQP connection closed")
36
- end.join
37
- end
38
-
39
- def start_consumers
40
- logger.info("Liebre# Starting consumers...")
41
- consumers.start_all
42
- end
19
+ private
43
20
 
44
- def log_and_wait e
45
- logger.warn(e)
46
- sleep(retry_interval)
47
- logger.warn("Liebre# Retrying connection")
48
- end
49
-
50
- def logger
51
- Liebre.logger
52
- end
53
-
54
- def consumers
55
- @consumers ||= Consumers.new(connection_manager)
21
+ def setup_signals
22
+ Signal.trap("TERM") { do_stop; exit }
23
+ Signal.trap("USR1") { do_stop; exit }
56
24
  end
57
25
 
58
- def connection_manager
59
- @connection_manager ||= ConnectionManager.instance
26
+ def do_stop
27
+ Thread.new { engine.stop }.join
60
28
  end
61
29
 
62
- attr_reader :retry_interval
30
+ attr_reader :engine
63
31
 
64
32
  end
65
33
  end
@@ -1,5 +1,5 @@
1
1
  module Liebre
2
2
 
3
- VERSION = "0.1.21"
3
+ VERSION = "0.2.1"
4
4
 
5
5
  end
@@ -6,10 +6,10 @@ require 'liebre/version'
6
6
  Gem::Specification.new do |spec|
7
7
  spec.name = "liebre"
8
8
  spec.version = Liebre::VERSION
9
- spec.authors = ["jcabotc", "graimon"]
10
- spec.email = ["jcabot@gmail.com", "graimon@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/iadbox/liebre"
9
+ spec.authors = ["jcabotc"]
10
+ spec.email = ["jcabot@gmail.com"]
11
+ spec.summary = %q{Some abstractions to interact with a AMQP broker}
12
+ spec.homepage = ""
13
13
  spec.license = "MIT"
14
14
 
15
15
  spec.files = `git ls-files -z`.split("\x0")
@@ -17,10 +17,12 @@ Gem::Specification.new do |spec|
17
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
18
  spec.require_paths = ["lib"]
19
19
 
20
- spec.add_runtime_dependency "bunny", '~> 2.5', '>= 2.5.1'
20
+ spec.add_dependency "concurrent-ruby"
21
21
 
22
- spec.add_development_dependency "bundler", '~> 1.6'
22
+ spec.add_development_dependency "bunny"
23
+
24
+ spec.add_development_dependency "bundler", "~> 1.6"
25
+ spec.add_development_dependency "rake"
23
26
  spec.add_development_dependency "rspec"
24
27
  spec.add_development_dependency "pry"
25
- spec.add_development_dependency "rake"
26
28
  end
@@ -0,0 +1,71 @@
1
+ RSpec.describe "Publish and consume" do
2
+
3
+ let(:connections) { {"test_conn" => {}} }
4
+
5
+ let :exchange do
6
+ {:name => "__test__.liebre.publish_and_consume_exchange",
7
+ :type => "fanout",
8
+ :opts => {:auto_delete => true, :durable => false}}
9
+ end
10
+
11
+ let :queue do
12
+ {:name => "__test__.liebre.publish_and_consume_queue",
13
+ :opts => {:auto_delete => true, :durable => false}}
14
+ end
15
+
16
+ let(:handler_class) { double 'handler_class' }
17
+ let(:handler) { double 'handler' }
18
+
19
+ let :actors do
20
+ {
21
+ :publishers => {
22
+ :my_publisher => {
23
+ :connection => "test_conn",
24
+ :resources => {:exchange => exchange}
25
+ }
26
+ },
27
+ :consumers => {
28
+ :my_consumer => {
29
+ :connection => "test_conn",
30
+ :prefetch_count => 5,
31
+ :pool_size => 1,
32
+ :handler => handler_class,
33
+ :resources => {:exchange => exchange, :queue => queue}
34
+ }
35
+ }
36
+ }
37
+ end
38
+
39
+ let :config do
40
+ Liebre::Config.new.tap do |config|
41
+ config.adapter = Liebre::Adapter::Bunny
42
+ config.connections = connections
43
+ config.actors = actors
44
+ end
45
+ end
46
+
47
+ let(:payload) { "some_data" }
48
+ let(:headers) { {"foo" => "bar"} }
49
+
50
+ it "sends and receives data" do
51
+ engine = Liebre::Engine.new(config)
52
+ engine.start
53
+
54
+ repo = engine.repo
55
+ publisher = repo.publisher(:my_publisher)
56
+
57
+ expect(handler_class).to receive :new do |payload, meta, callback|
58
+ expect(payload ).to eq payload
59
+ expect(meta.headers).to eq headers
60
+
61
+ handler
62
+ end
63
+ expect(handler).to receive(:call)
64
+
65
+ sleep(0.1) # wait for the consumer to bind its queue to the exchange
66
+ publisher.publish(payload, :headers => headers)
67
+
68
+ sleep(0.2) # wait for the message to be published and consumed
69
+ end
70
+
71
+ end