onstomp 1.0.0pre1 → 1.0.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.
- data/README.md +1 -1
- data/Rakefile +8 -0
- data/examples/openuri.rb +36 -0
- data/lib/onstomp.rb +4 -0
- data/lib/onstomp/client.rb +6 -5
- data/lib/onstomp/components.rb +0 -1
- data/lib/onstomp/components/frame_headers.rb +35 -38
- data/lib/onstomp/components/threaded_processor.rb +13 -0
- data/lib/onstomp/connections/base.rb +15 -8
- data/lib/onstomp/connections/stomp_1.rb +0 -6
- data/lib/onstomp/connections/stomp_1_0.rb +8 -0
- data/lib/onstomp/connections/stomp_1_1.rb +8 -0
- data/lib/onstomp/failover.rb +16 -0
- data/lib/onstomp/failover/buffers.rb +8 -0
- data/lib/onstomp/failover/buffers/written.rb +91 -0
- data/lib/onstomp/failover/client.rb +127 -0
- data/lib/onstomp/failover/failover_configurable.rb +63 -0
- data/lib/onstomp/failover/failover_events.rb +96 -0
- data/lib/onstomp/failover/new_with_failover.rb +20 -0
- data/lib/onstomp/failover/pools.rb +8 -0
- data/lib/onstomp/failover/pools/base.rb +39 -0
- data/lib/onstomp/failover/pools/round_robin.rb +17 -0
- data/lib/onstomp/failover/uri.rb +34 -0
- data/lib/onstomp/interfaces/client_configurable.rb +2 -6
- data/lib/onstomp/interfaces/client_events.rb +4 -0
- data/lib/onstomp/interfaces/connection_events.rb +3 -3
- data/lib/onstomp/interfaces/event_manager.rb +8 -0
- data/lib/onstomp/interfaces/uri_configurable.rb +7 -7
- data/lib/onstomp/open-uri.rb +37 -0
- data/lib/onstomp/open-uri/client_extensions.rb +88 -0
- data/lib/onstomp/open-uri/message_queue.rb +38 -0
- data/lib/onstomp/version.rb +1 -1
- data/spec/onstomp/client_spec.rb +1 -4
- data/spec/onstomp/components/frame_headers_spec.rb +2 -5
- data/spec/onstomp/connections/stomp_1_0_spec.rb +22 -0
- data/spec/onstomp/connections/stomp_1_1_spec.rb +22 -0
- data/spec/onstomp/connections/stomp_1_spec.rb +2 -19
- data/spec/onstomp/connections_spec.rb +4 -0
- data/spec/onstomp/failover/buffers/written_spec.rb +8 -0
- data/spec/onstomp/failover/client_spec.rb +38 -0
- data/spec/onstomp/failover/failover_events_spec.rb +75 -0
- data/spec/onstomp/failover/new_with_failover_spec.rb +16 -0
- data/spec/onstomp/failover/pools/base_spec.rb +54 -0
- data/spec/onstomp/failover/pools/round_robin_spec.rb +27 -0
- data/spec/onstomp/failover/uri_spec.rb +21 -0
- data/spec/onstomp/full_stacks/failover_spec.rb +55 -0
- data/spec/onstomp/full_stacks/onstomp_spec.rb +15 -0
- data/spec/onstomp/full_stacks/open-uri_spec.rb +40 -0
- data/spec/onstomp/full_stacks/ssl/README +6 -0
- data/spec/onstomp/full_stacks/ssl/broker_cert.csr +17 -0
- data/spec/onstomp/full_stacks/ssl/broker_cert.pem +72 -0
- data/spec/onstomp/full_stacks/ssl/broker_key.pem +27 -0
- data/spec/onstomp/full_stacks/ssl/client_cert.csr +17 -0
- data/spec/onstomp/full_stacks/ssl/client_cert.pem +72 -0
- data/spec/onstomp/full_stacks/ssl/client_key.pem +27 -0
- data/spec/onstomp/full_stacks/ssl/demoCA/cacert.pem +17 -0
- data/spec/onstomp/full_stacks/ssl/demoCA/index.txt +2 -0
- data/spec/onstomp/full_stacks/ssl/demoCA/index.txt.attr +1 -0
- data/spec/onstomp/full_stacks/ssl/demoCA/index.txt.attr.old +1 -0
- data/spec/onstomp/full_stacks/ssl/demoCA/index.txt.old +1 -0
- data/spec/onstomp/full_stacks/ssl/demoCA/newcerts/01.pem +72 -0
- data/spec/onstomp/full_stacks/ssl/demoCA/newcerts/02.pem +72 -0
- data/spec/onstomp/full_stacks/ssl/demoCA/private/cakey.pem +17 -0
- data/spec/onstomp/full_stacks/ssl/demoCA/serial +1 -0
- data/spec/onstomp/full_stacks/ssl/demoCA/serial.old +1 -0
- data/spec/onstomp/full_stacks/test_broker.rb +251 -0
- data/spec/onstomp/interfaces/connection_events_spec.rb +3 -1
- data/spec/onstomp/open-uri/client_extensions_spec.rb +113 -0
- data/spec/onstomp/open-uri/message_queue_spec.rb +29 -0
- data/spec/onstomp/open-uri_spec.rb +43 -0
- data/spec/spec_helper.rb +2 -0
- data/yard_extensions.rb +5 -1
- metadata +82 -8
- data/lib/onstomp/components/nil_processor.rb +0 -20
- data/spec/onstomp/components/nil_processor_spec.rb +0 -32
data/README.md
CHANGED
@@ -62,7 +62,7 @@ See the full {file:docs/LICENSE.md LICENSE} for details.
|
|
62
62
|
There are a few people/groups I'd like to thank for helping me with the
|
63
63
|
creation of this gem.
|
64
64
|
|
65
|
-
* Lionel Cons the good suggestions while I was implementing support for the
|
65
|
+
* Lionel Cons for the good suggestions while I was implementing support for the
|
66
66
|
STOMP 1.1 spec. Check out his Perl client [Net::STOMP::Client](http://search.cpan.org/~lcons/Net-STOMP-Client-0.9.5/lib/Net/STOMP/Client.pm)
|
67
67
|
* Brian McCallister, Johan Sørensen, Guy M. Allard and Thiago Morello for
|
68
68
|
their work on the `stomp` gem which introduced me to the STOMP protocol.
|
data/Rakefile
CHANGED
@@ -4,3 +4,11 @@ Bundler::GemHelper.install_tasks
|
|
4
4
|
require 'yard'
|
5
5
|
require File.expand_path("../yard_extensions", __FILE__)
|
6
6
|
YARD::Rake::YardocTask.new
|
7
|
+
|
8
|
+
require 'rspec/core/rake_task'
|
9
|
+
desc "Run specs"
|
10
|
+
RSpec::Core::RakeTask.new do |t|
|
11
|
+
t.verbose = false
|
12
|
+
end
|
13
|
+
|
14
|
+
task :default => :spec
|
data/examples/openuri.rb
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.unshift(File.expand_path('../../lib', __FILE__))
|
3
|
+
require 'onstomp'
|
4
|
+
require 'onstomp/open-uri'
|
5
|
+
|
6
|
+
open('stomp://localhost/queue/onstomp/openuri') do |c|
|
7
|
+
c.send "hello world!"
|
8
|
+
c.send "a fine day to you"
|
9
|
+
c.send "what rhymes with you?"
|
10
|
+
c.puts "may the rats eat your eyes"
|
11
|
+
c.send "I am now lost to your cause"
|
12
|
+
c.puts "the inquisition is here for a reason"
|
13
|
+
end
|
14
|
+
|
15
|
+
open('stomp://localhost/queue/onstomp/openuri') do |c|
|
16
|
+
c.each do |m|
|
17
|
+
puts "Got a message: #{m.body}"
|
18
|
+
break if m.body == 'what rhymes with you?'
|
19
|
+
end
|
20
|
+
|
21
|
+
c.take(2).each { |m| puts "From take(2): #{m.body}" }
|
22
|
+
|
23
|
+
puts "And finally: #{c.first.body}"
|
24
|
+
end
|
25
|
+
|
26
|
+
puts "Done with open-uri examples!"
|
27
|
+
|
28
|
+
# Example output:
|
29
|
+
#
|
30
|
+
# Got a message: hello world!
|
31
|
+
# Got a message: a fine day to you
|
32
|
+
# Got a message: what rhymes with you?
|
33
|
+
# From take(2): may the rats eat your eyes
|
34
|
+
# From take(2): I am now lost to your cause
|
35
|
+
# And finally: the inquisition is here for a reason
|
36
|
+
# Done with open-uri examples!
|
data/lib/onstomp.rb
CHANGED
@@ -33,6 +33,10 @@ require 'monitor'
|
|
33
33
|
|
34
34
|
# Primary namespace for the +onstomp+ gem
|
35
35
|
module OnStomp
|
36
|
+
# Class to use for creating enumerator objects, which depends upon the
|
37
|
+
# version of Ruby being used.
|
38
|
+
ENUMERATOR_KLASS = (RUBY_VERSION >= '1.9') ? Enumerator : Enumerable::Enumerator
|
39
|
+
|
36
40
|
# A common base class for errors raised by the OnStomp gem
|
37
41
|
# @abstract
|
38
42
|
class OnStompError < StandardError; end
|
data/lib/onstomp/client.rb
CHANGED
@@ -50,7 +50,7 @@ class OnStomp::Client
|
|
50
50
|
# Creates a new client for the specified uri and optional hash of options.
|
51
51
|
# @param [String,URI] uri
|
52
52
|
# @param [{Symbol => Object}] options
|
53
|
-
def initialize
|
53
|
+
def initialize uri, options={}
|
54
54
|
@uri = uri.is_a?(::URI) ? uri : ::URI.parse(uri)
|
55
55
|
@ssl = options.delete(:ssl)
|
56
56
|
configure_configurable options
|
@@ -65,7 +65,7 @@ class OnStomp::Client
|
|
65
65
|
# headers in the CONNECT frame, if specified.
|
66
66
|
# @param [{#to_sym => #to_s}] headers
|
67
67
|
# @return [self]
|
68
|
-
def connect
|
68
|
+
def connect headers={}
|
69
69
|
@connection = OnStomp::Connections.connect self, headers,
|
70
70
|
{ :'accept-version' => @versions.join(','), :host => @host,
|
71
71
|
:'heart-beat' => @heartbeats.join(','), :login => @login,
|
@@ -80,7 +80,8 @@ class OnStomp::Client
|
|
80
80
|
# the broker will get processed barring any IO exceptions.
|
81
81
|
# @param [{#to_sym => #to_s}] headers
|
82
82
|
# @return [OnStomp::Components::Frame] transmitted DISCONNECT frame
|
83
|
-
def disconnect_with_flush
|
83
|
+
def disconnect_with_flush headers={}
|
84
|
+
processor_inst.prepare_to_close
|
84
85
|
disconnect_without_flush(headers).tap do
|
85
86
|
processor_inst.join
|
86
87
|
end
|
@@ -111,11 +112,11 @@ class OnStomp::Client
|
|
111
112
|
# This method should not be invoked directly. Use the frame methods provided
|
112
113
|
# by the {OnStomp::Interfaces:FrameMethod} interface.
|
113
114
|
# @return [OnStomp::Components::Frame]
|
114
|
-
def transmit
|
115
|
+
def transmit frame, cbs={}
|
115
116
|
frame.tap do
|
116
117
|
register_callbacks frame, cbs
|
117
118
|
trigger_before_transmitting frame
|
118
|
-
connection.write_frame_nonblock
|
119
|
+
connection && connection.write_frame_nonblock(frame)
|
119
120
|
end
|
120
121
|
end
|
121
122
|
|
data/lib/onstomp/components.rb
CHANGED
@@ -8,6 +8,5 @@ require 'onstomp/components/uri'
|
|
8
8
|
require 'onstomp/components/frame_headers'
|
9
9
|
require 'onstomp/components/frame'
|
10
10
|
require 'onstomp/components/subscription'
|
11
|
-
require 'onstomp/components/nil_processor'
|
12
11
|
require 'onstomp/components/threaded_processor'
|
13
12
|
require 'onstomp/components/scopes'
|
@@ -14,7 +14,7 @@ class OnStomp::Components::FrameHeaders
|
|
14
14
|
# @see #merge!
|
15
15
|
def initialize(headers={})
|
16
16
|
@values = {}
|
17
|
-
|
17
|
+
initialize_names
|
18
18
|
merge! headers
|
19
19
|
end
|
20
20
|
|
@@ -115,7 +115,7 @@ class OnStomp::Components::FrameHeaders
|
|
115
115
|
def delete(name)
|
116
116
|
name = name.to_sym
|
117
117
|
if @values.key? name
|
118
|
-
|
118
|
+
delete_name name
|
119
119
|
@values.delete name
|
120
120
|
end
|
121
121
|
end
|
@@ -150,7 +150,7 @@ class OnStomp::Components::FrameHeaders
|
|
150
150
|
def []=(name, val)
|
151
151
|
name = name.to_sym
|
152
152
|
val = val.to_s
|
153
|
-
|
153
|
+
add_name name
|
154
154
|
@values[name] = [val]
|
155
155
|
val
|
156
156
|
end
|
@@ -162,51 +162,48 @@ class OnStomp::Components::FrameHeaders
|
|
162
162
|
@values.inject({}) { |h, (k,v)| h[k] = v.first; h }
|
163
163
|
end
|
164
164
|
|
165
|
+
# Iterates over header name / value pairs, yielding them as a pair
|
166
|
+
# of strings to the supplied block.
|
167
|
+
# @yield [header_name, header_value]
|
168
|
+
# @yieldparam [String] header_name
|
169
|
+
# @yieldparam [String] header_value
|
170
|
+
def each &block
|
171
|
+
if block_given?
|
172
|
+
iterate_each &block
|
173
|
+
self
|
174
|
+
else
|
175
|
+
OnStomp::ENUMERATOR_KLASS.new(self)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
165
179
|
if RUBY_VERSION >= "1.9"
|
166
180
|
def names; @values.keys; end
|
167
181
|
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
end
|
182
|
+
private
|
183
|
+
def iterate_each
|
184
|
+
@values.each do |name, vals|
|
185
|
+
name_str = name.to_s
|
186
|
+
vals.each do |val|
|
187
|
+
yield [name_str, val]
|
175
188
|
end
|
176
|
-
self
|
177
|
-
else
|
178
|
-
Enumerator.new(self)
|
179
189
|
end
|
180
190
|
end
|
181
|
-
|
182
|
-
|
183
|
-
def
|
184
|
-
def __delete_name__(name); end
|
185
|
-
def __add_name__(name); end
|
191
|
+
def initialize_names; end
|
192
|
+
def delete_name(name); end
|
193
|
+
def add_name(name); end
|
186
194
|
else
|
187
195
|
attr_reader :names
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
def each(&block)
|
195
|
-
if block_given?
|
196
|
-
@names.each do |name|
|
197
|
-
@values[name].each do |val|
|
198
|
-
yield [name.to_s, val]
|
199
|
-
end
|
196
|
+
|
197
|
+
private
|
198
|
+
def iterate_each
|
199
|
+
@names.each do |name|
|
200
|
+
@values[name].each do |val|
|
201
|
+
yield [name.to_s, val]
|
200
202
|
end
|
201
|
-
self
|
202
|
-
else
|
203
|
-
Enumerable::Enumerator.new(self)
|
204
203
|
end
|
205
204
|
end
|
206
|
-
|
207
|
-
|
208
|
-
def
|
209
|
-
def __delete_name__(name); @names.delete name; end
|
210
|
-
def __add_name__(name); @names << name unless @values.key?(name); end
|
205
|
+
def initialize_names; @names = []; end
|
206
|
+
def delete_name(name); @names.delete name; end
|
207
|
+
def add_name(name); @names << name unless @values.key?(name); end
|
211
208
|
end
|
212
209
|
end
|
@@ -7,6 +7,7 @@ class OnStomp::Components::ThreadedProcessor
|
|
7
7
|
def initialize client
|
8
8
|
@client = client
|
9
9
|
@run_thread = nil
|
10
|
+
@closing = false
|
10
11
|
end
|
11
12
|
|
12
13
|
# Returns true if its IO thread has been created and is alive, otherwise
|
@@ -25,6 +26,7 @@ class OnStomp::Components::ThreadedProcessor
|
|
25
26
|
begin
|
26
27
|
while @client.connected?
|
27
28
|
@client.connection.io_process
|
29
|
+
Thread.stop if @closing
|
28
30
|
end
|
29
31
|
rescue OnStomp::StopReceiver
|
30
32
|
rescue Exception
|
@@ -34,6 +36,17 @@ class OnStomp::Components::ThreadedProcessor
|
|
34
36
|
self
|
35
37
|
end
|
36
38
|
|
39
|
+
# Prepares the conneciton for closing by flushing its write buffer.
|
40
|
+
def prepare_to_close
|
41
|
+
if running?
|
42
|
+
@closing = true
|
43
|
+
Thread.pass until @run_thread.stop?
|
44
|
+
@client.connection.flush_write_buffer
|
45
|
+
@closing = false
|
46
|
+
@run_thread.wakeup
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
37
50
|
# Causes the thread this method was invoked in to +pass+ until the
|
38
51
|
# processor is no longer {#running? running}.
|
39
52
|
# @return [self]
|
@@ -93,13 +93,19 @@ class OnStomp::Connections::Base
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
+
# Flushes the write buffer by invoking {#io_process_write} until the
|
97
|
+
# buffer is empty.
|
98
|
+
def flush_write_buffer
|
99
|
+
io_process_write until @write_buffer.empty?
|
100
|
+
end
|
101
|
+
|
96
102
|
# Makes a single call to {#io_process_write} and a single call to
|
97
103
|
# {#io_process_read}
|
98
104
|
def io_process &cb
|
99
105
|
io_process_write &cb
|
100
106
|
io_process_read &cb
|
101
107
|
if @connection_up && !connected?
|
102
|
-
triggered_close :died
|
108
|
+
triggered_close 'connection timed out', :died
|
103
109
|
end
|
104
110
|
end
|
105
111
|
|
@@ -162,13 +168,13 @@ class OnStomp::Connections::Base
|
|
162
168
|
unshift_write_buffer data, frame
|
163
169
|
break
|
164
170
|
rescue Exception
|
165
|
-
triggered_close :terminated
|
171
|
+
triggered_close $!.message, :terminated
|
166
172
|
raise
|
167
173
|
end
|
168
174
|
end
|
169
175
|
end
|
170
176
|
if @write_buffer.empty? && @closing
|
171
|
-
triggered_close
|
177
|
+
triggered_close 'client disconnected'
|
172
178
|
end
|
173
179
|
end
|
174
180
|
|
@@ -189,20 +195,21 @@ class OnStomp::Connections::Base
|
|
189
195
|
rescue Errno::EINTR, Errno::EAGAIN, Errno::EWOULDBLOCK
|
190
196
|
# do not
|
191
197
|
rescue EOFError
|
192
|
-
triggered_close
|
198
|
+
triggered_close $!.message
|
193
199
|
rescue Exception
|
194
|
-
triggered_close :terminated
|
200
|
+
triggered_close $!.message, :terminated
|
195
201
|
raise
|
196
202
|
end
|
197
203
|
end
|
198
204
|
end
|
199
205
|
|
200
206
|
private
|
201
|
-
def triggered_close *evs
|
207
|
+
def triggered_close msg, *evs
|
202
208
|
@connection_up = false
|
203
209
|
@closing = false
|
204
210
|
socket.close
|
205
|
-
evs.each { |ev| trigger_connection_event ev }
|
206
|
-
trigger_connection_event :closed
|
211
|
+
evs.each { |ev| trigger_connection_event ev, msg }
|
212
|
+
trigger_connection_event :closed, msg
|
213
|
+
@write_buffer.clear
|
207
214
|
end
|
208
215
|
end
|
@@ -38,12 +38,6 @@ module OnStomp::Connections::Stomp_1
|
|
38
38
|
create_frame 'DISCONNECT', [h]
|
39
39
|
end
|
40
40
|
|
41
|
-
# Creates a SUBSCRIBE frame
|
42
|
-
# @return [OnStomp::Components::Frame] SUBSCRIBE frame
|
43
|
-
def subscribe_frame d, h
|
44
|
-
create_frame 'SUBSCRIBE', [{:id => OnStomp.next_serial}, h, {:destination => d}]
|
45
|
-
end
|
46
|
-
|
47
41
|
# Creates an UNSUBSCRIBE frame
|
48
42
|
# @return [OnStomp::Components::Frame] UNSUBSCRIBE frame
|
49
43
|
def unsubscribe_frame f, h
|
@@ -14,6 +14,14 @@ class OnStomp::Connections::Stomp_1_0 < OnStomp::Connections::Base
|
|
14
14
|
super
|
15
15
|
@serializer = OnStomp::Connections::Serializers::Stomp_1_0.new
|
16
16
|
end
|
17
|
+
|
18
|
+
# Creates a SUBSCRIBE frame. Sets +ack+ header to 'auto' unless it is
|
19
|
+
# already set to 'client'.
|
20
|
+
# @return [OnStomp::Components::Frame] SUBSCRIBE frame
|
21
|
+
def subscribe_frame d, h
|
22
|
+
h[:ack] = 'auto' unless h[:ack] == 'client'
|
23
|
+
create_frame 'SUBSCRIBE', [{:id => OnStomp.next_serial}, h, {:destination => d}]
|
24
|
+
end
|
17
25
|
|
18
26
|
# Creates an ACK frame
|
19
27
|
# @return [OnStomp::Components::Frame] ACK frame
|
@@ -31,6 +31,14 @@ class OnStomp::Connections::Stomp_1_1 < OnStomp::Connections::Base
|
|
31
31
|
super && pulse?
|
32
32
|
end
|
33
33
|
|
34
|
+
# Creates a SUBSCRIBE frame. Sets +ack+ header to 'auto' unless it is
|
35
|
+
# already set to 'client' or 'client-individual'.
|
36
|
+
# @return [OnStomp::Components::Frame] SUBSCRIBE frame
|
37
|
+
def subscribe_frame d, h
|
38
|
+
h[:ack] = 'auto' unless ['client', 'client-individual'].include?(h[:ack])
|
39
|
+
create_frame 'SUBSCRIBE', [{:id => OnStomp.next_serial}, h, {:destination => d}]
|
40
|
+
end
|
41
|
+
|
34
42
|
# Creates an ACK frame
|
35
43
|
# @return [OnStomp::Components::Frame] ACK frame
|
36
44
|
def ack_frame *args
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
# Namespace for failover extensions.
|
4
|
+
module OnStomp::Failover
|
5
|
+
# Raised if the supplied failover: URI is not properly formatted as
|
6
|
+
# +failover:(uri,uri,...)?optionalParams=values+
|
7
|
+
class InvalidFailoverURIError < OnStomp::OnStompError; end
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'onstomp/failover/uri'
|
11
|
+
require 'onstomp/failover/failover_configurable'
|
12
|
+
require 'onstomp/failover/failover_events'
|
13
|
+
require 'onstomp/failover/buffers'
|
14
|
+
require 'onstomp/failover/pools'
|
15
|
+
require 'onstomp/failover/client'
|
16
|
+
require 'onstomp/failover/new_with_failover'
|
@@ -0,0 +1,91 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
# A buffer that ensures frames are at least written to a
|
4
|
+
# {OnStomp::Client client}'s {OnStomp::Connections::Base connection} and
|
5
|
+
# replays the ones that were not when the
|
6
|
+
# {OnStomp::Failover::Client failover} client reconnects.
|
7
|
+
class OnStomp::Failover::Buffers::Written
|
8
|
+
def initialize failover
|
9
|
+
@failover = failover
|
10
|
+
@buffer_mutex = Mutex.new
|
11
|
+
@buffer = []
|
12
|
+
@txs = {}
|
13
|
+
|
14
|
+
failover.before_send &method(:buffer_frame)
|
15
|
+
failover.before_commit &method(:buffer_frame)
|
16
|
+
failover.before_abort &method(:buffer_frame)
|
17
|
+
failover.before_subscribe &method(:buffer_frame)
|
18
|
+
failover.before_begin &method(:buffer_transaction)
|
19
|
+
# We can scrub the subscription before UNSUBSCRIBE is fully written
|
20
|
+
# because if we replay before UNSUBSCRIBE was sent, we still don't
|
21
|
+
# want to be subscribed when we reconnect.
|
22
|
+
failover.before_unsubscribe &method(:debuffer_subscription)
|
23
|
+
# We only want to scrub the transactions if ABORT or COMMIT was
|
24
|
+
# at least written fully to the socket.
|
25
|
+
failover.on_commit &method(:debuffer_transaction)
|
26
|
+
failover.on_abort &method(:debuffer_transaction)
|
27
|
+
failover.on_send &method(:debuffer_non_transactional_frame)
|
28
|
+
|
29
|
+
failover.on_failover_connected &method(:replay)
|
30
|
+
end
|
31
|
+
|
32
|
+
# Adds a frame to a buffer so that it may be replayed if the
|
33
|
+
# {OnStomp::Failover::Client failover} client re-connects
|
34
|
+
def buffer_frame f, *_
|
35
|
+
@buffer_mutex.synchronize do
|
36
|
+
unless f.header? :'x-onstomp-failover-replay'
|
37
|
+
@buffer << f
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Records the start of a transaction so that it may be replayed if the
|
43
|
+
# {OnStomp::Failover::Client failover} client re-connects
|
44
|
+
def buffer_transaction f, *_
|
45
|
+
@txs[f[:transaction]] = true
|
46
|
+
buffer_frame f
|
47
|
+
end
|
48
|
+
|
49
|
+
# Removes the recorded transaction from the buffer after it has been
|
50
|
+
# written the broker socket so that it will not be replayed when the
|
51
|
+
# {OnStomp::Failover::Client failover} client re-connects
|
52
|
+
def debuffer_transaction f, *_
|
53
|
+
tx = f[:transaction]
|
54
|
+
if @txs.delete tx
|
55
|
+
@buffer_mutex.synchronize do
|
56
|
+
@buffer.reject! { |bf| bf[:transaction] == tx }
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Removes the matching SUBSCRIBE frame from the buffer after the
|
62
|
+
# UNSUBSCRIBE has been added to the connection's write buffer
|
63
|
+
# so that it will not be replayed when the
|
64
|
+
# {OnStomp::Failover::Client failover} client re-connects
|
65
|
+
def debuffer_subscription f, *_
|
66
|
+
@buffer_mutex.synchronize do
|
67
|
+
@buffer.reject! { |bf| bf.command == 'SUBSCRIBE' && bf[:id] == f[:id] }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Removes a frame that is not part of a transaction from the buffer
|
72
|
+
# after it has been written the broker socket so that it will not be
|
73
|
+
# replayed when the {OnStomp::Failover::Client failover} client re-connects
|
74
|
+
def debuffer_non_transactional_frame f, *_
|
75
|
+
unless @txs.key?(f[:transaction])
|
76
|
+
@buffer_mutex.synchronize { @buffer.delete f }
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# Called when the {OnStomp::Failover::Client failover} client triggers
|
81
|
+
# +on_failover_connected+ to start replaying any frames in the buffer.
|
82
|
+
def replay fail, client, *_
|
83
|
+
replay_frames = @buffer_mutex.synchronize do
|
84
|
+
@buffer.select { |f| f[:'x-onstomp-failover-replay'] = '1'; true }
|
85
|
+
end
|
86
|
+
|
87
|
+
replay_frames.each do |f|
|
88
|
+
client.transmit f
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|