banter 0.4.1 → 0.5.0
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.
- checksums.yaml +4 -4
- data/.travis.yml +5 -0
- data/README.md +4 -3
- data/Rakefile +6 -0
- data/lib/banter.rb +7 -10
- data/lib/banter/cli.rb +1 -0
- data/lib/banter/configuration.rb +38 -6
- data/lib/banter/publisher.rb +13 -18
- data/lib/banter/rabbit_logger.rb +32 -0
- data/lib/banter/railtie.rb +10 -0
- data/lib/banter/server/client_queue_listener.rb +3 -3
- data/lib/banter/server/rabbit_mq_subscriber.rb +7 -8
- data/lib/banter/server/subscriber_server.rb +3 -3
- data/lib/banter/subscriber.rb +9 -4
- data/lib/banter/version.rb +1 -1
- data/lib/generators/banter/install_generator.rb +13 -0
- data/lib/generators/banter/templates/banter.yml +38 -0
- data/spec/banter/configuration_spec.rb +10 -0
- data/spec/{message_spec.rb → banter/message_spec.rb} +0 -0
- data/spec/banter/rabbit_logger_spec.rb +73 -0
- data/spec/banter/server/client_queue_listener_spec.rb +2 -3
- data/spec/banter/{server/client_worker_spec.rb → subscriber_spec.rb} +17 -1
- data/spec/spec_helper.rb +2 -1
- metadata +14 -11
- data/config/pubsub.yml +0 -17
- data/lib/banter/logger.rb +0 -49
- data/lib/banter/logging.rb +0 -42
- data/spec/logger_spec.rb +0 -110
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9d0f8fa6fb6efcc9befadeaac184560b989606f3
|
4
|
+
data.tar.gz: 55445f64eb387bacb905718ba61284d272d72db7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 820d17a44fdb4b450f0d982c689ccc16883d589208c990db1b9e7279109876e55585c11404dc5dccf1839e823fe513ef59575c37d010784ec6f3f529e2195b6a
|
7
|
+
data.tar.gz: 5e74cca350d83ac11c6a8e32ca4fb771d931593616839b5086f4f25118a48d5e3a6f663dd7b3aea6833a7c3910b029687bca1c75afe8eb6850a9da57f7f1a209
|
data/.travis.yml
ADDED
data/README.md
CHANGED
@@ -2,7 +2,8 @@
|
|
2
2
|
|
3
3
|
Simple Publishers and subscribers for Ruby using RabbitMQ
|
4
4
|
|
5
|
-
[](https://travis-ci.org/honest/banter)
|
6
|
+

|
6
7
|
|
7
8
|
Developed & maintained by [The Honest Company](https://www.honest.com). We are always looking for the best talent, find your next opportunity at [Honest Careers](https://www.honest.com/careers)
|
8
9
|
|
@@ -61,8 +62,8 @@ You can declare a subscriber class as follows
|
|
61
62
|
|
62
63
|
```ruby
|
63
64
|
class UserWelcomeSubscriber < Banter::Subscriber
|
64
|
-
subscribe_to "user_created"
|
65
|
-
#
|
65
|
+
subscribe_to "user_created"
|
66
|
+
# Message prefix that you're subscribing to. You can also specify options for queue_name and queue_ttl
|
66
67
|
|
67
68
|
def perform(payload)
|
68
69
|
# My awesome logic goes here...
|
data/Rakefile
CHANGED
data/lib/banter.rb
CHANGED
@@ -5,9 +5,8 @@ require "airbrake"
|
|
5
5
|
|
6
6
|
require "banter/configuration"
|
7
7
|
require "banter/context"
|
8
|
-
require "banter/db_logger"
|
9
|
-
require "banter/
|
10
|
-
require "banter/logging"
|
8
|
+
# require "banter/db_logger"
|
9
|
+
require "banter/rabbit_logger"
|
11
10
|
require "banter/message"
|
12
11
|
require "banter/publisher"
|
13
12
|
require "banter/server/rabbit_mq_subscriber"
|
@@ -23,10 +22,6 @@ end
|
|
23
22
|
|
24
23
|
module Banter
|
25
24
|
|
26
|
-
def self.root
|
27
|
-
File.expand_path '../..', __FILE__
|
28
|
-
end
|
29
|
-
|
30
25
|
# This method publishes payload to rabbitmq. All listeners with appropriate
|
31
26
|
# routing keys will receive the payload.
|
32
27
|
# @param [String] routing_key Identifier of the message type
|
@@ -36,12 +31,14 @@ module Banter
|
|
36
31
|
Publisher.instance.publish(Banter::Context.instance, routing_key, payload)
|
37
32
|
end
|
38
33
|
|
34
|
+
# @return [Logger] Logger used for logging through the Banter gem
|
39
35
|
def self.logger
|
40
|
-
Banter::
|
36
|
+
return Banter::Configuration.logger if Banter::Configuration.logger
|
37
|
+
@logger ||= ActiveSupport::TaggedLogging.new(Logger.new($stdout))
|
41
38
|
end
|
42
39
|
|
43
|
-
# @param [Logger] logger Logger
|
40
|
+
# @param [Logger] logger Logger for publish, message received and error events
|
44
41
|
def self.logger=(logger)
|
45
|
-
Banter::
|
42
|
+
Banter::Configuration.logger = ActiveSupport::TaggedLogging.new(logger)
|
46
43
|
end
|
47
44
|
end
|
data/lib/banter/cli.rb
CHANGED
data/lib/banter/configuration.rb
CHANGED
@@ -1,9 +1,41 @@
|
|
1
1
|
module Banter
|
2
|
-
|
2
|
+
module Configuration
|
3
3
|
@@conf = nil
|
4
4
|
|
5
|
+
# Configuration setting to specify the number of seconds a message will live in the queue before
|
6
|
+
# being either consumed or discarded.
|
7
|
+
# @default 1 hour
|
8
|
+
mattr_accessor :default_queue_ttl
|
9
|
+
@@default_queue_ttl = 1.hour
|
10
|
+
|
11
|
+
# The exchange to publish (and subscribe) on RabbitMQ
|
12
|
+
# @default true
|
13
|
+
mattr_accessor :exchange_name
|
14
|
+
@@exchange_name = "banter"
|
15
|
+
|
16
|
+
# The topic prefix for RabbitMQ
|
17
|
+
# @default banter
|
18
|
+
mattr_accessor :topic_prefix
|
19
|
+
@@topic_prefix = "banter"
|
20
|
+
|
21
|
+
mattr_accessor :logger
|
22
|
+
|
23
|
+
# RabbitMQ push and subscribe logging toggle
|
24
|
+
# @default true
|
25
|
+
mattr_accessor :logging_enabled
|
26
|
+
@@logging_enabled = true
|
27
|
+
|
28
|
+
# RabbitMQ push enabled
|
29
|
+
# @default true
|
30
|
+
mattr_accessor :push_enabled
|
31
|
+
@@push_enabled = true
|
32
|
+
|
33
|
+
# Dead letter queue name
|
34
|
+
# @default nil
|
35
|
+
mattr_accessor :dead_letter_queue
|
36
|
+
|
5
37
|
def self.configure_with(environment_name, yaml_file = nil)
|
6
|
-
@@yaml_file = yaml_file.nil? ? "config/
|
38
|
+
@@yaml_file = yaml_file.nil? ? "config/banter.yml" : yaml_file
|
7
39
|
@@all_conf = Hashie::Mash.new(YAML.load_file(@@yaml_file) )
|
8
40
|
@@conf = @@all_conf[environment_name.to_sym]
|
9
41
|
self
|
@@ -14,6 +46,10 @@ module Banter
|
|
14
46
|
@@conf
|
15
47
|
end
|
16
48
|
|
49
|
+
def self.connection
|
50
|
+
configuration[:connection]
|
51
|
+
end
|
52
|
+
|
17
53
|
def self.environment
|
18
54
|
val = ENV["RAILS_ENV"] || ENV["RACK_ENV"]
|
19
55
|
val = if val.present?
|
@@ -27,10 +63,6 @@ module Banter
|
|
27
63
|
end
|
28
64
|
end
|
29
65
|
|
30
|
-
def self.default_queue_ttl
|
31
|
-
24.hours * 1000
|
32
|
-
end
|
33
|
-
|
34
66
|
def self.application_name
|
35
67
|
@application_name ||= if defined?(Rails)
|
36
68
|
Rails.application.class.name.to_s.gsub("::Application", '')
|
data/lib/banter/publisher.rb
CHANGED
@@ -12,14 +12,9 @@ module Banter
|
|
12
12
|
@@publisher
|
13
13
|
end
|
14
14
|
|
15
|
-
def initialize(exchange=
|
16
|
-
@exchange = exchange
|
15
|
+
def initialize(exchange = nil)
|
16
|
+
@exchange = exchange || Banter::Configuration.exchange_name
|
17
17
|
@disabled = false
|
18
|
-
@logger = ::Banter::Logger.new()
|
19
|
-
|
20
|
-
@config = Configuration.configuration
|
21
|
-
|
22
|
-
self
|
23
18
|
end
|
24
19
|
|
25
20
|
def enable(value)
|
@@ -28,47 +23,47 @@ module Banter
|
|
28
23
|
end
|
29
24
|
|
30
25
|
def start
|
31
|
-
|
26
|
+
unless Configuration.push_enabled
|
32
27
|
@disabled = true
|
33
28
|
return
|
34
29
|
end
|
35
30
|
|
36
31
|
# grab server configuration from initialization file somewhere
|
37
32
|
begin
|
38
|
-
@connection = Bunny.new(Configuration.
|
33
|
+
@connection = Bunny.new(Configuration.connection)
|
39
34
|
@connection.start
|
40
35
|
|
41
|
-
@channel
|
42
|
-
@publisher = @channel.topic(@exchange, :durable=>true, :auto_delete=>false)
|
36
|
+
@channel = @connection.create_channel
|
37
|
+
@publisher = @channel.topic(@exchange, :durable => true, :auto_delete => false)
|
43
38
|
|
44
39
|
rescue => e
|
45
|
-
Airbrake.notify(e, parameters: {message: e.message}, environment_name: ENV['RAILS_ENV']
|
40
|
+
Airbrake.notify(e, parameters: { message: e.message }, environment_name: ENV['RAILS_ENV'])
|
46
41
|
return
|
47
42
|
end
|
48
43
|
|
49
44
|
|
50
45
|
@publisher.on_return do |return_info, properties, content|
|
51
46
|
# contents are already transformed into message that we want to send
|
52
|
-
|
47
|
+
Banter::RabbitLogger.failed_publish(return_info[:routing_key], properties, content)
|
53
48
|
end
|
54
49
|
|
55
50
|
end
|
56
51
|
|
57
52
|
def publish(context, key, payload, enabled = true)
|
58
53
|
routing_key = "#{@exchange}.#{key}"
|
59
|
-
envelope
|
54
|
+
envelope = ::Banter::Message.new.serialize(context, key, payload)
|
60
55
|
|
61
56
|
if @publisher.nil?
|
62
57
|
start
|
63
58
|
end
|
64
59
|
|
65
60
|
if @disabled || @publisher.nil? || !enabled
|
66
|
-
|
61
|
+
Banter::RabbitLogger.failed_publish(routing_key, {}, envelope)
|
67
62
|
else
|
68
63
|
tries = 2
|
69
64
|
begin
|
70
|
-
@publisher.publish(envelope.to_json, :persistent=>true, :mandatory=>true, :timestamp=>envelope[:ts], :content_type=>"application/json", :routing_key =>routing_key
|
71
|
-
|
65
|
+
@publisher.publish(envelope.to_json, :persistent => true, :mandatory => true, :timestamp => envelope[:ts], :content_type => "application/json", :routing_key => routing_key)
|
66
|
+
Banter::RabbitLogger.log_publish(routing_key, envelope)
|
72
67
|
rescue => e
|
73
68
|
tries -= 1
|
74
69
|
teardown
|
@@ -76,7 +71,7 @@ module Banter
|
|
76
71
|
if tries > 0 && @publisher
|
77
72
|
retry
|
78
73
|
else
|
79
|
-
|
74
|
+
Banter::RabbitLogger.failed_publish(routing_key, {}, envelope)
|
80
75
|
end
|
81
76
|
end
|
82
77
|
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# Internal log class that is used to log messages before sending, after receiving, and failure to send
|
2
|
+
module Banter
|
3
|
+
class RabbitLogger
|
4
|
+
def self.enabled?
|
5
|
+
Banter::Configuration.logging_enabled
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.log_publish(routing_key, message)
|
9
|
+
return unless enabled?
|
10
|
+
tags = ["BANTER PUBLISH", message[:ts], message[:pub], message[:v], routing_key]
|
11
|
+
Banter.logger.tagged(tags) { Banter.logger.debug message[:payload].as_json }
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.failed_publish(routing_key, properties, message)
|
15
|
+
return unless enabled?
|
16
|
+
tags = ["BANTER FAILED_SEND", message[:ts], message[:pub], message[:v], routing_key]
|
17
|
+
Banter.logger.tagged(tags) { Banter.logger.error message[:payload].as_json }
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.log_receive(routing_key, message)
|
21
|
+
return unless enabled?
|
22
|
+
tags = ["BANTER RECEIVED", message[:ts], message[:pub], message[:v], routing_key, Process::pid]
|
23
|
+
Banter.logger.tagged(tags) { Banter.logger.debug message[:payload].as_json }
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.log_service(service_name, message)
|
27
|
+
return unless enabled?
|
28
|
+
tags = ["BANTER SERVICE", service_name, Process::pid]
|
29
|
+
Banter.logger.tagged(tags) {Banter.logger.info message[:payload].as_json}
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/banter/railtie.rb
CHANGED
@@ -1,11 +1,19 @@
|
|
1
1
|
# This railtie provides Rails engine hooks
|
2
|
+
require 'banter/middleware'
|
3
|
+
require 'banter/configuration'
|
2
4
|
|
3
5
|
module Banter
|
4
6
|
class Railtie < ::Rails::Railtie
|
7
|
+
config.banter = Banter::Configuration
|
8
|
+
|
5
9
|
initializer "banter.insert_middleware" do |app|
|
6
10
|
app.config.middleware.use Banter::Middleware
|
7
11
|
end
|
8
12
|
|
13
|
+
config.after_initialize do
|
14
|
+
Banter.logger = Rails.logger
|
15
|
+
end
|
16
|
+
|
9
17
|
console do
|
10
18
|
# Set up basic context to identify messages getting generated from console
|
11
19
|
Banter::Context.setup_context(
|
@@ -23,5 +31,7 @@ module Banter
|
|
23
31
|
unique_id: Digest::SHA1.new.to_s
|
24
32
|
)
|
25
33
|
end
|
34
|
+
|
35
|
+
|
26
36
|
end
|
27
37
|
end
|
@@ -10,13 +10,13 @@ module Banter
|
|
10
10
|
|
11
11
|
attr_reader :worker_class
|
12
12
|
|
13
|
-
def initialize(worker_class, request_key, queue, durable = true, topic =
|
14
|
-
@topic = topic
|
13
|
+
def initialize(worker_class, request_key, queue, durable = true, topic = nil)
|
14
|
+
@topic = topic || Banter::Configuration.topic_prefix
|
15
15
|
@request_key = request_key
|
16
16
|
@worker_class = worker_class
|
17
17
|
@queue_name = queue
|
18
18
|
@durable = durable
|
19
|
-
@subscriber = ::Banter::Server::RabbitMQSubscriber.new(@request_key, @durable, @topic)
|
19
|
+
@subscriber = ::Banter::Server::RabbitMQSubscriber.new(@request_key, worker_class.queue_ttl, @durable, @topic)
|
20
20
|
end
|
21
21
|
|
22
22
|
def start
|
@@ -5,27 +5,26 @@ module Banter
|
|
5
5
|
attr_reader :listener
|
6
6
|
attr_reader :exchange
|
7
7
|
attr_reader :channel
|
8
|
+
attr_reader :ttl
|
8
9
|
|
9
|
-
def initialize(routing_key, durable = true, topic=
|
10
|
+
def initialize(routing_key, ttl, durable = true, topic = Banter::Configuration.topic_prefix)
|
10
11
|
@initial_key = routing_key
|
11
12
|
@durable = durable
|
12
13
|
@topic = topic
|
14
|
+
@ttl = ttl
|
13
15
|
|
14
16
|
if @initial_key.present?
|
15
17
|
@routing_key = "#{@topic}.#{@initial_key}.#"
|
16
18
|
else
|
17
19
|
@routing_key = "#{@topic}.#"
|
18
20
|
end
|
19
|
-
@logger = ::Banter::Logger.new
|
20
|
-
|
21
|
-
self
|
22
21
|
end
|
23
22
|
|
24
23
|
# name - used to ensure that certain consumers are actually listening to an exchange
|
25
24
|
# pass in a lambda for this method to work. We might only want to expose the content instead of
|
26
25
|
# all 3 chunks.
|
27
26
|
def start(name, blocking=false)
|
28
|
-
@connection = Bunny.new(Configuration.
|
27
|
+
@connection = Bunny.new(Configuration.connection)
|
29
28
|
begin
|
30
29
|
@connection.start
|
31
30
|
rescue => e
|
@@ -46,8 +45,8 @@ module Banter
|
|
46
45
|
end
|
47
46
|
|
48
47
|
queue_arguments = {}
|
49
|
-
queue_arguments["x-dead-letter-exchange"] = Configuration.
|
50
|
-
queue_arguments["x-message-ttl"] =
|
48
|
+
queue_arguments["x-dead-letter-exchange"] = Configuration.dead_letter_queue if Configuration.dead_letter_queue.present?
|
49
|
+
queue_arguments["x-message-ttl"] = ttl * 1000
|
51
50
|
@listener = @channel.queue(@queue, arguments: queue_arguments).bind(@exchange, routing_key: @routing_key, exclusive: false)
|
52
51
|
|
53
52
|
# Parameters for subscribe that might be useful:
|
@@ -60,7 +59,7 @@ module Banter
|
|
60
59
|
Airbrake.notify("PubSub Message redelivery", params: { info: delivery_info, props: properties, contents: contents }, environment_name: ENV['RAILS_ENV'])
|
61
60
|
end
|
62
61
|
message = ::Banter::Message.new.parse(contents)
|
63
|
-
|
62
|
+
Banter::RabbitLogger.log_receive(delivery_info[:routing_key], message)
|
64
63
|
yield delivery_info, properties, message
|
65
64
|
true
|
66
65
|
end
|
@@ -38,15 +38,15 @@ module Banter
|
|
38
38
|
|
39
39
|
Thread.stop
|
40
40
|
|
41
|
-
::Banter::
|
41
|
+
::Banter::RabbitLogger.log_service("all_services", "Starting shutdown of all services")
|
42
42
|
|
43
43
|
@workers.each do |worker|
|
44
|
-
::Banter::
|
44
|
+
::Banter::RabbitLogger.log_service("all_services", "Tearing down worker: #{worker.worker_class.name}")
|
45
45
|
begin
|
46
46
|
STDOUT.puts "Tearing down subscriber for #{worker.worker_class.name}"
|
47
47
|
worker.shutdown
|
48
48
|
rescue => e
|
49
|
-
::Banter::
|
49
|
+
::Banter::RabbitLogger.log_service("all_services", "#{worker.worker_class.name} - did not tear down correctly. Error - #{e.message}")
|
50
50
|
end
|
51
51
|
end
|
52
52
|
ensure
|
data/lib/banter/subscriber.rb
CHANGED
@@ -8,7 +8,7 @@ module Banter
|
|
8
8
|
class Subscriber
|
9
9
|
@@registered_subscribers = []
|
10
10
|
|
11
|
-
class_attribute :payload_validators, :error_handlers, :subscribed_key, :subscribed_queue
|
11
|
+
class_attribute :payload_validators, :error_handlers, :subscribed_key, :subscribed_queue, :queue_ttl
|
12
12
|
attr_accessor :delivery_routing_data, :delivery_properties, :context
|
13
13
|
|
14
14
|
def self.inherited(klass)
|
@@ -17,14 +17,19 @@ module Banter
|
|
17
17
|
|
18
18
|
# Specify the routing key that the subscriber class should listen to.
|
19
19
|
# @param [String] routing_key_name The routing key to subscribe to. Must be characters only separated by periods (.)
|
20
|
-
# @param [Hash] options
|
20
|
+
# @param [Hash] options subscription options
|
21
|
+
# @option [String] :on Optionally specify a queue. If not provided, queue name is generated from the routing key
|
22
|
+
# @option [Integer] :queue_ttl Time, in seconds, that the message lives on the queue before being either consumer by a subscriber or being discarded.
|
23
|
+
# If not specified, then Banter::Configuration.default_queue_ttl is used
|
24
|
+
|
21
25
|
def self.subscribe_to(routing_key_name, options = {})
|
22
|
-
options.assert_valid_keys(:on)
|
26
|
+
options.assert_valid_keys(:on, :queue_ttl)
|
23
27
|
unless validate_routing_key_name(routing_key_name)
|
24
28
|
raise ArgumentError.new("#{routing_key_name} is not supported. Only lower case characters separated by periods are allowed.")
|
25
29
|
end
|
26
30
|
self.subscribed_key = routing_key_name
|
27
31
|
self.subscribed_queue = generated_queue_name(routing_key_name, options[:on])
|
32
|
+
self.queue_ttl = options[:queue_ttl] || Banter::Configuration.default_queue_ttl
|
28
33
|
end
|
29
34
|
|
30
35
|
# Sets the validator for payload
|
@@ -59,7 +64,7 @@ module Banter
|
|
59
64
|
raise ::Banter::PayloadValidationError.new("Invalid Payload for #{self.class.name}")
|
60
65
|
end
|
61
66
|
|
62
|
-
perform(
|
67
|
+
perform(payload)
|
63
68
|
end
|
64
69
|
|
65
70
|
# Actual subscribers need to implement perform method. This is the method where the message is actually processed.
|
data/lib/banter/version.rb
CHANGED
@@ -0,0 +1,13 @@
|
|
1
|
+
module Banter
|
2
|
+
class InstallGenerator < Rails::Generators::Base
|
3
|
+
source_root File.expand_path("../templates", __FILE__)
|
4
|
+
def copy_config_file
|
5
|
+
copy_file "banter.yml", "config/banter.yml"
|
6
|
+
end
|
7
|
+
|
8
|
+
def add_config_parameters
|
9
|
+
application "config.banter.default_queue_ttl = 1.hour"
|
10
|
+
application "config.banter.logger = Rails.logger"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
development:
|
2
|
+
|
3
|
+
# Documentation for parameters for rabbit and bunny is located here: http://rubybunny.info/articles/connecting.html
|
4
|
+
connection:
|
5
|
+
host: localhost
|
6
|
+
port: 5672
|
7
|
+
# username: rabbit
|
8
|
+
# password: rabbit
|
9
|
+
heartbeat: 60 # in seconds
|
10
|
+
log_level: 0
|
11
|
+
# log_file: log/rabbit.log
|
12
|
+
network_recovery_interval: 10 # in seconds
|
13
|
+
continuation_timeout: 4000 # in milliseconds
|
14
|
+
|
15
|
+
test:
|
16
|
+
# Documentation for parameters for rabbit and bunny is located here: http://rubybunny.info/articles/connecting.html
|
17
|
+
connection:
|
18
|
+
host: localhost
|
19
|
+
port: 5672
|
20
|
+
# username: rabbit
|
21
|
+
# password: rabbit
|
22
|
+
heartbeat: 60 # in seconds
|
23
|
+
log_level: 0
|
24
|
+
# log_file: log/rabbit.log
|
25
|
+
network_recovery_interval: 10 # in seconds
|
26
|
+
continuation_timeout: 4000 # in milliseconds
|
27
|
+
|
28
|
+
production:
|
29
|
+
connection:
|
30
|
+
host: localhost
|
31
|
+
port: 5672
|
32
|
+
# username: rabbit
|
33
|
+
# password: rabbit
|
34
|
+
heartbeat: 60 # in seconds
|
35
|
+
log_level: 0
|
36
|
+
# log_file: log/rabbit.log
|
37
|
+
network_recovery_interval: 10 # in seconds
|
38
|
+
continuation_timeout: 4000 # in milliseconds
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Banter::Configuration do
|
4
|
+
context "default_queue_ttl" do
|
5
|
+
context 'value overridden' do
|
6
|
+
before { Banter::Configuration.default_queue_ttl = 2.hour }
|
7
|
+
it { expect(Banter::Configuration.default_queue_ttl).to eq 2.hour }
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
File without changes
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Banter::RabbitLogger do
|
4
|
+
let(:routing_key) { "test/logger" }
|
5
|
+
let(:subject) { Banter::RabbitLogger }
|
6
|
+
let(:payload) { {"hit"=>"me"} }
|
7
|
+
let(:message) { Banter::Message.new.serialize(context, routing_key, payload) }
|
8
|
+
let(:config_buffer) { StringIO.new }
|
9
|
+
let(:output_string) { config_buffer.string }
|
10
|
+
let(:context) { {unique_id: "1234", orig_ip_address: "127.0.0.1"}}
|
11
|
+
|
12
|
+
before do
|
13
|
+
allow(Banter.logger).to receive(:debug)
|
14
|
+
allow(Banter.logger).to receive(:info)
|
15
|
+
allow(Banter.logger).to receive(:warning)
|
16
|
+
allow(Banter.logger).to receive(:error)
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#log_publish" do
|
20
|
+
let!(:result) { subject.log_publish(routing_key, message)}
|
21
|
+
|
22
|
+
it "should not fail" do
|
23
|
+
expect{ result }.not_to raise_error
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should write a row to the log" do
|
27
|
+
expect(Banter.logger).to have_received(:debug).with(anything)
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#failed_publish" do
|
33
|
+
let!(:result) { subject.failed_publish(routing_key, {}, message)}
|
34
|
+
|
35
|
+
context "warning log level" do
|
36
|
+
|
37
|
+
it "should not fail" do
|
38
|
+
expect{ result }.not_to raise_error()
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should respect the log level of the file" do
|
42
|
+
expect(Banter.logger).to have_received(:error).with(anything)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#log_receive" do
|
48
|
+
let!(:result) { subject.log_receive(routing_key, message)}
|
49
|
+
|
50
|
+
it "should not fail" do
|
51
|
+
expect{ result }.not_to raise_error()
|
52
|
+
end
|
53
|
+
|
54
|
+
it "should respect the log level of the file" do
|
55
|
+
expect(Banter.logger).to have_received(:debug).with(anything)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#log_service" do
|
60
|
+
let(:service_name) { "test" }
|
61
|
+
let!(:result) { subject.log_service(service_name, message)}
|
62
|
+
|
63
|
+
context "debugger log" do
|
64
|
+
it "should not fail" do
|
65
|
+
expect{ result }.not_to raise_error()
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should respect the log level of the file" do
|
69
|
+
expect(Banter.logger).to have_received(:info).with(anything)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -31,18 +31,17 @@ describe Banter::Server::ClientQueueListener do
|
|
31
31
|
context "Normal execution" do
|
32
32
|
let!(:klass_instance){
|
33
33
|
instance = Klass.new({},{}, {})
|
34
|
-
allow(instance).to receive(:perform)
|
34
|
+
allow(instance).to receive(:perform!)
|
35
35
|
instance
|
36
36
|
}
|
37
37
|
|
38
38
|
context "test exception" do
|
39
39
|
let(:no_call) { true }
|
40
|
-
|
41
40
|
it { should_not raise_exception }
|
42
41
|
end
|
43
42
|
|
44
43
|
context "call" do
|
45
|
-
it { expect(klass_instance).to have_received(:perform).with(
|
44
|
+
it { expect(klass_instance).to have_received(:perform!).with(payload) }
|
46
45
|
end
|
47
46
|
end
|
48
47
|
|
@@ -150,12 +150,28 @@ describe Banter::Subscriber do
|
|
150
150
|
end
|
151
151
|
|
152
152
|
context 'invalid routing key' do
|
153
|
-
before { }
|
154
153
|
it 'sets the routing key and queue name' do
|
155
154
|
expect {
|
156
155
|
Klass.subscribe_to 'a.b.c.', on: 'foo_bar'
|
157
156
|
}.to raise_error(ArgumentError)
|
158
157
|
end
|
159
158
|
end
|
159
|
+
|
160
|
+
context "queue_ttl" do
|
161
|
+
context "option provided" do
|
162
|
+
before { Klass.subscribe_to "a.b", queue_ttl: 4 }
|
163
|
+
it 'sets the ttl' do
|
164
|
+
expect(Klass.queue_ttl).to eq(4)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
context "option not provided" do
|
169
|
+
before { Klass.subscribe_to "a.b" }
|
170
|
+
it 'uses default' do
|
171
|
+
expect(Klass.queue_ttl).to eq(Banter::Configuration.default_queue_ttl)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
end
|
160
176
|
end
|
161
177
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -26,7 +26,8 @@ RSpec.configure do |config|
|
|
26
26
|
config.order = 'random'
|
27
27
|
end
|
28
28
|
|
29
|
-
Banter::Configuration.configure_with("test", File.
|
29
|
+
Banter::Configuration.configure_with("test", File.expand_path("../config.yml", __FILE__))
|
30
|
+
Banter::Configuration.logger = ActiveSupport::TaggedLogging.new(Logger.new(nil))
|
30
31
|
|
31
32
|
# Some test subscriber classes to make testing easier
|
32
33
|
class MyTestSubscriber1 < Banter::Subscriber
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: banter
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- The Honest Company
|
@@ -11,7 +11,7 @@ authors:
|
|
11
11
|
autorequire:
|
12
12
|
bindir: bin
|
13
13
|
cert_chain: []
|
14
|
-
date: 2014-07-
|
14
|
+
date: 2014-07-08 00:00:00.000000000 Z
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
17
17
|
name: bundler
|
@@ -193,24 +193,23 @@ extra_rdoc_files: []
|
|
193
193
|
files:
|
194
194
|
- .gitignore
|
195
195
|
- .ruby-version
|
196
|
+
- .travis.yml
|
196
197
|
- Gemfile
|
197
198
|
- LICENSE.txt
|
198
199
|
- README.md
|
199
200
|
- Rakefile
|
200
201
|
- banter.gemspec
|
201
202
|
- bin/start_subscribers
|
202
|
-
- config/pubsub.yml
|
203
203
|
- lib/banter.rb
|
204
204
|
- lib/banter/cli.rb
|
205
205
|
- lib/banter/configuration.rb
|
206
206
|
- lib/banter/context.rb
|
207
207
|
- lib/banter/db_logger.rb
|
208
208
|
- lib/banter/exceptions/payload_validation_error.rb
|
209
|
-
- lib/banter/logger.rb
|
210
|
-
- lib/banter/logging.rb
|
211
209
|
- lib/banter/message.rb
|
212
210
|
- lib/banter/middleware.rb
|
213
211
|
- lib/banter/publisher.rb
|
212
|
+
- lib/banter/rabbit_logger.rb
|
214
213
|
- lib/banter/railtie.rb
|
215
214
|
- lib/banter/server.rb
|
216
215
|
- lib/banter/server/client_queue_listener.rb
|
@@ -218,13 +217,16 @@ files:
|
|
218
217
|
- lib/banter/server/subscriber_server.rb
|
219
218
|
- lib/banter/subscriber.rb
|
220
219
|
- lib/banter/version.rb
|
220
|
+
- lib/generators/banter/install_generator.rb
|
221
|
+
- lib/generators/banter/templates/banter.yml
|
221
222
|
- spec/banter/cli_spec.rb
|
223
|
+
- spec/banter/configuration_spec.rb
|
224
|
+
- spec/banter/message_spec.rb
|
225
|
+
- spec/banter/rabbit_logger_spec.rb
|
222
226
|
- spec/banter/server/client_queue_listener_spec.rb
|
223
|
-
- spec/banter/server/client_worker_spec.rb
|
224
227
|
- spec/banter/server/rabbitmq_subscriber_spec.rb
|
228
|
+
- spec/banter/subscriber_spec.rb
|
225
229
|
- spec/config.yml
|
226
|
-
- spec/logger_spec.rb
|
227
|
-
- spec/message_spec.rb
|
228
230
|
- spec/spec_helper.rb
|
229
231
|
homepage: https://github.com/honest/banter
|
230
232
|
licenses:
|
@@ -252,10 +254,11 @@ specification_version: 4
|
|
252
254
|
summary: Library for pub-sub (Message Bus)
|
253
255
|
test_files:
|
254
256
|
- spec/banter/cli_spec.rb
|
257
|
+
- spec/banter/configuration_spec.rb
|
258
|
+
- spec/banter/message_spec.rb
|
259
|
+
- spec/banter/rabbit_logger_spec.rb
|
255
260
|
- spec/banter/server/client_queue_listener_spec.rb
|
256
|
-
- spec/banter/server/client_worker_spec.rb
|
257
261
|
- spec/banter/server/rabbitmq_subscriber_spec.rb
|
262
|
+
- spec/banter/subscriber_spec.rb
|
258
263
|
- spec/config.yml
|
259
|
-
- spec/logger_spec.rb
|
260
|
-
- spec/message_spec.rb
|
261
264
|
- spec/spec_helper.rb
|
data/config/pubsub.yml
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
development:
|
2
|
-
# Documentation for parameters for rabbit and bunny is located here: http://rubybunny.info/articles/connecting.html
|
3
|
-
connection:
|
4
|
-
host: localhost
|
5
|
-
port: 5672
|
6
|
-
# username: rabbit
|
7
|
-
# password: rabbit
|
8
|
-
heartbeat: 60 # in seconds
|
9
|
-
log_level: 0
|
10
|
-
log_file: rabbit.log
|
11
|
-
network_recovery_interval: 10 # in seconds
|
12
|
-
continuation_timeout: 4000 # in milliseconds
|
13
|
-
|
14
|
-
logger:
|
15
|
-
enabled: true
|
16
|
-
level: warn
|
17
|
-
file: pubsub.log
|
data/lib/banter/logger.rb
DELETED
@@ -1,49 +0,0 @@
|
|
1
|
-
# Internal log class that is used to log messages before sending, after receiving, and failure to send
|
2
|
-
module Banter
|
3
|
-
class Logger
|
4
|
-
def initialize(enable_publish_logging = true)
|
5
|
-
@enabled = Banter::Configuration.configuration[:logger][:enabled]
|
6
|
-
@enabled = enable_publish_logging if @enabled.nil?
|
7
|
-
end
|
8
|
-
|
9
|
-
def log_publish(routing_key, message)
|
10
|
-
return unless @enabled
|
11
|
-
# generate tags needed
|
12
|
-
tags = ["PUBLISH", message[:ts], message[:pub], message[:v], routing_key]
|
13
|
-
|
14
|
-
# FIX!!! -thl
|
15
|
-
# Could logging like this be too slow?
|
16
|
-
# Or should it be threaded?
|
17
|
-
# We'll need to benchmark, as we don't want this to get too slow.
|
18
|
-
logger.tagged(tags) { logger.warn message[:payload].as_json }
|
19
|
-
|
20
|
-
# TODO: -thl
|
21
|
-
# Log it into mongo as well?
|
22
|
-
end
|
23
|
-
|
24
|
-
def failed_publish(routing_key, properties, message)
|
25
|
-
tags = ["FAILED_SEND", message[:ts], message[:pub], message[:v], routing_key]
|
26
|
-
logger.tagged(tags) { logger.warn message[:payload].as_json }
|
27
|
-
end
|
28
|
-
|
29
|
-
def log_receive(routing_key, message)
|
30
|
-
tags = ["RECEIVED", message[:ts], message[:pub], message[:v], routing_key, Process::pid]
|
31
|
-
logger.tagged(tags) { logger.warn message[:payload].as_json }
|
32
|
-
end
|
33
|
-
|
34
|
-
def log_service(service_name, log_level, message)
|
35
|
-
tags = ["SERVICE", service_name, Process::pid]
|
36
|
-
log_method = log_level.to_sym.to_proc
|
37
|
-
logger.tagged(tags) { log_method.call(logger) { message.as_json } }
|
38
|
-
end
|
39
|
-
|
40
|
-
def teardown
|
41
|
-
logger.close
|
42
|
-
end
|
43
|
-
|
44
|
-
private
|
45
|
-
def logger
|
46
|
-
@logger ||= ActiveSupport::TaggedLogging.new(Banter.logger)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
data/lib/banter/logging.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
require 'logger'
|
2
|
-
|
3
|
-
# Manages a logger that can be used throughout the pubsub gem
|
4
|
-
# The logger can be set to any object that quacks like a logger including the
|
5
|
-
# Rails logger if so desired
|
6
|
-
#
|
7
|
-
# The logger can be set in the initializer of a program or anywhere throughout as
|
8
|
-
# Banter.logger = Rails.logger for example
|
9
|
-
|
10
|
-
module Banter
|
11
|
-
module Logging
|
12
|
-
# Sets the logger
|
13
|
-
#
|
14
|
-
# @param logger The logger to use throughout the pubsub gem
|
15
|
-
# @return The logger we use throughout the gem
|
16
|
-
def self.logger=(logger)
|
17
|
-
raise StandardError("Can't set logger to nil") unless logger.present?
|
18
|
-
@logger = logger
|
19
|
-
end
|
20
|
-
|
21
|
-
# Gets the logger
|
22
|
-
# If no logger is defined when this method is called it will return a standard
|
23
|
-
# ruby logger
|
24
|
-
#
|
25
|
-
# @return The logger we use throughout the gem
|
26
|
-
def self.logger
|
27
|
-
config = Banter::Configuration.configuration[:logger]
|
28
|
-
@logger ||= create_logger( {}.
|
29
|
-
merge( config[:level].present? ? { log_level: ::Logger::Severity.const_get(config[:level].upcase) } : {} ).
|
30
|
-
merge( config[:file].present? ? { log_target: config[:file] } : {} ) )
|
31
|
-
end
|
32
|
-
|
33
|
-
# Builds a standard ruby Logger
|
34
|
-
#
|
35
|
-
# @return Returns the logger at the end of the method
|
36
|
-
def self.create_logger( options = {} )
|
37
|
-
@logger = ::Logger.new(options.fetch(:log_target){ STDOUT })
|
38
|
-
@logger.level = options.fetch(:log_level){ ::Logger::INFO }
|
39
|
-
@logger
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
data/spec/logger_spec.rb
DELETED
@@ -1,110 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Banter::Logger do
|
4
|
-
let(:routing_key) { "test/logger" }
|
5
|
-
let(:subject) { Banter::Logger.new }
|
6
|
-
let(:payload) { {"hit"=>"me"} }
|
7
|
-
let(:message) { Banter::Message.new.serialize(context, routing_key, payload) }
|
8
|
-
let(:config_buffer) { StringIO.new }
|
9
|
-
let(:output_string) { config_buffer.string }
|
10
|
-
let(:config_override) { {} }
|
11
|
-
let(:context) { {unique_id: "1234", orig_ip_address: "127.0.0.1"}}
|
12
|
-
|
13
|
-
before do
|
14
|
-
Banter::Logging.instance_variable_set(:"@logger", nil)
|
15
|
-
directory = File::dirname(__FILE__)
|
16
|
-
full_name = File.join(directory, "config.yml")
|
17
|
-
@config_data = HashWithIndifferentAccess.new( YAML.load_file(full_name)[ENV["RAILS_ENV"]] )
|
18
|
-
@config_data.merge!(config_override)
|
19
|
-
@config_data[:logger][:file] = config_buffer
|
20
|
-
allow(Banter::Configuration).to receive(:configuration).at_least(1).and_return(@config_data)
|
21
|
-
end
|
22
|
-
|
23
|
-
describe "#log_publish" do
|
24
|
-
let(:result) { subject.log_publish(routing_key, message)}
|
25
|
-
|
26
|
-
|
27
|
-
it "should not fail" do
|
28
|
-
expect{ result }.not_to raise_error()
|
29
|
-
end
|
30
|
-
|
31
|
-
it "should write a row to the log" do
|
32
|
-
result
|
33
|
-
expect(output_string.length).not_to eq(0)
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
describe "#failed_publish" do
|
39
|
-
let(:result) { subject.failed_publish(routing_key, {}, message)}
|
40
|
-
|
41
|
-
context "warning log level" do
|
42
|
-
|
43
|
-
it "should not fail" do
|
44
|
-
expect{ result }.not_to raise_error()
|
45
|
-
end
|
46
|
-
|
47
|
-
it "should respect the log level of the file" do
|
48
|
-
result
|
49
|
-
expect(output_string.length).not_to eq(0)
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
context "fatal log level" do
|
54
|
-
let(:config_override) { { 'logger'=> { 'level'=>'fatal' } } }
|
55
|
-
|
56
|
-
it "should not fail" do
|
57
|
-
expect{ result }.not_to raise_error()
|
58
|
-
end
|
59
|
-
|
60
|
-
it "should respect the log level of the file" do
|
61
|
-
result
|
62
|
-
expect(output_string.length).to eq(0)
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
describe "#log_receive" do
|
68
|
-
let(:result) { subject.log_receive(routing_key, message)}
|
69
|
-
|
70
|
-
it "should not fail" do
|
71
|
-
expect{ result }.not_to raise_error()
|
72
|
-
end
|
73
|
-
|
74
|
-
it "should respect the log level of the file" do
|
75
|
-
result
|
76
|
-
expect(output_string.length).not_to eq(0)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
describe "#log_service" do
|
81
|
-
let(:service_name) { "test" }
|
82
|
-
let(:result) { subject.log_service(service_name, log_level, message)}
|
83
|
-
|
84
|
-
context "debugger log" do
|
85
|
-
let(:log_level) { :debug }
|
86
|
-
it "should not fail" do
|
87
|
-
expect{ result }.not_to raise_error()
|
88
|
-
end
|
89
|
-
|
90
|
-
it "should respect the log level of the file" do
|
91
|
-
result
|
92
|
-
expect(output_string.length).to eq(0)
|
93
|
-
end
|
94
|
-
end
|
95
|
-
|
96
|
-
context "warn log" do
|
97
|
-
let(:log_level) { :warn }
|
98
|
-
it "should not fail" do
|
99
|
-
expect{ result }.not_to raise_error()
|
100
|
-
end
|
101
|
-
|
102
|
-
it "should respect the log level of the file" do
|
103
|
-
result
|
104
|
-
expect(output_string.length).not_to eq(0)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
end
|
109
|
-
|
110
|
-
end
|