philotic 0.2.4 → 0.3.0

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