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.
- 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
|