basquiat 1.1.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.metrics +5 -0
- data/.reek +3 -0
- data/.rspec +1 -0
- data/.rubocop.yml +2 -1
- data/.ruby-version +1 -1
- data/Guardfile +5 -4
- data/README.md +10 -8
- data/basquiat.gemspec +10 -8
- data/basquiat_docker.sh +35 -0
- data/docker-compose.yml +5 -1
- data/docker/Dockerfile +2 -3
- data/docker/guard_start.sh +3 -0
- data/lib/basquiat.rb +5 -0
- data/lib/basquiat/adapters/base_adapter.rb +21 -11
- data/lib/basquiat/adapters/base_message.rb +29 -0
- data/lib/basquiat/adapters/rabbitmq/configuration.rb +52 -0
- data/lib/basquiat/adapters/rabbitmq/connection.rb +89 -0
- data/lib/basquiat/adapters/rabbitmq/events.rb +49 -0
- data/lib/basquiat/adapters/rabbitmq/message.rb +33 -0
- data/lib/basquiat/adapters/rabbitmq/requeue_strategies.rb +3 -0
- data/lib/basquiat/adapters/rabbitmq/requeue_strategies/base_strategy.rb +33 -0
- data/lib/basquiat/adapters/rabbitmq/requeue_strategies/basic_acknowledge.rb +12 -0
- data/lib/basquiat/adapters/rabbitmq/requeue_strategies/dead_lettering.rb +58 -0
- data/lib/basquiat/adapters/rabbitmq/requeue_strategies/delayed_delivery.rb +27 -0
- data/lib/basquiat/adapters/rabbitmq/session.rb +47 -0
- data/lib/basquiat/adapters/rabbitmq_adapter.rb +39 -95
- data/lib/basquiat/adapters/test_adapter.rb +4 -3
- data/lib/basquiat/errors.rb +2 -0
- data/lib/basquiat/errors/strategy_not_registered.rb +14 -0
- data/lib/basquiat/errors/subclass_responsibility.rb +9 -0
- data/lib/basquiat/interfaces/base.rb +0 -1
- data/lib/basquiat/support/configuration.rb +4 -4
- data/lib/basquiat/support/hash_refinements.rb +2 -1
- data/lib/basquiat/version.rb +1 -1
- data/spec/lib/adapters/base_adapter_spec.rb +24 -6
- data/spec/lib/adapters/base_message_spec.rb +16 -0
- data/spec/lib/adapters/rabbitmq/configuration_spec.rb +47 -0
- data/spec/lib/adapters/rabbitmq/connection_spec.rb +45 -0
- data/spec/lib/adapters/rabbitmq/events_spec.rb +78 -0
- data/spec/lib/adapters/rabbitmq/message_spec.rb +26 -0
- data/spec/lib/adapters/rabbitmq/requeue_strategies/basic_acknowledge_spec.rb +38 -0
- data/spec/lib/adapters/rabbitmq/requeue_strategies/dead_lettering_spec.rb +102 -0
- data/spec/lib/adapters/rabbitmq_adapter_spec.rb +39 -49
- data/spec/lib/adapters/test_adapter_spec.rb +15 -19
- data/spec/lib/support/configuration_spec.rb +1 -1
- data/spec/lib/support/hash_refinements_spec.rb +8 -2
- data/spec/spec_helper.rb +8 -5
- data/spec/support/rabbitmq_queue_matchers.rb +53 -0
- data/spec/support/shared_examples/basquiat_adapter_shared_examples.rb +9 -20
- metadata +65 -6
- data/.travis.yml +0 -3
- data/docker/basquiat_start.sh +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f2ece36298347faf2fb2607326545c2d35f78d08
|
4
|
+
data.tar.gz: e461978745bacda7cbf9e276327a91acdf814701
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 88cfcff653f37e3f25519df53f4ca434af685cd6bc3146f4519e5b00c6efaea54c55fc2a051cbc131b8c92c734c77cc0d784bc83a2148aaccee463eb2857da15
|
7
|
+
data.tar.gz: 7c500da60290323968215415e264b2bbc698d5c1ac703212bf4bb2745b81ea704d78dae3cf371cab415cbac704032a0c8c23920417dfe1614bba41859bec901c
|
data/.gitignore
CHANGED
data/.metrics
CHANGED
data/.reek
ADDED
data/.rspec
CHANGED
data/.rubocop.yml
CHANGED
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-2.
|
1
|
+
ruby-2.2
|
data/Guardfile
CHANGED
@@ -3,15 +3,16 @@ guard :bundler do
|
|
3
3
|
watch('basquiat.gemspec')
|
4
4
|
end
|
5
5
|
|
6
|
-
guard :rspec, {
|
6
|
+
guard :rspec, { cmd: 'bundle exec rspec', all_on_start: true,
|
7
|
+
keep: true, all_after_pass: true, run_all: { cmd: 'rspec -f progress' } } do
|
7
8
|
watch(%r{^spec/.+_spec.rb$})
|
8
9
|
watch(%r{^spec/lib/.+_spec.rb$})
|
9
10
|
watch(%r{^lib/basquiat/(.+)\.rb$}) { |matchdata| "spec/lib/#{matchdata[1]}_spec.rb" }
|
10
|
-
watch('spec/spec_helper.rb')
|
11
|
-
watch(%r{spec/support/.+\.rb})
|
11
|
+
watch('spec/spec_helper.rb') { 'spec' }
|
12
|
+
watch(%r{spec/support/.+\.rb}) { 'spec' }
|
12
13
|
end
|
13
14
|
|
14
|
-
guard :rubocop, { cli: '-fs -c./.rubocop.yml'} do
|
15
|
+
guard :rubocop, { cmd: 'rubocop', cli: '-fs -c./.rubocop.yml' } do
|
15
16
|
#watch(%r{.+\.rb$})
|
16
17
|
#watch(%r{(?:.+/)?\.rubocop\.yml$}) { |m| File.dirname(m[0]) }
|
17
18
|
end
|
data/README.md
CHANGED
@@ -80,16 +80,18 @@ Yaml File configuration example:
|
|
80
80
|
queue_name: 'my.queue'
|
81
81
|
default_adapter: Basquiat::Adapters::RabbitMq
|
82
82
|
adapter_options:
|
83
|
-
|
83
|
+
servers:
|
84
84
|
-
|
85
85
|
:host: 'localhost'
|
86
86
|
:port: '5672'
|
87
|
-
|
87
|
+
failover:
|
88
88
|
:default_timeout: 5
|
89
89
|
:max_retries: 5
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
90
|
+
publisher:
|
91
|
+
confirm: true
|
92
|
+
persistent: true
|
93
|
+
auth:
|
94
|
+
user: 'guest'
|
95
|
+
password: 'guest'
|
96
|
+
requeue:
|
97
|
+
enabled: false
|
data/basquiat.gemspec
CHANGED
@@ -4,16 +4,16 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
4
|
require 'basquiat/version'
|
5
5
|
|
6
6
|
Gem::Specification.new do |spec|
|
7
|
-
spec.name
|
8
|
-
spec.version
|
9
|
-
spec.authors
|
10
|
-
spec.email
|
11
|
-
spec.description
|
7
|
+
spec.name = 'basquiat'
|
8
|
+
spec.version = Basquiat::VERSION
|
9
|
+
spec.authors = ['Marcello "mereghost" Rocha']
|
10
|
+
spec.email = %w(marcello.rocha@gmail.com.br)
|
11
|
+
spec.description = <<EOD
|
12
12
|
Basquiat is a library that intends to abstract all the complexity of working with message queues
|
13
13
|
EOD
|
14
|
-
spec.summary
|
15
|
-
spec.homepage
|
16
|
-
spec.license
|
14
|
+
spec.summary = 'A pluggable library that aims to hide message queue complexity'
|
15
|
+
spec.homepage = 'http://github.com/VAGAScom/basquiat'
|
16
|
+
spec.license = 'MIT'
|
17
17
|
|
18
18
|
spec.files = `git ls-files`.split($RS)
|
19
19
|
spec.executables = spec.files.grep(/^bin\//) { |f| File.basename(f) }
|
@@ -33,6 +33,8 @@ EOD
|
|
33
33
|
spec.add_development_dependency 'simplecov'
|
34
34
|
spec.add_development_dependency 'metric_fu'
|
35
35
|
spec.add_development_dependency 'rubocop'
|
36
|
+
spec.add_development_dependency 'byebug'
|
37
|
+
spec.add_development_dependency 'pry-byebug'
|
36
38
|
|
37
39
|
spec.add_dependency 'multi_json'
|
38
40
|
spec.add_dependency 'naught'
|
data/basquiat_docker.sh
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
function bundle_list() {
|
3
|
+
bundle list
|
4
|
+
}
|
5
|
+
|
6
|
+
function generate_gemfile() {
|
7
|
+
bundle_list | awk '
|
8
|
+
BEGIN {
|
9
|
+
FS=" "
|
10
|
+
print "source \"https://rubygems.org\"";
|
11
|
+
format = "gem \"%s\", \"%s\"\r\n";
|
12
|
+
}
|
13
|
+
{
|
14
|
+
if ($2 == "bundler") {
|
15
|
+
next;
|
16
|
+
}
|
17
|
+
if ($1 == "*") {
|
18
|
+
match($3, "[^()]+");
|
19
|
+
version = substr($3,RSTART,RLENGTH);
|
20
|
+
printf format, $2, version;
|
21
|
+
}
|
22
|
+
}' > docker/Gemfile
|
23
|
+
}
|
24
|
+
|
25
|
+
function stop_and_remove_containers {
|
26
|
+
docker-compose stop rabbitmq
|
27
|
+
docker rm basquiat_basquiat_run_1
|
28
|
+
docker rm --volumes=true basquiat_rabbitmq_1
|
29
|
+
}
|
30
|
+
|
31
|
+
generate_gemfile
|
32
|
+
docker-compose start rabbitmq
|
33
|
+
docker-compose run basquiat
|
34
|
+
|
35
|
+
trap stop_and_remove_containers EXIT SIGINT SIGTERM SIGKILL
|
data/docker-compose.yml
CHANGED
@@ -1,11 +1,15 @@
|
|
1
1
|
basquiat:
|
2
2
|
build: docker
|
3
|
-
command: /basquiat/docker/
|
3
|
+
command: /basquiat/docker/guard_start.sh
|
4
4
|
volumes:
|
5
5
|
- ./:/basquiat
|
6
6
|
links:
|
7
7
|
- rabbitmq
|
8
8
|
tty: true
|
9
|
+
stdin_open: true
|
9
10
|
|
10
11
|
rabbitmq:
|
11
12
|
image: mereghost/rabbitmq:latest
|
13
|
+
ports:
|
14
|
+
- "15672"
|
15
|
+
- "5672"
|
data/docker/Dockerfile
CHANGED
data/lib/basquiat.rb
CHANGED
@@ -3,6 +3,7 @@ require 'naught'
|
|
3
3
|
require 'yaml'
|
4
4
|
|
5
5
|
require 'basquiat/support'
|
6
|
+
require 'basquiat/errors'
|
6
7
|
require 'basquiat/adapters'
|
7
8
|
require 'basquiat/version'
|
8
9
|
require 'basquiat/interfaces/base'
|
@@ -21,6 +22,10 @@ module Basquiat
|
|
21
22
|
def configure
|
22
23
|
yield configuration
|
23
24
|
end
|
25
|
+
|
26
|
+
def logger
|
27
|
+
configuration.logger
|
28
|
+
end
|
24
29
|
end
|
25
30
|
end
|
26
31
|
|
@@ -1,15 +1,32 @@
|
|
1
|
+
require 'delegate'
|
2
|
+
require 'basquiat/adapters/base_message'
|
3
|
+
|
1
4
|
module Basquiat
|
2
5
|
module Adapters
|
3
6
|
# Base implementation for an adapter
|
4
|
-
|
7
|
+
class Base
|
5
8
|
using Basquiat::HashRefinements
|
6
9
|
|
10
|
+
class << self
|
11
|
+
def strategies
|
12
|
+
@strategies ||= {}
|
13
|
+
end
|
14
|
+
|
15
|
+
def register_strategy(config_name, klass)
|
16
|
+
strategies.merge!(config_name.to_sym => klass)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
7
20
|
def initialize
|
8
21
|
@options = base_options
|
9
22
|
@procs = {}
|
10
23
|
@retries = 0
|
11
24
|
end
|
12
25
|
|
26
|
+
def strategies
|
27
|
+
self.class.strategies
|
28
|
+
end
|
29
|
+
|
13
30
|
# Used to set the options for the adapter. It is merged in
|
14
31
|
# to the default_options hash.
|
15
32
|
# @param [Hash] opts an adapter dependant hash of options
|
@@ -27,28 +44,21 @@ module Basquiat
|
|
27
44
|
{}
|
28
45
|
end
|
29
46
|
|
30
|
-
def update_config
|
31
|
-
end
|
32
|
-
|
33
47
|
def publish
|
48
|
+
fail Basquiat::Errors::SubclassResponsibility
|
34
49
|
end
|
35
50
|
|
36
51
|
def subscribe_to
|
52
|
+
fail Basquiat::Errors::SubclassResponsibility
|
37
53
|
end
|
38
54
|
|
39
55
|
def disconnect
|
40
|
-
|
41
|
-
|
42
|
-
def disconnected?
|
56
|
+
fail Basquiat::Errors::SubclassResponsibility
|
43
57
|
end
|
44
58
|
|
45
59
|
private
|
46
60
|
|
47
61
|
attr_reader :procs, :options
|
48
|
-
|
49
|
-
def logger
|
50
|
-
Basquiat.configuration.logger
|
51
|
-
end
|
52
62
|
end
|
53
63
|
end
|
54
64
|
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Basquiat
|
2
|
+
module Adapters
|
3
|
+
class BaseMessage < SimpleDelegator
|
4
|
+
attr_reader :action
|
5
|
+
|
6
|
+
def initialize(message)
|
7
|
+
@message = Basquiat::Json.decode(message)
|
8
|
+
super(@message)
|
9
|
+
@action = :ack
|
10
|
+
end
|
11
|
+
|
12
|
+
def ack?
|
13
|
+
fail Basquiat::Errors::SubclassResponsibility
|
14
|
+
end
|
15
|
+
|
16
|
+
def unack
|
17
|
+
fail Basquiat::Errors::SubclassResponsibility
|
18
|
+
end
|
19
|
+
|
20
|
+
def requeue
|
21
|
+
fail Basquiat::Errors::SubclassResponsibility
|
22
|
+
end
|
23
|
+
|
24
|
+
def delay_redelivery
|
25
|
+
fail Basquiat::Errors::SubclassResponsibility
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module Basquiat
|
2
|
+
module Adapters
|
3
|
+
class RabbitMq
|
4
|
+
class Configuration
|
5
|
+
using Basquiat::HashRefinements
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@options = { failover: { default_timeout: 5, max_retries: 5 },
|
9
|
+
servers: [{ host: 'localhost', port: 5672 }],
|
10
|
+
queue: {
|
11
|
+
name: Basquiat.configuration.queue_name,
|
12
|
+
options: { durable: true } },
|
13
|
+
exchange: {
|
14
|
+
name: Basquiat.configuration.exchange_name,
|
15
|
+
options: { durable: true } },
|
16
|
+
publisher: { confirm: true, persistent: false },
|
17
|
+
auth: { user: 'guest', password: 'guest' },
|
18
|
+
requeue: { enabled: false } }
|
19
|
+
end
|
20
|
+
|
21
|
+
def base_options
|
22
|
+
@options
|
23
|
+
end
|
24
|
+
|
25
|
+
def merge_user_options(user_opts)
|
26
|
+
@options.merge!(user_opts)
|
27
|
+
end
|
28
|
+
|
29
|
+
def connection_options
|
30
|
+
{ servers: @options[:servers],
|
31
|
+
failover: @options[:failover],
|
32
|
+
auth: @options[:auth] }
|
33
|
+
end
|
34
|
+
|
35
|
+
def session_options
|
36
|
+
{ exchange: @options[:exchange],
|
37
|
+
publisher: @options[:publisher],
|
38
|
+
queue: @options[:queue] }.deep_merge(strategy.session_options)
|
39
|
+
end
|
40
|
+
|
41
|
+
def strategy
|
42
|
+
return BasicAcknowledge unless @options[:requeue][:enabled]
|
43
|
+
@strategy ||= RabbitMq.strategies.fetch(@options[:requeue][:strategy].to_sym)
|
44
|
+
@strategy.setup(@options[:requeue][:options] || {})
|
45
|
+
@strategy
|
46
|
+
rescue KeyError
|
47
|
+
fail Basquiat::Errors::StrategyNotRegistered.new(@options[:requeue][:strategy])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,89 @@
|
|
1
|
+
module Basquiat
|
2
|
+
module Adapters
|
3
|
+
class RabbitMq
|
4
|
+
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)
|
9
|
+
end
|
10
|
+
|
11
|
+
def start
|
12
|
+
with_network_failure_handler do
|
13
|
+
connection.start
|
14
|
+
current_server[:retries] = 0
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def connected?
|
19
|
+
connection.status == :started
|
20
|
+
end
|
21
|
+
|
22
|
+
def disconnect
|
23
|
+
connection.close_all_channels
|
24
|
+
connection.close
|
25
|
+
reset
|
26
|
+
end
|
27
|
+
|
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
|
+
private
|
44
|
+
|
45
|
+
def reset
|
46
|
+
@connection = nil
|
47
|
+
end
|
48
|
+
|
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
|
+
def connection
|
64
|
+
Basquiat.logger.info("Connecting to #{current_server_uri}")
|
65
|
+
@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)
|
72
|
+
__setobj__(@connection)
|
73
|
+
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
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|