philotic 0.2.4 → 0.3.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.
@@ -6,6 +6,7 @@ module Philotic
6
6
  class Logger < ::Logger
7
7
 
8
8
  attr_writer :event_class
9
+ attr_accessor :connection
9
10
 
10
11
  def event_class
11
12
  @event_class ||= Philotic::Logging::Event
@@ -27,7 +28,8 @@ module Philotic
27
28
  end
28
29
  @logdev.write(format_message(format_severity(severity), Time.now, progname, message))
29
30
  begin
30
- event_class.publish(severity, message, progname)
31
+ event = event_class.new(severity, message, progname)
32
+ connection.publish event if connection
31
33
  rescue => e
32
34
  @logdev.write(format_message(format_severity(Logger::ERROR), Time.now, progname, e.message))
33
35
  end
@@ -1,11 +1,21 @@
1
1
  require 'philotic/connection'
2
2
 
3
3
  module Philotic
4
- module Publisher
5
- extend self
4
+ class Publisher
5
+
6
+ attr_accessor :connection
7
+ attr_accessor :log_event_handler
8
+
9
+ def initialize(connection)
10
+ @connection = connection
11
+ end
12
+
13
+ def logger
14
+ connection.logger
15
+ end
6
16
 
7
17
  def config
8
- Philotic::Config
18
+ connection.config
9
19
  end
10
20
 
11
21
  def publish(event)
@@ -17,20 +27,20 @@ module Philotic
17
27
  private
18
28
  def _publish(payload, message_metadata = {})
19
29
  if config.disable_publish
20
- Philotic.log_event_published(:warn, message_metadata, payload, 'attempted to publish a message when publishing is disabled.')
30
+ log_event_published(:warn, message_metadata, payload, 'attempted to publish a message when publishing is disabled.')
21
31
  return false
22
32
  end
23
- Philotic.connect!
24
- unless Philotic::Connection.connected?
25
- Philotic.log_event_published(:error, message_metadata, payload, 'unable to publish event, not connected to RabbitMQ')
33
+ connection.connect!
34
+ unless connection.connected?
35
+ log_event_published(:error, message_metadata, payload, 'unable to publish event, not connected to RabbitMQ')
26
36
  return
27
37
  end
28
38
  message_metadata = merge_metadata(message_metadata)
29
39
 
30
40
  payload = normalize_payload_times(payload)
31
41
 
32
- Philotic::Connection.exchange.publish(payload.to_json, message_metadata)
33
- Philotic.log_event_published(:debug, message_metadata, payload, 'published event')
42
+ connection.exchange.publish(payload.to_json, message_metadata)
43
+ log_event_published(:debug, message_metadata, payload, 'published event')
34
44
  end
35
45
 
36
46
  def normalize_payload_times(payload)
@@ -53,5 +63,17 @@ module Philotic
53
63
  message_metadata[:headers] = {philotic_firehose: true}.merge(message_metadata[:headers])
54
64
  message_metadata
55
65
  end
66
+
67
+ def on_publish_event(&block)
68
+ @log_event_handler = block
69
+ end
70
+
71
+ def log_event_published(severity, metadata, payload, message)
72
+ if @log_event_handler
73
+ @log_event_handler.call(severity, metadata, payload, message)
74
+ else
75
+ logger.send(severity, "#{message}; message_metadata:#{metadata}, payload:#{payload.to_json}")
76
+ end
77
+ end
56
78
  end
57
79
  end
@@ -61,10 +61,6 @@ module Philotic
61
61
  attr_routable_writers.concat(names)
62
62
  attr_accessor(*names)
63
63
  end
64
-
65
- def publish(*args)
66
- self.new(*args).publish
67
- end
68
64
  end
69
65
 
70
66
  def payload
@@ -88,10 +84,6 @@ module Philotic
88
84
  @message_metadata.merge! options
89
85
  end
90
86
 
91
- def publish
92
- Philotic::Publisher.publish self
93
- end
94
-
95
87
  private
96
88
 
97
89
  def _payload_or_headers(payload_or_headers)
@@ -8,7 +8,17 @@ module Philotic
8
8
  end
9
9
  end
10
10
 
11
- def self.subscription_callback
11
+ attr_accessor :connection
12
+
13
+ def initialize(connection)
14
+ @connection = connection
15
+ end
16
+
17
+ def logger
18
+ connection.logger
19
+ end
20
+
21
+ def subscription_callback
12
22
  lambda do |delivery_info, metadata, payload|
13
23
  hash_payload = JSON.parse payload
14
24
 
@@ -22,13 +32,13 @@ module Philotic
22
32
  end
23
33
  end
24
34
 
25
- def self.subscribe(subscription = {}, subscribe_options = Philotic::DEFAULT_SUBSCRIBE_OPTIONS, &block)
26
- Philotic.connect!
27
- @exchange = Philotic::Connection.exchange
35
+ def subscribe(subscription = {}, subscribe_options = Philotic::DEFAULT_SUBSCRIBE_OPTIONS, &block)
36
+ connection.connect!
37
+ @exchange = connection.exchange
28
38
 
29
39
  subscription_settings = get_subscription_settings subscription, subscribe_options
30
40
 
31
- q = Philotic::Connection.channel.queue(subscription_settings[:queue_name], subscription_settings[:queue_options])
41
+ q = connection.channel.queue(subscription_settings[:queue_name], subscription_settings[:queue_options])
32
42
 
33
43
  q.bind(@exchange, arguments: subscription_settings[:arguments]) if subscription_settings[:arguments]
34
44
 
@@ -36,7 +46,7 @@ module Philotic
36
46
 
37
47
  end
38
48
 
39
- def self.get_subscription_settings(subscription, subscribe_options)
49
+ def get_subscription_settings(subscription, subscribe_options)
40
50
 
41
51
  if subscription.is_a? String
42
52
  queue_name = subscription
@@ -63,21 +73,21 @@ module Philotic
63
73
  }
64
74
  end
65
75
 
66
- def self.acknowledge(message, up_to_and_including=false)
67
- Philotic::Connection.channel.acknowledge(message[:delivery_info].delivery_tag, up_to_and_including)
76
+ def acknowledge(message, up_to_and_including=false)
77
+ connection.channel.acknowledge(message[:delivery_info].delivery_tag, up_to_and_including)
68
78
  end
69
79
 
70
- def self.reject(message, requeue=true)
71
- Philotic::Connection.channel.reject(message[:delivery_info].delivery_tag, requeue)
80
+ def reject(message, requeue=true)
81
+ connection.channel.reject(message[:delivery_info].delivery_tag, requeue)
72
82
  end
73
83
 
74
- def self.subscribe_to_any(options = {})
84
+ def subscribe_to_any(options = {})
75
85
  if block_given?
76
- self.subscribe(options.merge(:'x-match' => :any), &Proc.new)
86
+ subscribe(options.merge(:'x-match' => :any), &Proc.new)
77
87
  end
78
88
  end
79
89
 
80
- def self.endure
90
+ def endure
81
91
  while true
82
92
  Thread.pass
83
93
  end
@@ -3,16 +3,19 @@ namespace :philotic do
3
3
  task :init_queues, :filename do |t, args|
4
4
  raise "You must specify a file name for #{t.name}: rake #{t.name}[FILENAME] #yes, you need the brackets, no space." if !args[:filename]
5
5
 
6
- # ENV['PHILOTIC_INITIALIZE_NAMED_QUEUE'] must equal 'true' to run Philotic.initialize_named_queue!
7
- ENV['PHILOTIC_INITIALIZE_NAMED_QUEUE'] = 'true'
8
-
9
6
  require 'philotic'
10
7
 
8
+ philotic = Philotic::Connection.new
9
+
10
+ # philotic.config.initialize_named_queues must be truthy to run Philotic.initialize_named_queue!
11
+ philotic.config.initialize_named_queues = true
12
+
13
+
11
14
  @filename = args[:filename]
12
15
  queues = YAML.load_file(@filename)
13
- Philotic.connect!
16
+ philotic.connect!
14
17
  queues.each_pair do |queue_name, queue_options|
15
- Philotic.initialize_named_queue!(queue_name, queue_options)
18
+ philotic.initialize_named_queue!(queue_name, queue_options)
16
19
  end
17
20
  end
18
21
  end
@@ -1,3 +1,3 @@
1
1
  module Philotic
2
- VERSION = '0.2.4'
2
+ VERSION = '0.3.0'
3
3
  end
@@ -1,40 +1,43 @@
1
1
  require 'spec_helper'
2
+ require 'philotic/config'
3
+ require 'philotic/connection'
2
4
 
3
5
  describe Philotic::Config do
4
6
 
5
- describe '.defaults' do
7
+ describe '#defaults' do
6
8
  end
7
9
 
8
- describe '.load' do
10
+ describe '#load' do
9
11
  end
10
12
 
11
- describe '.load_file' do
13
+ describe '#load_file' do
12
14
  end
13
15
 
14
- describe '.parse_rabbit_uri' do
16
+ describe '#parse_rabbit_uri' do
15
17
  let(:url) { 'amqp://user:pass@host:12345/vhost' }
18
+ let(:config) { Philotic::Connection.new.config }
16
19
  before do
17
- Philotic::Config.rabbit_url = url
20
+ config.rabbit_url = url
18
21
  end
19
- subject { lambda { Philotic::Config.parse_rabbit_uri } }
22
+ subject { lambda { config.parse_rabbit_uri } }
20
23
 
21
24
  it do
22
25
  should change {
23
- [
24
- Philotic::Config.rabbit_user,
25
- Philotic::Config.rabbit_password,
26
- Philotic::Config.rabbit_host,
27
- Philotic::Config.rabbit_port,
28
- Philotic::Config.rabbit_vhost,
29
- ]
30
- }
31
- .to [
32
- 'user',
33
- 'pass',
34
- 'host',
35
- 12345,
36
- 'vhost',
37
- ]
26
+ [
27
+ config.rabbit_user,
28
+ config.rabbit_password,
29
+ config.rabbit_host,
30
+ config.rabbit_port,
31
+ config.rabbit_vhost,
32
+ ]
33
+ }
34
+ .to [
35
+ 'user',
36
+ 'pass',
37
+ 'host',
38
+ 12345,
39
+ 'vhost',
40
+ ]
38
41
  end
39
42
  end
40
43
  end
@@ -2,11 +2,9 @@ require 'spec_helper'
2
2
 
3
3
  describe Philotic::Connection do
4
4
 
5
- describe '.config' do
6
- its(:config) { should eq Philotic::Config }
7
- end
8
5
 
9
- describe '.connect!' do
6
+ describe '#connect!' do
7
+ subject { Philotic::Connection.new }
10
8
  context 'not connected' do
11
9
  context 'success' do
12
10
  specify do
@@ -23,7 +21,7 @@ describe Philotic::Connection do
23
21
  expect(subject).to receive(:connected?).and_return(false, false)
24
22
  expect(subject).to receive(:start_connection!)
25
23
  expect(subject).not_to receive(:set_exchange_return_handler!)
26
- expect(Philotic.logger).to receive(:error)
24
+ expect(subject.logger).to receive(:error)
27
25
 
28
26
  subject.connect!
29
27
  end
@@ -43,25 +41,109 @@ describe Philotic::Connection do
43
41
  end
44
42
  end
45
43
 
46
- describe '.start_connection!' do
44
+ describe '#start_connection!' do
47
45
  let(:connection) { double }
46
+ subject { Philotic::Connection.new }
48
47
  specify do
49
- expect(Bunny).to receive(:new).with(Philotic::Config.rabbit_url, Philotic::Connection.connection_settings).and_return(connection)
48
+ expect(Bunny).to receive(:new).with(subject.config.rabbit_url, subject.connection_settings).and_return(connection)
50
49
  expect(connection).to receive(:start)
51
50
 
52
- Philotic::Connection.start_connection!
51
+ subject.start_connection!
53
52
  end
54
53
  end
55
54
 
56
- describe '.close' do
55
+ describe '#close' do
57
56
  let(:connection) { double }
57
+ subject { Philotic::Connection.new }
58
58
  specify do
59
- allow(Philotic::Connection).to receive(:connection).and_return(connection)
59
+ allow(subject).to receive(:connection).and_return(connection)
60
60
  expect(connection).to receive(:connected?).and_return(true)
61
61
  expect(connection).to receive(:close)
62
- expect(Philotic::Connection.instance_variable_get(:@channel)).to eq(nil)
63
- expect(Philotic::Connection.instance_variable_get(:@exchange)).to eq(nil)
64
- Philotic::Connection.close
62
+ expect(subject.instance_variable_get(:@channel)).to eq(nil)
63
+ expect(subject.instance_variable_get(:@exchange)).to eq(nil)
64
+ subject.close
65
+ end
66
+ end
67
+
68
+ describe '#initialize_named_queue!' do
69
+ let(:test_queues) do
70
+ {
71
+ app_live_feed: {
72
+ exchange: 'philotic.headers.test_app.feed.live',
73
+ options: {
74
+ arguments: {
75
+ :'x-dead-letter-exchange' => 'philotic.headers.test_app.feed.delayed',
76
+ :'x-message-ttl' => 600000 # ms
77
+ }},
78
+ bindings:
79
+ [
80
+ {
81
+ philotic_product: 'test_app',
82
+ philotic_component: 'app_component',
83
+ :'x-match:' => 'all'
84
+ },
85
+ ],
86
+ }
87
+ }
88
+ end
89
+ subject { Philotic::Connection.new }
90
+
91
+ it 'should throw an error when Philotic::Config.initialize_named_queues is falsey' do
92
+ allow(subject.config).to receive(:initialize_named_queues).and_return(nil)
93
+ queue_name = test_queues.keys.first
94
+ config = test_queues[queue_name]
95
+ expect(subject).not_to receive(:connect!)
96
+ expect { subject.initialize_named_queue! queue_name, config }.to raise_error
97
+
98
+ end
99
+
100
+ it 'should log a warning when Philotic::Config.delete_existing_queues is falsey and the queue already exists' do
101
+ allow(subject.config).to receive(:initialize_named_queues).and_return(true)
102
+ allow(subject.config).to receive(:delete_existing_queues).and_return(nil)
103
+
104
+ test_queues.each_pair do |queue_name, config|
105
+
106
+ connection = double
107
+
108
+ expect(subject).to receive(:connect!)
109
+ expect(subject).to receive(:connection).and_return(connection)
110
+ expect(connection).to receive(:queue_exists?).and_return(true)
111
+
112
+ expect(subject.logger).to receive(:warn)
113
+
114
+ subject.initialize_named_queue! queue_name, config
115
+ end
116
+ end
117
+
118
+ it 'should delete the queue first when Philotic::Config.delete_existing_queues is truthy and the queue already exists' do
119
+ allow(subject.config).to receive(:initialize_named_queues).and_return(true)
120
+ allow(subject.config).to receive(:delete_existing_queues).and_return(true)
121
+
122
+ test_queues.each_pair do |queue_name, config|
123
+
124
+ queue_options = Philotic::DEFAULT_NAMED_QUEUE_OPTIONS.dup
125
+ queue_options.merge!(config[:options] || {})
126
+
127
+ channel = double
128
+ queue = double
129
+ exchange = double
130
+ connection = double
131
+
132
+ expect(subject).to receive(:connect!)
133
+ expect(subject).to receive(:connection).and_return(connection)
134
+ expect(connection).to receive(:queue_exists?).and_return(true)
135
+ expect(subject).to receive(:channel).and_return(channel).exactly(3).times
136
+ expect(channel).to receive(:queue).with(queue_name, {passive: true}).and_return(queue)
137
+ expect(queue).to receive(:delete)
138
+ expect(channel).to receive(:queue).with(queue_name, queue_options).and_return(queue)
139
+ expect(channel).to receive(:headers).with(config[:exchange], durable: true) { exchange }
140
+ expect(queue).to receive(:name).and_return(queue_name).exactly(2).times
141
+
142
+ config[:bindings].each do |arguments|
143
+ expect(queue).to receive(:bind).with(exchange, {arguments: arguments})
144
+ end
145
+ subject.initialize_named_queue! queue_name, config
146
+ end
65
147
  end
66
148
  end
67
149
  end
@@ -3,19 +3,26 @@ require 'spec_helper'
3
3
  module Philotic
4
4
  module Logging
5
5
  describe Logger do
6
- let (:device) { double }
6
+ let(:device) do
7
+ fd = IO.sysopen('/dev/null', 'w')
8
+ IO.new(fd, 'w')
9
+
10
+ end
7
11
  let(:logger) { Philotic::Logging::Logger.new(device) }
8
12
  let(:message) { 'Hey!' }
9
13
  let(:error_message) { "These are not the droids you're looking for" }
14
+
15
+ before do
16
+ logger.connection = Philotic::Connection.new
17
+ end
10
18
  specify do
11
19
 
12
- expect(Philotic::Publisher).to receive(:publish) do |event|
20
+ expect(logger.connection).to receive(:publish) do |event|
13
21
  expect(event.message).to eq message
14
22
  expect(event.severity).to eq Logger::INFO
15
23
 
16
24
  end
17
- expect(device).to receive(:respond_to?).with(:write).and_return(true)
18
- expect(device).to receive(:respond_to?).with(:close).and_return(true)
25
+
19
26
  expect(device).to receive(:write) do |log_message|
20
27
  expect(log_message).to match /#{message}/
21
28
  end
@@ -24,11 +31,10 @@ module Philotic
24
31
  end
25
32
 
26
33
  it "should not die if it can't log to RabbitMQ" do
27
- expect(Philotic::Publisher).to receive(:publish) do |event|
34
+ expect(logger.connection).to receive(:publish) do |event|
28
35
  raise error_message
29
36
  end
30
- expect(device).to receive(:respond_to?).with(:write).and_return(true)
31
- expect(device).to receive(:respond_to?).with(:close).and_return(true)
37
+
32
38
  expect(device).to receive(:write) do |log_message|
33
39
  expect(log_message).to match /#{message}/
34
40
  end