amqp 0.5.9 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
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