amqp 0.5.9 → 0.6.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 CHANGED
@@ -51,8 +51,8 @@ AMQP resources:
51
51
 
52
52
  Servers:
53
53
  RabbitMQ (Rabbit Technologies, Erlang/OTP, MPL) - http://rabbitmq.com
54
- ZeroMQ (iMatrix/FastMQ/Intel, C++, GPL3) - http://www.zeromq.org
55
- OpenAMQ (iMatrix, C, GPL2) - http://openamq.org
54
+ ZeroMQ (iMatix/FastMQ/Intel, C++, GPL3) - http://www.zeromq.org
55
+ OpenAMQ (iMatix, C, GPL2) - http://openamq.org
56
56
  ActiveMQ (Apache Foundation, Java, apache2) - http://activemq.apache.org
57
57
 
58
58
  Steve Vinoski explains AMQP in his column, Towards Integration
@@ -67,8 +67,8 @@ AMQP resources:
67
67
  ZeroMQ's analysis of the messaging technology market
68
68
  http://www.zeromq.org/whitepapers:market-analysis
69
69
 
70
- ZeroMQ's background to AMQP
71
- http://www.zeromq.org/whitepapers:amqp-analysis
70
+ Pieter Hintjens's background to AMQP
71
+ http://www.openamq.org/doc:amqp-background
72
72
 
73
73
  Barry Pederson's py-amqplib
74
74
  http://barryp.org/software/py-amqplib/
@@ -13,8 +13,8 @@ EM.run{
13
13
  pp(msg)
14
14
  puts
15
15
  }
16
-
17
- else
16
+
17
+ elsif ARGV[0] == 'client'
18
18
 
19
19
  log = Logger.new
20
20
  log.debug 'its working!'
@@ -39,6 +39,16 @@ EM.run{
39
39
 
40
40
  AMQP.stop{ EM.stop_event_loop }
41
41
 
42
+ else
43
+
44
+ puts
45
+ puts "#{$0} <client|server>"
46
+ puts " client: send logs to message queue"
47
+ puts " server: read logs from message queue"
48
+ puts
49
+
50
+ EM.stop
51
+
42
52
  end
43
53
  }
44
54
 
@@ -0,0 +1,46 @@
1
+ $:.unshift File.dirname(__FILE__) + '/../../lib'
2
+ require 'mq'
3
+ require 'pp'
4
+
5
+ # For ack to work appropriatly you must shutdown AMQP gracefully,
6
+ # otherwise all items in your queue will be returned
7
+ Signal.trap('INT') { AMQP.stop{ EM.stop } }
8
+ Signal.trap('TERM'){ AMQP.stop{ EM.stop } }
9
+
10
+ EM.run do
11
+ MQ.queue('awesome').publish('Totally rad 1')
12
+ MQ.queue('awesome').publish('Totally rad 2')
13
+ MQ.queue('awesome').publish('Totally rad 3')
14
+
15
+ i = 0
16
+
17
+ # Stopping after the second item was acked will keep the 3rd item in the queue
18
+ MQ.queue('awesome').subscribe(:ack => true) do |h,m|
19
+ if (i+=1) == 3
20
+ puts 'Shutting down...'
21
+ AMQP.stop{ EM.stop }
22
+ end
23
+
24
+ if AMQP.closing?
25
+ puts "#{m} (ignored, redelivered later)"
26
+ else
27
+ puts m
28
+ h.ack
29
+ end
30
+ end
31
+ end
32
+
33
+ __END__
34
+
35
+ Totally rad 1
36
+ Totally rad 2
37
+ Shutting down...
38
+ Totally rad 3 (ignored, redelivered later)
39
+
40
+ When restarted:
41
+
42
+ Totally rad 3
43
+ Totally rad 1
44
+ Shutting down...
45
+ Totally rad 2 (ignored, redelivered later)
46
+ Totally rad 3 (ignored, redelivered later)
@@ -0,0 +1,43 @@
1
+ $:.unshift File.dirname(__FILE__) + '/../../lib'
2
+ require 'mq'
3
+ require 'pp'
4
+
5
+ Signal.trap('INT') { AMQP.stop{ EM.stop } }
6
+ Signal.trap('TERM'){ AMQP.stop{ EM.stop } }
7
+
8
+ AMQP.start do
9
+ queue = MQ.queue('awesome')
10
+
11
+ queue.publish('Totally rad 1')
12
+ queue.publish('Totally rad 2')
13
+ EM.add_timer(5){ queue.publish('Totally rad 3') }
14
+
15
+ queue.pop{ |msg|
16
+ unless msg
17
+ # queue was empty
18
+ p [Time.now, :queue_empty!]
19
+
20
+ # try again in 1 second
21
+ EM.add_timer(1){ queue.pop }
22
+ else
23
+ # process this message
24
+ p [Time.now, msg]
25
+
26
+ # get the next message in the queue
27
+ queue.pop
28
+ end
29
+ }
30
+ end
31
+
32
+ __END__
33
+
34
+ [Wed Oct 15 15:24:30 -0700 2008, "Totally rad 1"]
35
+ [Wed Oct 15 15:24:30 -0700 2008, "Totally rad 2"]
36
+ [Wed Oct 15 15:24:30 -0700 2008, :queue_empty!]
37
+ [Wed Oct 15 15:24:31 -0700 2008, :queue_empty!]
38
+ [Wed Oct 15 15:24:32 -0700 2008, :queue_empty!]
39
+ [Wed Oct 15 15:24:33 -0700 2008, :queue_empty!]
40
+ [Wed Oct 15 15:24:34 -0700 2008, :queue_empty!]
41
+ [Wed Oct 15 15:24:35 -0700 2008, "Totally rad 3"]
42
+ [Wed Oct 15 15:24:35 -0700 2008, :queue_empty!]
43
+ [Wed Oct 15 15:24:36 -0700 2008, :queue_empty!]
@@ -5,7 +5,7 @@ require 'pp'
5
5
  EM.run do
6
6
 
7
7
  # connect to the amqp server
8
- connection = AMQP.connect(:host => 'dev.rabbitmq.com', :logging => false)
8
+ connection = AMQP.connect(:host => 'localhost', :logging => false)
9
9
 
10
10
  # open a channel on the AMQP connection
11
11
  channel = MQ.new(connection)
data/lib/amqp.rb CHANGED
@@ -14,7 +14,8 @@ module AMQP
14
14
  class << self
15
15
  @logging = false
16
16
  attr_accessor :logging
17
- attr_reader :conn
17
+ attr_reader :conn, :closing
18
+ alias :closing? :closing
18
19
  alias :connection :conn
19
20
  end
20
21
 
@@ -41,24 +42,61 @@ module AMQP
41
42
  }
42
43
  end
43
44
 
44
- def self.start *args
45
- @conn ||= connect *args
45
+ # Must be called to startup the connection to the AMQP server.
46
+ #
47
+ # The method takes several arguments and an optional block.
48
+ #
49
+ # This takes any option that is also accepted by EventMachine::connect.
50
+ # Additionally, there are several AMQP-specific options.
51
+ #
52
+ # * :user => String (default 'guest')
53
+ # The username as defined by the AMQP server.
54
+ # * :pass => String (default 'guest')
55
+ # The password for the associated :user as defined by the AMQP server.
56
+ # * :vhost => String (default '/')
57
+ # The virtual host as defined by the AMQP server.
58
+ # * :timeout => Numeric (default nil)
59
+ # Measured in seconds.
60
+ # * :logging => true | false (default false)
61
+ # Toggle the extremely verbose logging of all protocol communications
62
+ # between the client and the server. Extremely useful for debugging.
63
+ #
64
+ # AMQP.start do
65
+ # # default is to connect to localhost:5672
66
+ #
67
+ # # define queues, exchanges and bindings here.
68
+ # # also define all subscriptions and/or publishers
69
+ # # here.
70
+ #
71
+ # # this block never exits unless EM.stop_event_loop
72
+ # # is called.
73
+ # end
74
+ #
75
+ # Most code will use the MQ api. Any calls to MQ.direct / MQ.fanout /
76
+ # MQ.topic / MQ.queue will implicitly call #start. In those cases,
77
+ # it is sufficient to put your code inside of an EventMachine.run
78
+ # block. See the code examples in MQ for details.
79
+ #
80
+ def self.start *args, &blk
81
+ EM.run{
82
+ @conn ||= connect *args
83
+ @conn.callback(&blk) if blk
84
+ @conn
85
+ }
86
+ end
87
+
88
+ class << self
89
+ alias :run :start
46
90
  end
47
91
 
48
92
  def self.stop
49
- if @conn
93
+ if @conn and not @closing
94
+ @closing = true
50
95
  @conn.close{
51
96
  yield if block_given?
52
97
  @conn = nil
98
+ @closing = false
53
99
  }
54
100
  end
55
101
  end
56
-
57
- def self.run *args
58
- EM.run{
59
- AMQP.start(*args).callback{
60
- yield
61
- }
62
- }
63
- end
64
- end
102
+ end
data/lib/amqp/buffer.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  if [].map.respond_to? :with_index
2
- class Array
2
+ class Array #:nodoc:
3
3
  def enum_with_index
4
4
  each.with_index
5
5
  end
@@ -9,9 +9,9 @@ else
9
9
  end
10
10
 
11
11
  module AMQP
12
- class Buffer
13
- class Overflow < Exception; end
14
- class InvalidType < Exception; end
12
+ class Buffer #:nodoc: all
13
+ class Overflow < StandardError; end
14
+ class InvalidType < StandardError; end
15
15
 
16
16
  def initialize data = ''
17
17
  @data = data
data/lib/amqp/client.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  require 'amqp/frame'
2
2
 
3
3
  module AMQP
4
- class Error < Exception; end
4
+ class Error < StandardError; end
5
5
 
6
6
  module BasicClient
7
7
  def process_frame frame
@@ -30,13 +30,14 @@ module AMQP
30
30
 
31
31
  send Protocol::Connection::Open.new(:virtual_host => @settings[:vhost],
32
32
  :capabilities => '',
33
- :insist => false)
33
+ :insist => @settings[:insist])
34
34
 
35
35
  when Protocol::Connection::OpenOk
36
36
  succeed(self)
37
37
 
38
38
  when Protocol::Connection::Close
39
- raise Error, "#{method.reply_text} in #{Protocol.classes[method.class_id].methods[method.method_id]}"
39
+ # raise Error, "#{method.reply_text} in #{Protocol.classes[method.class_id].methods[method.method_id]}"
40
+ STDERR.puts "#{method.reply_text} in #{Protocol.classes[method.class_id].methods[method.method_id]}"
40
41
 
41
42
  when Protocol::Connection::CloseOk
42
43
  @on_disconnect.call if @on_disconnect
@@ -61,7 +62,7 @@ module AMQP
61
62
  @settings = opts
62
63
  extend AMQP.client
63
64
 
64
- @on_disconnect = proc{ raise Error, "Could not connect to server #{opts[:host]}:#{opts[:port]}" }
65
+ @on_disconnect ||= proc{ raise Error, "Could not connect to server #{opts[:host]}:#{opts[:port]}" }
65
66
 
66
67
  timeout @settings[:timeout] if @settings[:timeout]
67
68
  errback{ @on_disconnect.call }
@@ -69,7 +70,11 @@ module AMQP
69
70
 
70
71
  def connection_completed
71
72
  log 'connected'
72
- @on_disconnect = proc{ raise Error, 'Disconnected from server' }
73
+ # @on_disconnect = proc{ raise Error, 'Disconnected from server' }
74
+ unless @closing
75
+ @on_disconnect = method(:reconnect)
76
+ @reconnecting = false
77
+ end
73
78
  @buf = Buffer.new
74
79
  send_data HEADER
75
80
  send_data [1, 1, VERSION_MAJOR, VERSION_MINOR].pack('C4')
@@ -77,7 +82,7 @@ module AMQP
77
82
 
78
83
  def unbind
79
84
  log 'disconnected'
80
- @on_disconnect.call unless $!
85
+ EM.next_tick{ @on_disconnect.call }
81
86
  end
82
87
 
83
88
  def add_channel mq
@@ -115,13 +120,21 @@ module AMQP
115
120
  send_data data.to_s
116
121
  end
117
122
 
123
+ #:stopdoc:
118
124
  # def send_data data
119
125
  # log 'send_data', data
120
126
  # super
121
127
  # end
128
+ #:startdoc:
122
129
 
123
130
  def close &on_disconnect
124
- @on_disconnect = on_disconnect if on_disconnect
131
+ if on_disconnect
132
+ @closing = true
133
+ @on_disconnect = proc{
134
+ on_disconnect.call
135
+ @closing = false
136
+ }
137
+ end
125
138
 
126
139
  callback{ |c|
127
140
  if c.channels.any?
@@ -136,7 +149,29 @@ module AMQP
136
149
  end
137
150
  }
138
151
  end
139
-
152
+
153
+ def reconnect force = false
154
+ if @reconnecting and not force
155
+ # wait 1 second after first reconnect attempt, in between each subsequent attempt
156
+ EM.add_timer(1){ reconnect(true) }
157
+ return
158
+ end
159
+
160
+ unless @reconnecting
161
+ @deferred_status = nil
162
+ initialize(@settings)
163
+
164
+ mqs = @channels
165
+ @channels = {}
166
+ mqs.each{ |_,mq| mq.reset } if mqs
167
+
168
+ @reconnecting = true
169
+ end
170
+
171
+ log 'reconnecting'
172
+ EM.reconnect @settings[:host], @settings[:port], self
173
+ end
174
+
140
175
  def self.connect opts = {}
141
176
  opts = AMQP.settings.merge(opts)
142
177
  EM.connect opts[:host], opts[:port], self, opts
data/lib/amqp/frame.rb CHANGED
@@ -3,7 +3,7 @@ require 'amqp/buffer'
3
3
  require 'amqp/protocol'
4
4
 
5
5
  module AMQP
6
- class Frame
6
+ class Frame #:nodoc: all
7
7
  def initialize payload = nil, channel = 0
8
8
  @channel, @payload = channel, payload
9
9
  end
@@ -33,7 +33,7 @@ module AMQP
33
33
  end
34
34
  end
35
35
 
36
- class Invalid < Exception; end
36
+ class Invalid < StandardError; end
37
37
 
38
38
  class Method
39
39
  def initialize payload = nil, channel = 0
data/lib/amqp/protocol.rb CHANGED
@@ -3,6 +3,7 @@ require 'amqp/buffer'
3
3
 
4
4
  module AMQP
5
5
  module Protocol
6
+ #:stopdoc:
6
7
  class Class::Method
7
8
  def initialize *args
8
9
  opts = args.pop if args.last.is_a? Hash
@@ -64,6 +65,29 @@ module AMQP
64
65
  end
65
66
  end
66
67
 
68
+ #:startdoc:
69
+ #
70
+ # Contains a properties hash that holds some potentially interesting
71
+ # information.
72
+ # * :delivery_mode
73
+ # 1 equals transient.
74
+ # 2 equals persistent. Unconsumed persistent messages will survive
75
+ # a server restart when they are stored in a durable queue.
76
+ # * :redelivered
77
+ # True or False
78
+ # * :routing_key
79
+ # The routing string used for matching this message to this queue.
80
+ # * :priority
81
+ # An integer in the range of 0 to 9 inclusive.
82
+ # * :content_type
83
+ # Always "application/octet-stream" (byte stream)
84
+ # * :exchange
85
+ # The source exchange which published this message.
86
+ # * :message_count
87
+ # The number of unconsumed messages contained in the queue.
88
+ # * :delivery_tag
89
+ # A monotonically increasing integer. This number should not be trusted
90
+ # as a sequence number. There is no guarantee it won't get reset.
67
91
  class Header
68
92
  def initialize *args
69
93
  opts = args.pop if args.last.is_a? Hash
@@ -132,6 +156,7 @@ module AMQP
132
156
  class_id, method_id = buf.read(:short, :short)
133
157
  classes[class_id].methods[method_id].new(buf)
134
158
  end
159
+ #:stopdoc:
135
160
  end
136
161
  end
137
162
 
data/lib/amqp/spec.rb CHANGED
@@ -1,6 +1,7 @@
1
1
 
2
- # this file was autogenerated on Fri Aug 01 15:08:30 -0700 2008
3
- # using amqp-0.8.json (mtime: Fri Aug 01 15:08:22 -0700 2008)
2
+ #:stopdoc:
3
+ # this file was autogenerated on Sat Jan 03 14:05:57 -0600 2009
4
+ # using amqp-0.8.json (mtime: Sat Jan 03 08:58:13 -0600 2009)
4
5
  #
5
6
  # DO NOT EDIT! (edit protocol/codegen.rb instead, and run `rake codegen`)
6
7
 
@@ -1,7 +1,7 @@
1
1
  unless defined?(BlankSlate)
2
2
  class BlankSlate < BasicObject; end if defined?(BasicObject)
3
3
 
4
- class BlankSlate
4
+ class BlankSlate #:nodoc:
5
5
  instance_methods.each { |m| undef_method m unless m =~ /^__/ }
6
6
  end
7
7
  end