banter 0.4.1 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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