right_agent 0.6.3 → 0.6.6
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/lib/right_agent.rb +1 -0
- data/lib/right_agent/agent_tags_manager.rb +1 -1
- data/lib/right_agent/broker_client.rb +6 -1
- data/lib/right_agent/core_payload_types.rb +1 -0
- data/lib/right_agent/core_payload_types/dev_repositories.rb +11 -1
- data/lib/right_agent/core_payload_types/dev_repository.rb +76 -0
- data/lib/right_agent/log.rb +2 -1
- data/lib/right_agent/monkey_patches/amqp_patch.rb +181 -102
- data/lib/right_agent/platform/linux.rb +134 -2
- data/lib/right_agent/sender.rb +7 -3
- data/right_agent.gemspec +2 -2
- data/spec/broker_client_spec.rb +37 -37
- data/spec/core_payload_types/dev_repositories_spec.rb +5 -5
- data/spec/core_payload_types/dev_repository_spec.rb +33 -0
- data/spec/monkey_patches/amqp_patch_spec.rb +0 -12
- data/spec/platform/linux_volume_manager_spec.rb +180 -0
- data/spec/sender_spec.rb +95 -0
- metadata +39 -36
data/lib/right_agent.rb
CHANGED
@@ -184,7 +184,7 @@ module RightScale
|
|
184
184
|
request = RightScale::IdempotentRequest.new("/mapper/query_tags", payload)
|
185
185
|
request.callback { |result| yield raw ? request.raw_response : result }
|
186
186
|
request.errback do |message|
|
187
|
-
|
187
|
+
Log.error("Failed to query tags: #{message}")
|
188
188
|
yield((raw ? request.raw_response : nil) || message)
|
189
189
|
end
|
190
190
|
request.run
|
@@ -543,6 +543,11 @@ module RightScale
|
|
543
543
|
# Do not let closed connection regress to failed
|
544
544
|
return true if status == :failed && @status == :closed
|
545
545
|
|
546
|
+
# Wait until connection is ready (i.e. handshake with broker is completed) before
|
547
|
+
# changing our status to connected
|
548
|
+
return true if status == :connected
|
549
|
+
status = :connected if status == :ready
|
550
|
+
|
546
551
|
before = @status
|
547
552
|
@status = status
|
548
553
|
|
@@ -587,7 +592,7 @@ module RightScale
|
|
587
592
|
:heartbeat => @options[:heartbeat],
|
588
593
|
:reconnect_delay => lambda { rand(reconnect_interval) },
|
589
594
|
:reconnect_interval => reconnect_interval)
|
590
|
-
@channel =
|
595
|
+
@channel = MQ.new(@connection)
|
591
596
|
@channel.__send__(:connection).connection_status { |status| update_status(status) }
|
592
597
|
@channel.prefetch(@options[:prefetch]) if @options[:prefetch]
|
593
598
|
rescue Exception => e
|
@@ -27,6 +27,7 @@ require File.normalize_path(File.join(CORE_PAYLOAD_TYPES_BASE_DIR, 'cookbook'))
|
|
27
27
|
require File.normalize_path(File.join(CORE_PAYLOAD_TYPES_BASE_DIR, 'cookbook_repository'))
|
28
28
|
require File.normalize_path(File.join(CORE_PAYLOAD_TYPES_BASE_DIR, 'cookbook_sequence'))
|
29
29
|
require File.normalize_path(File.join(CORE_PAYLOAD_TYPES_BASE_DIR, 'cookbook_position'))
|
30
|
+
require File.normalize_path(File.join(CORE_PAYLOAD_TYPES_BASE_DIR, 'dev_repository'))
|
30
31
|
require File.normalize_path(File.join(CORE_PAYLOAD_TYPES_BASE_DIR, 'dev_repositories'))
|
31
32
|
require File.normalize_path(File.join(CORE_PAYLOAD_TYPES_BASE_DIR, 'executable_bundle'))
|
32
33
|
require File.normalize_path(File.join(CORE_PAYLOAD_TYPES_BASE_DIR, 'event_categories'))
|
@@ -21,6 +21,8 @@
|
|
21
21
|
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
22
|
#++
|
23
23
|
|
24
|
+
require File.join(File.dirname(__FILE__), 'dev_repository')
|
25
|
+
|
24
26
|
module RightScale
|
25
27
|
# Sequence of cookbooks to be checked out on the instance.
|
26
28
|
class DevRepositories
|
@@ -76,7 +78,15 @@ module RightScale
|
|
76
78
|
# result(Hash):: The entry added to the collection of repositories
|
77
79
|
def add_repo(repo_sha, repo_detail, cookbook_positions)
|
78
80
|
@repositories ||= {}
|
79
|
-
@repositories[repo_sha] =
|
81
|
+
@repositories[repo_sha] = DevRepository.new(repo_detail[:repo_type],
|
82
|
+
repo_detail[:url],
|
83
|
+
repo_detail[:tag],
|
84
|
+
repo_detail[:cookboooks_path],
|
85
|
+
repo_detail[:ssh_key],
|
86
|
+
repo_detail[:username],
|
87
|
+
repo_detail[:password],
|
88
|
+
repo_sha,
|
89
|
+
cookbook_positions)
|
80
90
|
end
|
81
91
|
|
82
92
|
#
|
@@ -0,0 +1,76 @@
|
|
1
|
+
#--
|
2
|
+
# Copyright: Copyright (c) 2010-2011 RightScale, Inc.
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# 'Software'), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
18
|
+
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
19
|
+
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
20
|
+
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
21
|
+
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
#++
|
23
|
+
|
24
|
+
module RightScale
|
25
|
+
# Sequence of cookbooks to be checked out on the instance.
|
26
|
+
class DevRepository
|
27
|
+
include Serializable
|
28
|
+
|
29
|
+
# (Symbol) Type of repository: one of :git, :svn, :download or :local
|
30
|
+
# * :git denotes a 'git' repository that should be retrieved via 'git clone'
|
31
|
+
# * :svn denotes a 'svn' repository that should be retrieved via 'svn checkout'
|
32
|
+
# * :download denotes a tar ball that should be retrieved via HTTP GET (HTTPS if uri starts with https://)
|
33
|
+
# * :local denotes cookbook that is already local and doesn't need to be retrieved
|
34
|
+
attr_accessor :repo_type
|
35
|
+
# (String) URL to repository (e.g. git://github.com/opscode/chef-repo.git)
|
36
|
+
attr_accessor :url
|
37
|
+
# (String) git commit or svn branch that should be used to retrieve repository
|
38
|
+
# Optional, use 'master' for git and 'trunk' for svn if tag is nil.
|
39
|
+
# Not used for raw repositories.
|
40
|
+
attr_accessor :tag
|
41
|
+
# (Array) Path to cookbooks inside repostory
|
42
|
+
# Optional (use location of repository as cookbook path if nil)
|
43
|
+
attr_accessor :cookbooks_path
|
44
|
+
# (String) Private SSH key used to retrieve git repositories
|
45
|
+
# Optional, not used for svn and raw repositories.
|
46
|
+
attr_accessor :ssh_key
|
47
|
+
# (String) Username used to retrieve svn and raw repositories
|
48
|
+
# Optional, not used for git repositories.
|
49
|
+
attr_accessor :username
|
50
|
+
# (String) Password used to retrieve svn and raw repositories
|
51
|
+
# Optional, not used for git repositories.
|
52
|
+
attr_accessor :password
|
53
|
+
# (String) hash of the CookbookSequence that corresponds to the repo
|
54
|
+
attr_accessor :repo_sha
|
55
|
+
# (Array) List of cookbook <name, position> pairs
|
56
|
+
attr_accessor :positions
|
57
|
+
|
58
|
+
# Initialize fields from given arguments
|
59
|
+
def initialize(*args)
|
60
|
+
@repo_type = args[0]
|
61
|
+
@url = args[1] if args.size > 1
|
62
|
+
@tag = args[2] if args.size > 2
|
63
|
+
@cookbooks_path = args[3] if args.size > 3
|
64
|
+
@ssh_key = args[4] if args.size > 4
|
65
|
+
@username = args[5] if args.size > 5
|
66
|
+
@password = args[6] if args.size > 6
|
67
|
+
@repo_sha = args[7] if args.size > 7
|
68
|
+
@positions = args[8] if args.size > 8
|
69
|
+
end
|
70
|
+
|
71
|
+
# Array of serialized fields given to constructor
|
72
|
+
def serialized_members
|
73
|
+
[ @repo_type, @url, @tag, @cookbooks_path, @ssh_key, @username, @password, @repo_sha, @positions ]
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/right_agent/log.rb
CHANGED
@@ -319,8 +319,9 @@ module RightScale
|
|
319
319
|
if new_level != @level
|
320
320
|
@logger.info("[setup] Setting log level to #{level_to_sym(new_level).to_s.upcase}")
|
321
321
|
@logger.level = @level = new_level
|
322
|
-
@notify.each { |n| n.call(@level) } if @notify
|
323
322
|
end
|
323
|
+
# Notify even if unchanged since don't know when callback was set
|
324
|
+
@notify.each { |n| n.call(@level) } if @notify
|
324
325
|
end
|
325
326
|
level = level_to_sym(@level)
|
326
327
|
end
|
@@ -20,48 +20,170 @@
|
|
20
20
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
21
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
22
|
|
23
|
-
|
24
|
-
# Clean up AMQP connection when an error is raised after a broker request failure,
|
25
|
-
# otherwise AMQP becomes unusable
|
26
|
-
AMQP.module_eval do
|
27
|
-
def self.start *args, &blk
|
28
|
-
begin
|
29
|
-
EM.run{
|
30
|
-
@conn ||= connect *args
|
31
|
-
@conn.callback { AMQP.channel = AMQP::Channel.new(@conn) }
|
23
|
+
class MQ
|
32
24
|
|
33
|
-
|
34
|
-
|
35
|
-
|
25
|
+
class Queue
|
26
|
+
# Asks the broker to redeliver all unacknowledged messages on a
|
27
|
+
# specified channel. Zero or more messages may be redelivered.
|
28
|
+
#
|
29
|
+
# * requeue (default false)
|
30
|
+
# If this parameter is false, the message will be redelivered to the original recipient.
|
31
|
+
# If this flag is true, the server will attempt to requeue the message, potentially then
|
32
|
+
# delivering it to an alternative subscriber.
|
33
|
+
#
|
34
|
+
def recover(requeue = false)
|
35
|
+
@mq.callback{
|
36
|
+
@mq.send Protocol::Basic::Recover.new({ :requeue => requeue })
|
37
|
+
}
|
38
|
+
self
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# May raise a MQ::Error exception when the frame payload contains a
|
43
|
+
# Protocol::Channel::Close object.
|
44
|
+
#
|
45
|
+
# This usually occurs when a client attempts to perform an illegal
|
46
|
+
# operation. A short, and incomplete, list of potential illegal operations
|
47
|
+
# follows:
|
48
|
+
# * publish a message to a deleted exchange (NOT_FOUND)
|
49
|
+
# * declare an exchange using the reserved 'amq.' naming structure (ACCESS_REFUSED)
|
50
|
+
#
|
51
|
+
def process_frame frame
|
52
|
+
log :received, frame
|
53
|
+
|
54
|
+
case frame
|
55
|
+
when Frame::Header
|
56
|
+
@header = frame.payload
|
57
|
+
@body = ''
|
58
|
+
|
59
|
+
when Frame::Body
|
60
|
+
@body << frame.payload
|
61
|
+
if @body.length >= @header.size
|
62
|
+
if @method.is_a? Protocol::Basic::Return
|
63
|
+
@on_return_message.call @method, @body if @on_return_message
|
64
|
+
else
|
65
|
+
@header.properties.update(@method.arguments)
|
66
|
+
@consumer.receive @header, @body if @consumer
|
67
|
+
end
|
68
|
+
@body = @header = @consumer = @method = nil
|
69
|
+
end
|
70
|
+
|
71
|
+
when Frame::Method
|
72
|
+
case method = frame.payload
|
73
|
+
when Protocol::Channel::OpenOk
|
74
|
+
send Protocol::Access::Request.new(:realm => '/data',
|
75
|
+
:read => true,
|
76
|
+
:write => true,
|
77
|
+
:active => true,
|
78
|
+
:passive => true)
|
79
|
+
|
80
|
+
when Protocol::Access::RequestOk
|
81
|
+
@ticket = method.ticket
|
82
|
+
callback{
|
83
|
+
send Protocol::Channel::Close.new(:reply_code => 200,
|
84
|
+
:reply_text => 'bye',
|
85
|
+
:method_id => 0,
|
86
|
+
:class_id => 0)
|
87
|
+
} if @closing
|
88
|
+
succeed
|
89
|
+
|
90
|
+
when Protocol::Basic::CancelOk
|
91
|
+
if @consumer = consumers[ method.consumer_tag ]
|
92
|
+
@consumer.cancelled
|
93
|
+
else
|
94
|
+
MQ.error "Basic.CancelOk for invalid consumer tag: #{method.consumer_tag}"
|
95
|
+
end
|
96
|
+
|
97
|
+
when Protocol::Queue::DeclareOk
|
98
|
+
queues[ method.queue ].receive_status method
|
99
|
+
|
100
|
+
when Protocol::Basic::Deliver, Protocol::Basic::GetOk
|
101
|
+
@method = method
|
102
|
+
@header = nil
|
103
|
+
@body = ''
|
104
|
+
|
105
|
+
if method.is_a? Protocol::Basic::GetOk
|
106
|
+
@consumer = get_queue{|q| q.shift }
|
107
|
+
MQ.error "No pending Basic.GetOk requests" unless @consumer
|
108
|
+
else
|
109
|
+
@consumer = consumers[ method.consumer_tag ]
|
110
|
+
MQ.error "Basic.Deliver for invalid consumer tag: #{method.consumer_tag}" unless @consumer
|
111
|
+
end
|
112
|
+
|
113
|
+
when Protocol::Basic::GetEmpty
|
114
|
+
if @consumer = get_queue{|q| q.shift }
|
115
|
+
@consumer.receive nil, nil
|
116
|
+
else
|
117
|
+
MQ.error "Basic.GetEmpty for invalid consumer"
|
118
|
+
end
|
119
|
+
|
120
|
+
when Protocol::Basic::Return
|
121
|
+
@method = method
|
122
|
+
@header = nil
|
123
|
+
@body = ''
|
124
|
+
|
125
|
+
when Protocol::Channel::Close
|
126
|
+
raise Error, "#{method.reply_text} in #{Protocol.classes[method.class_id].methods[method.method_id]} on #{@channel}"
|
127
|
+
|
128
|
+
when Protocol::Channel::CloseOk
|
129
|
+
@closing = false
|
130
|
+
conn.callback{ |c|
|
131
|
+
c.channels.delete @channel
|
132
|
+
c.close if c.channels.empty?
|
36
133
|
}
|
37
|
-
|
38
|
-
|
39
|
-
|
134
|
+
|
135
|
+
when Protocol::Basic::ConsumeOk
|
136
|
+
if @consumer = consumers[ method.consumer_tag ]
|
137
|
+
@consumer.confirm_subscribe
|
138
|
+
else
|
139
|
+
MQ.error "Basic.ConsumeOk for invalid consumer tag: #{method.consumer_tag}"
|
140
|
+
end
|
40
141
|
end
|
41
142
|
end
|
42
143
|
end
|
43
144
|
|
145
|
+
# Provide callback to be activated when a message is returned
|
146
|
+
def return_message(&blk)
|
147
|
+
@on_return_message = blk
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
|
152
|
+
# monkey patch to the amqp gem that adds :no_declare => true option for new Queue objects.
|
153
|
+
# This allows an instance that has no configuration privileges to enroll without blowing
|
154
|
+
# up the AMQP gem when it tries to subscribe to its queue before it has been created.
|
155
|
+
# Exchange :no_declare support is already in the eventmachine-0.12.10 gem.
|
156
|
+
# temporary until we get this into amqp proper
|
157
|
+
MQ::Queue.class_eval do
|
158
|
+
def initialize mq, name, opts = {}
|
159
|
+
@mq = mq
|
160
|
+
@opts = opts
|
161
|
+
@bindings ||= {}
|
162
|
+
@mq.queues[@name = name] ||= self
|
163
|
+
unless opts[:no_declare]
|
164
|
+
@mq.callback{
|
165
|
+
@mq.send AMQP::Protocol::Queue::Declare.new({ :queue => name,
|
166
|
+
:nowait => true }.merge(opts))
|
167
|
+
}
|
168
|
+
end
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
begin
|
173
|
+
# Monkey patch AMQP reconnect backoff
|
44
174
|
AMQP::Client.module_eval do
|
45
|
-
# Add callback for connection failure
|
46
175
|
def initialize opts = {}
|
47
176
|
@settings = opts
|
48
177
|
extend AMQP.client
|
49
178
|
|
50
|
-
@_channel_mutex = Mutex.new
|
51
|
-
|
52
179
|
@on_disconnect ||= proc{ @connection_status.call(:failed) if @connection_status }
|
53
180
|
|
54
181
|
timeout @settings[:timeout] if @settings[:timeout]
|
55
182
|
errback{ @on_disconnect.call } unless @reconnecting
|
56
|
-
@connection_status = @settings[:connection_status]
|
57
183
|
|
58
|
-
|
59
|
-
@tcp_connection_established = false
|
60
|
-
# AMQP connection "openness"
|
61
|
-
@connected = false
|
184
|
+
@connected = false
|
62
185
|
end
|
63
186
|
|
64
|
-
# Add backoff controls to the reconnect algorithm
|
65
187
|
def reconnect(force = false)
|
66
188
|
if @reconnecting and not force
|
67
189
|
# Wait after first reconnect attempt and in between each subsequent attempt
|
@@ -94,96 +216,53 @@ begin
|
|
94
216
|
"#{RightScale::AgentIdentity.new('rs', 'broker', @settings[:port].to_i, @settings[:host].gsub('-', '~')).to_s}")
|
95
217
|
log 'reconnecting'
|
96
218
|
EM.reconnect(@settings[:host], @settings[:port], self)
|
97
|
-
rescue Exception => e
|
98
|
-
RightScale::Log.error("Exception caught during AMQP reconnect", e, :trace)
|
99
|
-
reconnect if @reconnecting
|
100
219
|
end
|
220
|
+
end
|
101
221
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
def receive_data(*args)
|
222
|
+
# Monkey patch AMQP to clean up @conn when an error is raised after a broker request failure,
|
223
|
+
# otherwise AMQP becomes unusable
|
224
|
+
AMQP.module_eval do
|
225
|
+
def self.start *args, &blk
|
107
226
|
begin
|
108
|
-
|
227
|
+
EM.run{
|
228
|
+
@conn ||= connect *args
|
229
|
+
@conn.callback(&blk) if blk
|
230
|
+
@conn
|
231
|
+
}
|
109
232
|
rescue Exception => e
|
110
|
-
|
111
|
-
|
112
|
-
end
|
113
|
-
close_connection
|
233
|
+
@conn = nil
|
234
|
+
raise e
|
114
235
|
end
|
115
236
|
end
|
116
|
-
|
117
|
-
# Make it log to RightScale when logging enabled
|
118
|
-
def log(*args)
|
119
|
-
return unless @settings[:logging] or AMQP.logging
|
120
|
-
require 'pp'
|
121
|
-
RightScale::Log.info("AMQP #{args.pretty_inspect.chomp}")
|
122
|
-
end
|
123
237
|
end
|
124
238
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
# Provide callback to be activated when a message is returned
|
140
|
-
def return_message(&blk)
|
141
|
-
@on_return_message = blk
|
142
|
-
end
|
143
|
-
|
144
|
-
# Apply :no_declare option
|
145
|
-
def validate_parameters_match!(entity, parameters)
|
146
|
-
unless entity.opts == parameters || parameters[:passive] || parameters[:no_declare] || entity.opts[:no_declare]
|
147
|
-
raise AMQP::IncompatibleOptionsError.new(entity.name, entity.opts, parameters)
|
239
|
+
# This monkey patch catches exceptions that would otherwise cause EM to stop or be in a bad
|
240
|
+
# state if a top level EM error handler was setup. Instead close the connection and leave EM
|
241
|
+
# alone.
|
242
|
+
# Don't log an error if the environment variable IGNORE_AMQP_FAILURES is set (used in the
|
243
|
+
# enroll script)
|
244
|
+
AMQP::Client.module_eval do
|
245
|
+
alias :orig_receive_data :receive_data
|
246
|
+
def receive_data(*args)
|
247
|
+
begin
|
248
|
+
orig_receive_data(*args)
|
249
|
+
rescue Exception => e
|
250
|
+
RightScale::Log.error("Exception caught while processing AMQP frame, closing connection",
|
251
|
+
e, :trace) unless ENV['IGNORE_AMQP_FAILURES']
|
252
|
+
close_connection
|
148
253
|
end
|
149
254
|
end
|
150
|
-
|
151
|
-
# Make it log to RightScale when logging enabled
|
152
|
-
def log(*args)
|
153
|
-
return unless AMQP.logging
|
154
|
-
require 'pp'
|
155
|
-
RightScale::Log.info("AMQP #{args.pretty_inspect.chomp}")
|
156
|
-
end
|
157
255
|
end
|
158
256
|
|
159
|
-
# Add
|
160
|
-
#
|
161
|
-
#
|
162
|
-
#
|
163
|
-
AMQP::
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
@
|
168
|
-
@opts = self.class.add_default_options(name, opts, block)
|
169
|
-
@bindings ||= {}
|
170
|
-
@status = @opts[:nowait] ? :unknown : :unfinished
|
171
|
-
|
172
|
-
if name.empty?
|
173
|
-
@mq.queues_awaiting_declare_ok.push(self)
|
174
|
-
else
|
175
|
-
@name = name
|
176
|
-
end
|
177
|
-
|
178
|
-
unless opts[:no_declare]
|
179
|
-
@mq.callback{
|
180
|
-
@mq.send AMQP::Protocol::Queue::Declare.new(@opts)
|
181
|
-
}
|
182
|
-
end
|
183
|
-
|
184
|
-
self.callback = block
|
185
|
-
|
186
|
-
block.call(self) if @opts[:nowait] && block
|
257
|
+
# Add a new callback to amqp gem that triggers once the handshake with the broker completed
|
258
|
+
# The 'connected' status callback happens before the handshake is done and if it results in
|
259
|
+
# a lot of activity it might prevent EM from being able to call the code handling the
|
260
|
+
# incoming handshake packet in a timely fashion causing the broker to close the connection
|
261
|
+
AMQP::BasicClient.module_eval do
|
262
|
+
alias :orig_process_frame :process_frame
|
263
|
+
def process_frame(frame)
|
264
|
+
orig_process_frame(frame)
|
265
|
+
@connection_status.call(:ready) if @connection_status && frame.payload.is_a?(AMQP::Protocol::Connection::Start)
|
187
266
|
end
|
188
267
|
end
|
189
268
|
|