basquiat 1.2.0 → 1.3.0.pre.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 (52) hide show
  1. checksums.yaml +4 -4
  2. data/.codeclimate.yml +50 -0
  3. data/.gitignore +1 -0
  4. data/.metrics +1 -5
  5. data/.reek +0 -1
  6. data/.rubocop.yml +2 -1
  7. data/.ruby-version +1 -1
  8. data/Guardfile +4 -0
  9. data/README.md +77 -61
  10. data/basquiat.gemspec +5 -4
  11. data/basquiat_docker.sh +1 -1
  12. data/docker/Dockerfile +8 -3
  13. data/docker-compose.yml +3 -3
  14. data/lib/basquiat/adapters/base_adapter.rb +42 -7
  15. data/lib/basquiat/adapters/base_message.rb +14 -9
  16. data/lib/basquiat/adapters/rabbitmq/configuration.rb +31 -16
  17. data/lib/basquiat/adapters/rabbitmq/connection.rb +33 -56
  18. data/lib/basquiat/adapters/rabbitmq/events.rb +1 -1
  19. data/lib/basquiat/adapters/rabbitmq/message.rb +10 -9
  20. data/lib/basquiat/adapters/rabbitmq/requeue_strategies/auto_acknowledge.rb +15 -0
  21. data/lib/basquiat/adapters/rabbitmq/requeue_strategies/base_strategy.rb +8 -4
  22. data/lib/basquiat/adapters/rabbitmq/requeue_strategies/basic_acknowledge.rb +1 -1
  23. data/lib/basquiat/adapters/rabbitmq/requeue_strategies/dead_lettering.rb +16 -15
  24. data/lib/basquiat/adapters/rabbitmq/requeue_strategies/delayed_delivery.rb +80 -16
  25. data/lib/basquiat/adapters/rabbitmq/requeue_strategies.rb +7 -0
  26. data/lib/basquiat/adapters/rabbitmq/session.rb +12 -14
  27. data/lib/basquiat/adapters/rabbitmq_adapter.rb +35 -16
  28. data/lib/basquiat/adapters/test_adapter.rb +2 -5
  29. data/lib/basquiat/errors/strategy_not_registered.rb +1 -9
  30. data/lib/basquiat/interfaces/base.rb +28 -7
  31. data/lib/basquiat/support/configuration.rb +33 -4
  32. data/lib/basquiat/support/hash_refinements.rb +9 -0
  33. data/lib/basquiat/support/json.rb +9 -0
  34. data/lib/basquiat/version.rb +1 -1
  35. data/lib/basquiat.rb +6 -1
  36. data/spec/lib/adapters/base_adapter_spec.rb +1 -1
  37. data/spec/lib/adapters/base_message_spec.rb +0 -6
  38. data/spec/lib/adapters/rabbitmq/configuration_spec.rb +2 -2
  39. data/spec/lib/adapters/rabbitmq/connection_spec.rb +8 -13
  40. data/spec/lib/adapters/rabbitmq/events_spec.rb +8 -1
  41. data/spec/lib/adapters/rabbitmq/requeue_strategies/auto_acknowledge_spec.rb +24 -0
  42. data/spec/lib/adapters/rabbitmq/requeue_strategies/basic_acknowledge_spec.rb +4 -4
  43. data/spec/lib/adapters/rabbitmq/requeue_strategies/dead_lettering_spec.rb +23 -28
  44. data/spec/lib/adapters/rabbitmq/requeue_strategies/delayed_delivery_spec.rb +105 -0
  45. data/spec/lib/adapters/rabbitmq_adapter_spec.rb +21 -17
  46. data/spec/lib/basquiat_spec.rb +0 -6
  47. data/spec/lib/interfaces/base_spec.rb +11 -19
  48. data/spec/lib/support/configuration_spec.rb +0 -8
  49. data/spec/lib/support/hash_refinements_spec.rb +2 -2
  50. data/spec/spec_helper.rb +2 -6
  51. data/spec/support/rabbitmq_queue_matchers.rb +9 -3
  52. metadata +21 -12
@@ -1,88 +1,65 @@
1
1
  module Basquiat
2
2
  module Adapters
3
3
  class RabbitMq
4
+ # Control the connection to the RabitMQ server. Delegates calls to {Bunny::Connection}
4
5
  class Connection < SimpleDelegator
5
- def initialize(servers:, failover: {}, auth: {})
6
- @servers = Array(servers)
7
- @failover = { default_timeout: 5, max_retries: 5 }.merge(failover)
8
- @auth = { user: 'guest', password: 'guest' }.merge(auth)
6
+ # @param hosts: [Array<String>] IPs or FQDN of the RabbitMQ instances
7
+ # @param port: [Fixnum] Port that the RabbitMQ instances run
8
+ # @param failover: [Hash]
9
+ # @option failover: [Fixnum] :max_retries (5) Maximum number of reconnection retries
10
+ # @option failover: [Fixnum] :default_timeout (5) Interval between to reconnect attempts
11
+ # @option failover: [Fixnum] :connection_timeout (5) Allowed time before a connection attempt timeouts
12
+ # @param auth: [Hash]
13
+ # @option auth: [String] :user ('guest')
14
+ # @option auth: [String] :password ('guest')
15
+ def initialize(hosts:, port: 5672, failover: {}, auth: {})
16
+ @hosts = hosts
17
+ @port = port
18
+ @failover = failover
19
+ @auth = auth
9
20
  end
10
21
 
22
+ # Creates a channel
23
+ # @return [Bunny::Channel]
24
+ def create_channel
25
+ connection.start
26
+ connection.create_channel
27
+ end
28
+
29
+ # Starts the connection if needed
11
30
  def start
12
- with_network_failure_handler do
13
- connection.start
14
- current_server[:retries] = 0
15
- end
31
+ connection.start unless connection.connected?
16
32
  end
17
33
 
18
34
  def connected?
19
35
  connection.status == :started
20
36
  end
21
37
 
38
+ # Closes the channels and the connection.
22
39
  def disconnect
23
40
  connection.close_all_channels
24
41
  connection.close
25
42
  reset
26
43
  end
27
44
 
28
- def current_server_uri
29
- "amqp://#{current_server[:host]}:#{current_server[:port]}#{current_server[:vhost]}"
30
- end
31
-
32
- def with_network_failure_handler
33
- yield if block_given?
34
- rescue Bunny::ConnectionForced, Bunny::TCPConnectionFailed, Bunny::NetworkFailure => error
35
- if current_server.fetch(:retries, 0) <= @failover.fetch(:max_retries)
36
- handle_network_failures
37
- retry
38
- else
39
- raise(error)
40
- end
41
- end
42
-
43
45
  private
44
46
 
45
47
  def reset
46
48
  @connection = nil
47
49
  end
48
50
 
49
- def handle_network_failures
50
- Basquiat.logger.warn "Failed to connect to #{current_server_uri}"
51
- retries = current_server.fetch(:retries, 0)
52
- current_server[:retries] = retries + 1
53
- if retries < @failover.fetch(:max_retries)
54
- Basquiat.logger.warn("Retrying connection to #{current_server_uri} in #{@failover.fetch(:default_timeout)} seconds")
55
- sleep(@failover.fetch(:default_timeout))
56
- else
57
- Basquiat.logger.warn("Total number of retries exceeded for #{current_server_uri}")
58
- rotate
59
- end
60
- reset
61
- end
62
-
63
51
  def connection
64
- Basquiat.logger.info("Connecting to #{current_server_uri}")
65
52
  @connection ||= Bunny.new(
66
- current_server_uri,
67
- user: auth[:user],
68
- password: auth[:password],
69
- automatic_recovery: false,
70
- threaded: @failover.fetch(:threaded, true),
71
- logger: Basquiat.logger)
53
+ hosts: @hosts,
54
+ port: @port,
55
+ username: @auth.fetch(:user, 'guest'),
56
+ password: @auth.fetch(:password, 'guest'),
57
+ recovery_attempts: @failover.fetch(:max_retries, 5),
58
+ network_recovery_interval: @failover.fetch(:default_timeout, 5),
59
+ connection_timeout: @failover.fetch(:connection_timeout, 5),
60
+ logger: Basquiat.logger)
72
61
  __setobj__(@connection)
73
62
  end
74
-
75
- def current_server
76
- @servers.first
77
- end
78
-
79
- def auth
80
- current_server[:auth] || @auth
81
- end
82
-
83
- def rotate
84
- @servers.rotate!
85
- end
86
63
  end
87
64
  end
88
65
  end
@@ -27,10 +27,10 @@ module Basquiat
27
27
  raise KeyError, "No event handler found for #{key}"
28
28
  end
29
29
 
30
- # event.for.the.win, event.for.everyone, event.for.*
31
30
  private
32
31
 
33
32
  def set_pattern_key(key, value)
33
+ key = key.gsub('.', '\.')
34
34
  key = if key =~ /\*/
35
35
  /^#{key.gsub('*', '[^.]+')}$/
36
36
  else
@@ -4,6 +4,10 @@ module Basquiat
4
4
  class Message < Basquiat::Adapters::BaseMessage
5
5
  attr_reader :delivery_info, :props
6
6
  alias_method :di, :delivery_info
7
+ # @!attribute [r] delivery_info
8
+ # @return [Hash] RabbitMQ delivery_info.
9
+ # @!attribute [r] props
10
+ # @return [Hash] RabbitMQ message properties, such as headers.
7
11
 
8
12
  def initialize(message, delivery_info = {}, props = {})
9
13
  super(message)
@@ -12,21 +16,18 @@ module Basquiat
12
16
  @action = :ack
13
17
  end
14
18
 
19
+ # @!attribute [rw] routing_key
20
+ # It overrides (but not overwrites) the delivery_info routing_key
21
+ # @return [String] returns either the set routing_key or the delivery_info routing_key
22
+ attr_writer :routing_key
15
23
  def routing_key
16
- delivery_info.routing_key
24
+ @routing_key || delivery_info.routing_key
17
25
  end
18
26
 
27
+ # Shorthand for delivery_info.delivery_tag
19
28
  def delivery_tag
20
29
  delivery_info.delivery_tag
21
30
  end
22
-
23
- def ack
24
- @action = :ack
25
- end
26
-
27
- def unack
28
- @action = :unack
29
- end
30
31
  end
31
32
  end
32
33
  end
@@ -0,0 +1,15 @@
1
+ module Basquiat
2
+ module Adapters
3
+ class RabbitMq
4
+ class AutoAcknowledge < BaseStrategy
5
+ def self.session_options
6
+ { consumer: { manual_ack: false } }
7
+ end
8
+
9
+ def run(*)
10
+ yield
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -20,13 +20,17 @@ module Basquiat
20
20
  fail Basquiat::Errors::SubclassResponsibility
21
21
  end
22
22
 
23
- def ack(delivery_tag)
24
- @session.channel.ack(delivery_tag)
23
+ def ack(message)
24
+ @session.channel.ack(message.delivery_tag)
25
25
  end
26
26
 
27
- def unack(delivery_tag)
28
- @session.channel.nack(delivery_tag, false)
27
+ def nack(message)
28
+ @session.channel.nack(message.delivery_tag, false)
29
29
  end
30
+
31
+ private
32
+
33
+ attr_reader :session
30
34
  end
31
35
  end
32
36
  end
@@ -4,7 +4,7 @@ module Basquiat
4
4
  class BasicAcknowledge < BaseStrategy
5
5
  def run(message)
6
6
  yield
7
- send(message.action, message.di.delivery_tag)
7
+ public_send(message.action, message)
8
8
  end
9
9
  end
10
10
  end
@@ -7,10 +7,11 @@ module Basquiat
7
7
 
8
8
  def setup(opts)
9
9
  @options = {
10
- session: { queue: {
11
- options: { 'x-dead-letter-exchange' => opts.fetch(:exchange, 'basquiat.dlx') }
12
- } },
13
- dlx: { ttl: opts.fetch(:ttl, 1_000) } }
10
+ session: {
11
+ queue: {
12
+ options: {
13
+ 'x-dead-letter-exchange' => opts.fetch(:exchange, 'basquiat.dlx') } } },
14
+ dlx: { ttl: opts.fetch(:ttl, 1_000) } }
14
15
  end
15
16
 
16
17
  def session_options
@@ -27,18 +28,18 @@ module Basquiat
27
28
 
28
29
  def run(message)
29
30
  catch :skip_processing do
30
- check_incoming_messages(message)
31
+ check_incoming_messages(message.props.headers)
31
32
  yield
32
33
  end
33
- public_send(message.action, message.delivery_tag)
34
+ public_send(message.action, message)
34
35
  end
35
36
 
36
37
  private
37
38
 
38
- def check_incoming_messages(message)
39
- message.props.headers and
40
- message.props.headers['x-death'][1]['queue'] != @session.queue.name and
41
- throw(:skip_processing)
39
+ def check_incoming_messages(headers)
40
+ headers &&
41
+ headers['x-death'][1]['queue'] != session.queue.name &&
42
+ throw(:skip_processing)
42
43
  end
43
44
 
44
45
  def options
@@ -46,11 +47,11 @@ module Basquiat
46
47
  end
47
48
 
48
49
  def setup_dead_lettering
49
- dlx = @session.channel.topic('basquiat.dlx')
50
- queue = @session.channel.queue('basquiat.dlq',
51
- arguments: { 'x-dead-letter-exchange' => @session.exchange.name,
52
- 'x-message-ttl' => options[:dlx][:ttl] })
53
- queue.bind(dlx, routing_key: '*.#')
50
+ dlx = session.channel.topic('basquiat.dlx')
51
+ queue = session.channel.queue('basquiat.dlq',
52
+ arguments: { 'x-dead-letter-exchange' => session.exchange.name,
53
+ 'x-message-ttl' => options[:dlx][:ttl] })
54
+ queue.bind(dlx, routing_key: '#')
54
55
  end
55
56
  end
56
57
  end
@@ -1,24 +1,88 @@
1
1
  module Basquiat
2
2
  module Adapters
3
3
  class RabbitMq
4
- module Strategies
5
- class DelayedDeliveryWIP
6
- def initialize(channel, message)
7
- @channel = channel
8
- @message = message
4
+ class DelayedDelivery < BaseStrategy
5
+ class << self
6
+ using HashRefinements
7
+ attr_reader :options
8
+
9
+ def setup(opts)
10
+ @options = { ddl: { retries: 5,
11
+ exchange_name: 'basquiat.dlx',
12
+ queue_name_preffix: 'basquiat.ddlq' } }.deep_merge(opts)
13
+ end
14
+ end
15
+
16
+ def initialize(session)
17
+ super
18
+ setup_delayed_delivery
19
+ end
20
+
21
+ def run(message)
22
+ message.routing_key = extract_event_info(message.routing_key)[0]
23
+ yield
24
+ public_send(message.action, message)
25
+ end
26
+
27
+ # @param [Message] message the, well, message to be requeued
28
+ def requeue(message)
29
+ @exchange.publish(Basquiat::Json.encode(message), routing_key: requeue_route_for(message.di.routing_key))
30
+ ack(message)
31
+ end
32
+
33
+ private
34
+
35
+ # @param [#match] key the current routing key of the message
36
+ # @return [String] the calculated routing key for a republish / requeue
37
+ def requeue_route_for(key)
38
+ event_name, timeout = extract_event_info(key)
39
+ if timeout == 2**options[:retries] * 1_000
40
+ "rejected.#{session.queue.name}.#{event_name}"
41
+ else
42
+ "#{timeout * 2}.#{session.queue.name}.#{event_name}"
9
43
  end
44
+ end
45
+
46
+ # @param [#match] key the current routing key of the message
47
+ # @return [Array<String, Integer>] a 2 item array composed of the event.name (aka original routing_key) and
48
+ # the current timeout
49
+ def extract_event_info(key)
50
+ md = key.match(/^(\d+)\.#{session.queue.name}\.(.+)$/)
51
+ if md
52
+ [md.captures[1], md.captures[0].to_i]
53
+ else
54
+ # So timeout can turn into 1 second, weird but spares some checking
55
+ [key, 500]
56
+ end
57
+ end
58
+
59
+ def options
60
+ self.class.options[:ddl]
61
+ end
62
+
63
+ def setup_delayed_delivery
64
+ @exchange = session.channel.topic(options[:exchange_name], durable: true)
65
+ session.bind_queue("*.#{session.queue.name}.#")
66
+ prepare_timeout_queues
67
+ queue = session.channel.queue("#{options[:queue_name_preffix]}_rejected", durable: true)
68
+ queue.bind(@exchange, routing_key: 'rejected.#')
69
+ end
70
+
71
+ def prepare_timeout_queues
72
+ queues = (0..options[:retries] - 1).map do |iteration|
73
+ timeout = 2**iteration
74
+ session.channel.queue("#{options[:queue_name_preffix]}_#{timeout}", durable: true,
75
+ arguments: {
76
+ 'x-dead-letter-exchange' => session.exchange.name,
77
+ 'x-message-ttl' => timeout * 1_000 })
78
+ end
79
+ bind_timeout_queues(queues)
80
+ end
10
81
 
11
- # Criar um exchange
12
- # Criar o queue (ou redeclara-lo)
13
- # O queue tem que ter um dlx para o exchange padrão
14
- # Publicar a mensagem no exchange com um ttl igual ao anterior **2
15
- # dar um unack caso o tempo estoure o maximo.
16
- def message_handler
17
- delay = message[:headers][0][:expiration]**2
18
- exchange = channel.topic('basquiat.dd')
19
- queue = channel.queue('delay', ttl: delay * 2)
20
- queue.bind(exchange, 'original_queue.delay.message_name')
21
- exchange.publish('original_queue.delay.message_name', message, ttl: delay, dlx: default_exchange)
82
+ def bind_timeout_queues(queues)
83
+ queues.each do |queue|
84
+ timeout = queue.arguments['x-message-ttl'].to_i
85
+ queue.bind(@exchange, routing_key: "#{timeout}.#")
22
86
  end
23
87
  end
24
88
  end
@@ -1,3 +1,10 @@
1
1
  require 'basquiat/adapters/rabbitmq/requeue_strategies/base_strategy'
2
+ require 'basquiat/adapters/rabbitmq/requeue_strategies/auto_acknowledge'
2
3
  require 'basquiat/adapters/rabbitmq/requeue_strategies/basic_acknowledge'
3
4
  require 'basquiat/adapters/rabbitmq/requeue_strategies/dead_lettering'
5
+ require 'basquiat/adapters/rabbitmq/requeue_strategies/delayed_delivery'
6
+
7
+ Basquiat::Adapters::RabbitMq.register_strategy(:auto_ack, Basquiat::Adapters::RabbitMq::AutoAcknowledge)
8
+ Basquiat::Adapters::RabbitMq.register_strategy(:basic_ack, Basquiat::Adapters::RabbitMq::BasicAcknowledge)
9
+ Basquiat::Adapters::RabbitMq.register_strategy(:dead_lettering, Basquiat::Adapters::RabbitMq::DeadLettering)
10
+ Basquiat::Adapters::RabbitMq.register_strategy(:delayed_delivery, Basquiat::Adapters::RabbitMq::DelayedDelivery)
@@ -2,9 +2,11 @@ module Basquiat
2
2
  module Adapters
3
3
  class RabbitMq
4
4
  class Session
5
- def initialize(connection, session_options = {})
6
- @connection = connection
7
- @options = session_options
5
+ attr_reader :channel
6
+
7
+ def initialize(channel, session_options = {})
8
+ @channel = channel
9
+ @options = session_options
8
10
  end
9
11
 
10
12
  def bind_queue(routing_key)
@@ -15,30 +17,26 @@ module Basquiat
15
17
  channel.confirm_select if @options[:publisher][:confirm]
16
18
  exchange.publish(Basquiat::Json.encode(message),
17
19
  { routing_key: routing_key,
20
+ persistent: true,
18
21
  timestamp: Time.now.to_i }.merge(props))
19
22
  end
20
23
 
21
- def subscribe(lock, &_block)
22
- queue.subscribe(block: lock, manual_ack: true) do |di, props, msg|
23
- message = Basquiat::Adapters::RabbitMq::Message.new(msg, di, props)
24
- yield message
24
+ def subscribe(block: true, manual_ack: @options[:consumer][:manual_ack])
25
+ channel.prefetch(@options[:consumer][:prefetch])
26
+ queue.subscribe(block: block, manual_ack: manual_ack) do |di, props, msg|
27
+ yield Basquiat::Adapters::RabbitMq::Message.new(msg, di, props)
25
28
  end
26
29
  end
27
30
 
28
- def channel
29
- @connection.start unless @connection.connected?
30
- @channel ||= @connection.create_channel
31
- end
32
-
33
31
  def queue
34
32
  @queue ||= channel.queue(@options[:queue][:name],
35
- durable: true,
33
+ durable: @options[:queue][:durable],
36
34
  arguments: (@options[:queue][:options] || {}))
37
35
  end
38
36
 
39
37
  def exchange
40
38
  @exchange ||= channel.topic(@options[:exchange][:name],
41
- durable: true,
39
+ durable: @options[:exchange][:durable],
42
40
  arguments: (@options[:exchange][:options] || {}))
43
41
  end
44
42
  end
@@ -7,7 +7,6 @@ module Basquiat
7
7
  class RabbitMq < Basquiat::Adapters::Base
8
8
  using Basquiat::HashRefinements
9
9
 
10
-
11
10
  # Avoid superclass mismatch errors
12
11
  require 'basquiat/adapters/rabbitmq/events'
13
12
  require 'basquiat/adapters/rabbitmq/message'
@@ -16,56 +15,76 @@ module Basquiat
16
15
  require 'basquiat/adapters/rabbitmq/session'
17
16
  require 'basquiat/adapters/rabbitmq/requeue_strategies'
18
17
 
18
+ # Initializes the superclass using a {Events} object as the procs instance variable
19
19
  def initialize
20
- super
21
- @procs = Events.new
20
+ super(procs: Events.new)
22
21
  end
23
22
 
23
+ # Since the RabbitMQ configuration options are quite vast and it's interations with the requeue strategies a bit
24
+ # convoluted it uses a {Configuration} object to handle it all
24
25
  def base_options
25
26
  @configuration ||= Configuration.new
26
27
  @configuration.merge_user_options(Basquiat.configuration.adapter_options)
27
28
  end
28
29
 
30
+ # Adds the subscription and register the proc to the event.
31
+ # @param event_name [String] routing key to be matched (and bound to) when listening
32
+ # @param proc [#call] callable object to be run when a message with the said routing_key is received
29
33
  def subscribe_to(event_name, proc)
30
34
  procs[event_name] = proc
31
35
  end
32
36
 
33
- def publish(event, message, persistent: options[:publisher][:persistent], props: {})
34
- connection.with_network_failure_handler do
35
- session.publish(event, message, props)
36
- disconnect unless persistent
37
- end
37
+ # Publishes the event to the exchange configured.
38
+ # @param event [String] routing key to be used
39
+ # @param message [Hash] the message to be publish
40
+ # @param props [Hash] other properties you wish to publish with the message, such as custom headers etc.
41
+ def publish(event, message, props: {})
42
+ session.publish(event, message, props)
43
+ disconnect unless options[:publisher][:persistent]
38
44
  end
39
45
 
40
- def listen(block: true)
41
- connection.with_network_failure_handler do
42
- procs.keys.each { |key| session.bind_queue(key) }
43
- session.subscribe(block) do |message|
44
- strategy.run(message) do
45
- procs[message.routing_key].call(message)
46
- end
46
+ # Binds the queues and start the event lopp.
47
+ # @param block [Boolean] block the thread
48
+ def listen(block: true, rescue_proc: Basquiat.configuration.rescue_proc)
49
+ procs.keys.each { |key| session.bind_queue(key) }
50
+ session.subscribe(block: block) do |message|
51
+ strategy.run(message) do
52
+ process_message(message, rescue_proc)
47
53
  end
48
54
  end
49
55
  end
50
56
 
57
+ def process_message(message, rescue_proc)
58
+ procs[message.routing_key].call(message)
59
+ rescue => ex
60
+ rescue_proc.call(ex, message)
61
+ end
62
+
63
+ # Reset the connection to RabbitMQ.
51
64
  def reset_connection
52
65
  connection.disconnect
53
66
  @connection = nil
54
67
  @session = nil
68
+ @strategy = nil
55
69
  end
56
70
 
57
71
  alias_method :disconnect, :reset_connection
58
72
 
73
+ # Lazy initializes the requeue strategy configured for the adapter
74
+ # @return [BaseStrategy]
59
75
  def strategy
60
76
  @strategy ||= @configuration.strategy.new(session)
61
77
  end
62
78
 
79
+ # Lazy initializes and return the session
80
+ # @return [Session]
63
81
  def session
64
- @session ||= Session.new(connection, @configuration.session_options)
82
+ @session ||= Session.new(connection.create_channel, @configuration.session_options)
65
83
  end
66
84
 
67
85
  private
68
86
 
87
+ # Lazy initializes the connection
69
88
  def connection
70
89
  @connection ||= Connection.new(@configuration.connection_options)
71
90
  end
@@ -2,9 +2,6 @@ module Basquiat
2
2
  module Adapters
3
3
  # An adapter to be used in testing
4
4
  class Test < Basquiat::Adapters::Base
5
- class Message < BaseMessage
6
- end
7
-
8
5
  class << self
9
6
  def events
10
7
  @events ||= Hash.new { |hash, key| hash[key] = [] }
@@ -17,7 +14,7 @@ module Basquiat
17
14
 
18
15
  attr_reader :options
19
16
 
20
- def default_options
17
+ def base_options
21
18
  @event_names = []
22
19
  { host: '127.0.0.1', port: 123_456, durable: true }
23
20
  end
@@ -38,7 +35,7 @@ module Basquiat
38
35
  def listen(*)
39
36
  event = subscribed_event
40
37
  msg = self.class.events[event].shift
41
- msg ? procs[event].call(Message.new(msg)) : nil
38
+ msg ? procs[event].call(BaseMessage.new(msg)) : nil
42
39
  end
43
40
 
44
41
  private
@@ -1,14 +1,6 @@
1
1
  module Basquiat
2
2
  module Errors
3
- class StrategyNotRegistered < StandardError
4
- def initialize(symbol)
5
- super()
6
- @symbol = symbol
7
- end
8
-
9
- def message
10
- "No matching requeue strategy registered as :#{@symbol}"
11
- end
3
+ class StrategyNotRegistered < KeyError
12
4
  end
13
5
  end
14
6
  end