philotic 0.2.4 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -7
- data/.travis.yml +2 -0
- data/README.md +8 -6
- data/examples/creating_named_queues/manually.rb +9 -6
- data/examples/creating_named_queues/with_rake.rb +2 -2
- data/examples/publishing/publish.rb +4 -2
- data/examples/simple_combined_example.rb +8 -6
- data/examples/subscribing/acks.rb +10 -7
- data/examples/subscribing/anonymous_queue.rb +5 -3
- data/examples/subscribing/multiple_named_queues.rb +6 -4
- data/examples/subscribing/named_queue.rb +3 -2
- data/lib/philotic.rb +4 -85
- data/lib/philotic/config.rb +27 -14
- data/lib/philotic/connection.rb +79 -8
- data/lib/philotic/logging/logger.rb +3 -1
- data/lib/philotic/publisher.rb +31 -9
- data/lib/philotic/routable.rb +0 -8
- data/lib/philotic/subscriber.rb +23 -13
- data/lib/philotic/tasks/init_queues.rb +8 -5
- data/lib/philotic/version.rb +1 -1
- data/spec/philotic/config_spec.rb +24 -21
- data/spec/philotic/connection_spec.rb +95 -13
- data/spec/philotic/logging/logger_spec.rb +13 -7
- data/spec/philotic/publisher_spec.rb +9 -14
- data/spec/philotic/routable_spec.rb +3 -8
- data/spec/philotic/subscriber_spec.rb +27 -20
- data/spec/philotic_spec.rb +4 -79
- data/spec/spec_helper.rb +2 -1
- metadata +180 -126
- data/examples/README.md +0 -13
- data/examples/creating_named_queues/philotic_named_queues.yml +0 -6
@@ -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.
|
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
|
data/lib/philotic/publisher.rb
CHANGED
@@ -1,11 +1,21 @@
|
|
1
1
|
require 'philotic/connection'
|
2
2
|
|
3
3
|
module Philotic
|
4
|
-
|
5
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
24
|
-
unless
|
25
|
-
|
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
|
-
|
33
|
-
|
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
|
data/lib/philotic/routable.rb
CHANGED
@@ -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)
|
data/lib/philotic/subscriber.rb
CHANGED
@@ -8,7 +8,17 @@ module Philotic
|
|
8
8
|
end
|
9
9
|
end
|
10
10
|
|
11
|
-
|
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
|
26
|
-
|
27
|
-
@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 =
|
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
|
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
|
67
|
-
|
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
|
71
|
-
|
80
|
+
def reject(message, requeue=true)
|
81
|
+
connection.channel.reject(message[:delivery_info].delivery_tag, requeue)
|
72
82
|
end
|
73
83
|
|
74
|
-
def
|
84
|
+
def subscribe_to_any(options = {})
|
75
85
|
if block_given?
|
76
|
-
|
86
|
+
subscribe(options.merge(:'x-match' => :any), &Proc.new)
|
77
87
|
end
|
78
88
|
end
|
79
89
|
|
80
|
-
def
|
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
|
-
|
16
|
+
philotic.connect!
|
14
17
|
queues.each_pair do |queue_name, queue_options|
|
15
|
-
|
18
|
+
philotic.initialize_named_queue!(queue_name, queue_options)
|
16
19
|
end
|
17
20
|
end
|
18
21
|
end
|
data/lib/philotic/version.rb
CHANGED
@@ -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 '
|
7
|
+
describe '#defaults' do
|
6
8
|
end
|
7
9
|
|
8
|
-
describe '
|
10
|
+
describe '#load' do
|
9
11
|
end
|
10
12
|
|
11
|
-
describe '
|
13
|
+
describe '#load_file' do
|
12
14
|
end
|
13
15
|
|
14
|
-
describe '
|
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
|
-
|
20
|
+
config.rabbit_url = url
|
18
21
|
end
|
19
|
-
subject { lambda {
|
22
|
+
subject { lambda { config.parse_rabbit_uri } }
|
20
23
|
|
21
24
|
it do
|
22
25
|
should change {
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
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 '
|
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(
|
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 '
|
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(
|
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
|
-
|
51
|
+
subject.start_connection!
|
53
52
|
end
|
54
53
|
end
|
55
54
|
|
56
|
-
describe '
|
55
|
+
describe '#close' do
|
57
56
|
let(:connection) { double }
|
57
|
+
subject { Philotic::Connection.new }
|
58
58
|
specify do
|
59
|
-
allow(
|
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(
|
63
|
-
expect(
|
64
|
-
|
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
|
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(
|
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
|
-
|
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(
|
34
|
+
expect(logger.connection).to receive(:publish) do |event|
|
28
35
|
raise error_message
|
29
36
|
end
|
30
|
-
|
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
|