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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c2c2033f430505bcb3c7b1fa84a2ec3f7da6a04a
4
- data.tar.gz: 7feb51b107de61559c90540f4dea73fc104a5fb2
3
+ metadata.gz: 9d0f8fa6fb6efcc9befadeaac184560b989606f3
4
+ data.tar.gz: 55445f64eb387bacb905718ba61284d272d72db7
5
5
  SHA512:
6
- metadata.gz: d611262dcb9921b58016ed4768547789c05736b5fd559d64b83f9d411c09c2099bf1d5e62b3eb4c6608d1af595ce7d354717c8555b9458c1b28274314664425c
7
- data.tar.gz: 984f2b86a71ade2646d013d2dce99922c6beaaadd14f4e70eb8804904c7314a2ca753c23c1e23c2406e42a6032c3e465cd176199ee405f76bbb1c0d89b1c4a90
6
+ metadata.gz: 820d17a44fdb4b450f0d982c689ccc16883d589208c990db1b9e7279109876e55585c11404dc5dccf1839e823fe513ef59575c37d010784ec6f3f529e2195b6a
7
+ data.tar.gz: 5e74cca350d83ac11c6a8e32ca4fb771d931593616839b5086f4f25118a48d5e3a6f663dd7b3aea6833a7c3910b029687bca1c75afe8eb6850a9da57f7f1a209
@@ -0,0 +1,5 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - 2.1.0
data/README.md CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  Simple Publishers and subscribers for Ruby using RabbitMQ
4
4
 
5
- [![Gem Version](https://badge.fury.io/rb/banter.svg)](http://badge.fury.io/rb/banter)
5
+ [![Build Status](https://travis-ci.org/honest/banter.svg?branch=master)](https://travis-ci.org/honest/banter)
6
+ ![Gem Version](https://badge.fury.io/rb/banter.svg?foo=bar)
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" # The message prefix that you're subscribing to
65
- # subscribe_to "user_created", on: 'welcome_emails_queue' # If you want to specify the queue name
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
@@ -1 +1,7 @@
1
1
  require "bundler/gem_tasks"
2
+
3
+ begin
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ task :default => :spec
7
+ end
@@ -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/logger"
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::Logging.logger
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 used by Banter
40
+ # @param [Logger] logger Logger for publish, message received and error events
44
41
  def self.logger=(logger)
45
- Banter::Logging.logger = logger
42
+ Banter::Configuration.logger = ActiveSupport::TaggedLogging.new(logger)
46
43
  end
47
44
  end
@@ -71,6 +71,7 @@ module Banter
71
71
 
72
72
  if File.directory?(require_path)
73
73
  require 'rails'
74
+ require 'banter/railtie'
74
75
  require File.expand_path("#{require_path}/config/environment.rb")
75
76
  ::Rails.application.eager_load!
76
77
  else
@@ -1,9 +1,41 @@
1
1
  module Banter
2
- class Configuration
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/pubsub.yml" : yaml_file
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", '')
@@ -12,14 +12,9 @@ module Banter
12
12
  @@publisher
13
13
  end
14
14
 
15
- def initialize(exchange="honest")
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
- if !@config[:enabled].nil? && @config[:enabled] == false
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.configuration[:connection])
33
+ @connection = Bunny.new(Configuration.connection)
39
34
  @connection.start
40
35
 
41
- @channel = @connection.create_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
- @logger.failed_publish(return_info[:routing_key], properties, content)
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 = ::Banter::Message.new.serialize(context, key, payload)
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
- @logger.failed_publish(routing_key, {}, envelope)
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
- @logger.log_publish(routing_key, envelope)
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
- @logger.failed_publish(routing_key, {}, envelope)
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
@@ -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 = "honest")
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="honest")
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.configuration[:connection])
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.configuration[:dead_letter] if Configuration.configuration[:dead_letter].present?
50
- queue_arguments["x-message-ttl"] = Configuration.default_queue_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
- @logger.log_receive(delivery_info[:routing_key], message)
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::Logger.new.log_service("all_services", :warn, "Starting shutdown of all services")
41
+ ::Banter::RabbitLogger.log_service("all_services", "Starting shutdown of all services")
42
42
 
43
43
  @workers.each do |worker|
44
- ::Banter::Logger.new.log_service("all_services", :warn, "Tearing down worker: #{worker.worker_class.name}")
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::Logger.new.log_service("all_services", :warn, "#{worker.worker_class.name} - did not tear down correctly. Error - #{e.message}")
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
@@ -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 Allowed option is :on to optionally specify a queue. If not provided, queue name is generated from the routing key
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(context, payload)
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.
@@ -1,3 +1,3 @@
1
1
  module Banter
2
- VERSION = "0.4.1"
2
+ VERSION = "0.5.0"
3
3
  end
@@ -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
@@ -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({}, payload) }
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
@@ -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.join(Banter.root,"spec/config.yml") )
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.1
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-01 00:00:00.000000000 Z
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
@@ -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
@@ -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
@@ -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
@@ -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