amqp 0.5.5 → 0.5.9

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
@@ -7,6 +7,8 @@ Simple AMQP driver for Ruby/EventMachine
7
7
  http://groups.google.com/group/ruby-amqp
8
8
  http://lists.rabbitmq.com/pipermail/rabbitmq-discuss/2008-July/001417.html
9
9
 
10
+ This library works with Ruby 1.8, Ruby 1.9 and JRuby.
11
+
10
12
  This library was tested primarily with RabbitMQ, although it should be compatible with any
11
13
  server implementing the AMQP 0-8 spec.
12
14
 
@@ -86,6 +88,7 @@ AMQP resources:
86
88
  http://hg.rabbitmq.com/rabbitmq-codegen/
87
89
 
88
90
  Erlang Exchange presentation on the implementation of RabbitMQ
91
+ http://skillsmatter.com/podcast/erlang/presenting-rabbitmq-an-erlang-based-implementatio-nof-amqp
89
92
  http://www.lshift.net/blog/2008/07/01/slides-from-our-erlang-exchange-talk
90
93
 
91
94
  Jonathan Conway's series on RabbitMQ and using it with Ruby/Merb
@@ -113,5 +116,8 @@ Messaging and distributed systems resources:
113
116
  Metaprotocol Taxonomy and Communications Patterns
114
117
  http://hessian.caucho.com/doc/metaprotocol-taxonomy.xtp
115
118
 
116
- Joe Armstrong on Erlang messaging vs RPC:
119
+ Joe Armstrong on Erlang messaging vs RPC
117
120
  http://armstrongonsoftware.blogspot.com/2008/05/road-we-didnt-go-down.html
121
+
122
+ SEDA: scalable internet services using message queues
123
+ http://www.eecs.harvard.edu/~mdw/papers/seda-sosp01.pdf
@@ -1,74 +1,13 @@
1
1
  $:.unshift File.dirname(__FILE__) + '/../../lib'
2
2
  require 'mq'
3
+ require 'mq/logger'
3
4
 
4
- class Logger
5
- def initialize *args, &block
6
- opts = args.pop if args.last.is_a? Hash
7
- opts ||= {}
8
- printer(block) if block
9
- @log = []
10
- @tags = ([:timestamp] + args).uniq
11
- end
12
-
13
- def log severity, *args
14
- opts = args.pop if args.last.is_a? Hash and args.size != 1
15
- opts ||= {}
16
- data = args.shift
17
-
18
- data = {:type => :exception,
19
- :name => data.class.to_s.intern,
20
- :backtrace => data.backtrace,
21
- :message => data.message} if data.is_a? Exception
22
-
23
- (@tags + args).each do |tag|
24
- tag = tag.to_sym
25
- case tag
26
- when :timestamp
27
- opts.update :timestamp => Time.now.to_i
28
- when :hostname
29
- @hostname ||= { :hostname => `hostname`.strip }
30
- opts.update @hostname
31
- when :process
32
- @process_id ||= { :process_id => Process.pid,
33
- :process_name => $0,
34
- :process_parent_id => Process.ppid,
35
- :thread_id => Thread.current.object_id }
36
- opts.update :process => @process_id
37
- else
38
- (opts[:tags] ||= []) << tag
39
- end
40
- end
41
-
42
- opts.update(:severity => severity,
43
- :data => data)
44
-
45
- print(opts)
46
- MQ.queue('logger', :durable => true).publish(Marshal.dump(opts), :persistent => true)
47
- opts
48
- end
49
- alias :method_missing :log
50
-
51
- def print data = nil, &block
52
- if block
53
- @printer = block
54
- elsif data.is_a? Proc
55
- @printer = data
56
- elsif @printer and data
57
- @printer.call(data)
58
- else
59
- @printer
60
- end
61
- end
62
- alias :printer :print
63
- end
5
+ Logger = MQ::Logger
64
6
 
65
7
  EM.run{
66
- # AMQP.logging = true
67
- # MQ.logging = true
68
-
69
8
  if ARGV[0] == 'server'
70
9
 
71
- MQ.queue('logger', :durable => true).subscribe{|msg|
10
+ MQ.queue('logger').bind(MQ.fanout('logging', :durable => true)).subscribe{|msg|
72
11
  msg = Marshal.load(msg)
73
12
  require 'pp'
74
13
  pp(msg)
@@ -7,50 +7,52 @@ EM.run{
7
7
  p [ Time.now, *args ]
8
8
  end
9
9
 
10
- # AMQP.logging = true
11
-
12
- EM.add_periodic_timer(1){
13
- puts
14
-
15
- log :publishing, 'stock.usd.appl', price = 170+rand(1000)/100.0
16
- MQ.topic.publish(price, :key => 'stock.usd.appl', :headers => {:symbol => 'appl'})
17
-
18
- log :publishing, 'stock.usd.msft', price = 22+rand(500)/100.0
19
- MQ.topic.publish(price, :key => 'stock.usd.msft', :headers => {:symbol => 'msft'})
20
- }
10
+ def publish_stock_prices
11
+ mq = MQ.new
12
+ EM.add_periodic_timer(1){
13
+ puts
14
+
15
+ { :appl => 170+rand(1000)/100.0,
16
+ :msft => 22+rand(500)/100.0
17
+ }.each do |stock, price|
18
+ stock = "usd.#{stock}"
19
+
20
+ log :publishing, stock, price
21
+ mq.topic('stocks').publish(price, :key => stock)
22
+ end
23
+ }
24
+ end
21
25
 
22
- Thread.new{
23
- amq = MQ.new
24
- amq.queue('apple stock').bind(amq.topic, :key => 'stock.usd.appl').subscribe{ |price|
26
+ def watch_appl_stock
27
+ mq = MQ.new
28
+ mq.queue('apple stock').bind(mq.topic('stocks'), :key => 'usd.appl').subscribe{ |price|
25
29
  log 'apple stock', price
26
30
  }
27
- }
31
+ end
28
32
 
29
- Thread.new{
30
- amq = MQ.new
31
- amq.queue('us stocks').bind(amq.topic, :key => 'stock.usd.*').subscribe{ |info, price|
32
- log 'us stock', info.headers[:symbol], price
33
+ def watch_us_stocks
34
+ mq = MQ.new
35
+ mq.queue('us stocks').bind(mq.topic('stocks'), :key => 'usd.*').subscribe{ |info, price|
36
+ log 'us stock', info.routing_key, price
33
37
  }
34
- }
38
+ end
39
+
40
+ publish_stock_prices
41
+ watch_appl_stock
42
+ watch_us_stocks
35
43
 
36
44
  }
37
45
 
38
46
  __END__
39
47
 
40
- [Thu Jul 17 14:51:07 -0700 2008, :publishing, "stock.usd.appl", 170.84]
41
- [Thu Jul 17 14:51:07 -0700 2008, :publishing, "stock.usd.msft", 23.68]
42
- [Thu Jul 17 14:51:07 -0700 2008, "apple stock", "170.84"]
43
- [Thu Jul 17 14:51:07 -0700 2008, "us stock", "appl", "170.84"]
44
- [Thu Jul 17 14:51:07 -0700 2008, "us stock", "msft", "23.68"]
45
-
46
- [Thu Jul 17 14:51:08 -0700 2008, :publishing, "stock.usd.appl", 173.61]
47
- [Thu Jul 17 14:51:08 -0700 2008, :publishing, "stock.usd.msft", 25.8]
48
- [Thu Jul 17 14:51:08 -0700 2008, "apple stock", "173.61"]
49
- [Thu Jul 17 14:51:08 -0700 2008, "us stock", "appl", "173.61"]
50
- [Thu Jul 17 14:51:08 -0700 2008, "us stock", "msft", "25.8"]
51
-
52
- [Thu Jul 17 14:51:09 -0700 2008, :publishing, "stock.usd.appl", 173.94]
53
- [Thu Jul 17 14:51:09 -0700 2008, :publishing, "stock.usd.msft", 24.88]
54
- [Thu Jul 17 14:51:09 -0700 2008, "apple stock", "173.94"]
55
- [Thu Jul 17 14:51:09 -0700 2008, "us stock", "appl", "173.94"]
56
- [Thu Jul 17 14:51:09 -0700 2008, "us stock", "msft", "24.88"]
48
+ [Fri Aug 15 01:39:00 -0700 2008, :publishing, "usd.appl", 173.45]
49
+ [Fri Aug 15 01:39:00 -0700 2008, :publishing, "usd.msft", 26.98]
50
+ [Fri Aug 15 01:39:00 -0700 2008, "apple stock", "173.45"]
51
+ [Fri Aug 15 01:39:00 -0700 2008, "us stock", "usd.appl", "173.45"]
52
+ [Fri Aug 15 01:39:00 -0700 2008, "us stock", "usd.msft", "26.98"]
53
+
54
+ [Fri Aug 15 01:39:01 -0700 2008, :publishing, "usd.appl", 179.72]
55
+ [Fri Aug 15 01:39:01 -0700 2008, :publishing, "usd.msft", 26.56]
56
+ [Fri Aug 15 01:39:01 -0700 2008, "apple stock", "179.72"]
57
+ [Fri Aug 15 01:39:01 -0700 2008, "us stock", "usd.appl", "179.72"]
58
+ [Fri Aug 15 01:39:01 -0700 2008, "us stock", "usd.msft", "26.56"]
@@ -1,5 +1,5 @@
1
1
  module AMQP
2
- VERSION = '0.5.5'
2
+ VERSION = '0.5.9'
3
3
 
4
4
  DIR = File.expand_path(File.dirname(File.expand_path(__FILE__)))
5
5
  $:.unshift DIR
@@ -14,6 +14,8 @@ module AMQP
14
14
  class << self
15
15
  @logging = false
16
16
  attr_accessor :logging
17
+ attr_reader :conn
18
+ alias :connection :conn
17
19
  end
18
20
 
19
21
  def self.connect *args
@@ -22,9 +24,19 @@ module AMQP
22
24
 
23
25
  def self.settings
24
26
  @settings ||= {
27
+ # server address
28
+ :host => '127.0.0.1',
29
+ :port => PORT,
30
+
31
+ # login details
25
32
  :user => 'guest',
26
33
  :pass => 'guest',
27
34
  :vhost => '/',
35
+
36
+ # connection timeout
37
+ :timeout => nil,
38
+
39
+ # logging
28
40
  :logging => false
29
41
  }
30
42
  end
@@ -41,4 +53,12 @@ module AMQP
41
53
  }
42
54
  end
43
55
  end
56
+
57
+ def self.run *args
58
+ EM.run{
59
+ AMQP.start(*args).callback{
60
+ yield
61
+ }
62
+ }
63
+ end
44
64
  end
@@ -60,21 +60,34 @@ module AMQP
60
60
  def initialize opts = {}
61
61
  @settings = opts
62
62
  extend AMQP.client
63
+
64
+ @on_disconnect = proc{ raise Error, "Could not connect to server #{opts[:host]}:#{opts[:port]}" }
65
+
66
+ timeout @settings[:timeout] if @settings[:timeout]
67
+ errback{ @on_disconnect.call }
63
68
  end
64
69
 
65
70
  def connection_completed
66
71
  log 'connected'
72
+ @on_disconnect = proc{ raise Error, 'Disconnected from server' }
67
73
  @buf = Buffer.new
68
74
  send_data HEADER
69
75
  send_data [1, 1, VERSION_MAJOR, VERSION_MINOR].pack('C4')
70
76
  end
71
77
 
78
+ def unbind
79
+ log 'disconnected'
80
+ @on_disconnect.call unless $!
81
+ end
82
+
72
83
  def add_channel mq
73
- channels[ key = (channels.keys.max || 0) + 1 ] = mq
74
- key
84
+ (@_channel_mutex ||= Mutex.new).synchronize do
85
+ channels[ key = (channels.keys.max || 0) + 1 ] = mq
86
+ key
87
+ end
75
88
  end
76
89
 
77
- def channels mq = nil
90
+ def channels
78
91
  @channels ||= {}
79
92
  end
80
93
 
@@ -111,8 +124,8 @@ module AMQP
111
124
  @on_disconnect = on_disconnect if on_disconnect
112
125
 
113
126
  callback{ |c|
114
- if c.channels.keys.any?
115
- c.channels.each do |_, mq|
127
+ if c.channels.any?
128
+ c.channels.each do |ch, mq|
116
129
  mq.close
117
130
  end
118
131
  else
@@ -123,16 +136,9 @@ module AMQP
123
136
  end
124
137
  }
125
138
  end
126
-
127
- def unbind
128
- log 'disconnected'
129
- end
130
139
 
131
140
  def self.connect opts = {}
132
141
  opts = AMQP.settings.merge(opts)
133
- opts[:host] ||= '127.0.0.1'
134
- opts[:port] ||= PORT
135
-
136
142
  EM.connect opts[:host], opts[:port], self, opts
137
143
  end
138
144
 
@@ -1,6 +1,6 @@
1
1
 
2
- # this file was autogenerated on Sun Jul 20 04:06:05 -0700 2008
3
- # using amqp-0.8.json (mtime: Wed Jul 16 12:10:42 -0700 2008)
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)
4
4
  #
5
5
  # DO NOT EDIT! (edit protocol/codegen.rb instead, and run `rake codegen`)
6
6
 
@@ -340,6 +340,8 @@ module AMQP
340
340
  class PurgeOk < Method( 31, :purge_ok ); end
341
341
  class Delete < Method( 40, :delete ); end
342
342
  class DeleteOk < Method( 41, :delete_ok ); end
343
+ class Unbind < Method( 50, :unbind ); end
344
+ class UnbindOk < Method( 51, :unbind_ok ); end
343
345
 
344
346
  class Declare
345
347
  short :ticket
@@ -392,6 +394,17 @@ module AMQP
392
394
  long :message_count
393
395
  end
394
396
 
397
+ class Unbind
398
+ short :ticket
399
+ shortstr :queue
400
+ shortstr :exchange
401
+ shortstr :routing_key
402
+ table :arguments
403
+ end
404
+
405
+ class UnbindOk
406
+ end
407
+
395
408
  end
396
409
 
397
410
  class Basic
data/lib/mq.rb CHANGED
@@ -43,7 +43,7 @@ class MQ
43
43
  if @body.length >= @header.size
44
44
  @header.properties.update(@method.arguments)
45
45
  @consumer.receive @header, @body
46
- @body = ''
46
+ @body = @header = @consumer = @method = nil
47
47
  end
48
48
 
49
49
  when Frame::Method
@@ -70,25 +70,28 @@ class MQ
70
70
  @body = ''
71
71
  @consumer = queues[ method.consumer_tag ]
72
72
 
73
-
74
73
  when Protocol::Channel::Close
75
- raise Error, "#{method.reply_text} in #{Protocol.classes[method.class_id].methods[method.method_id]}"
74
+ raise Error, "#{method.reply_text} in #{Protocol.classes[method.class_id].methods[method.method_id]} on #{@channel}"
76
75
 
77
76
  when Protocol::Channel::CloseOk
78
77
  @closing = false
79
78
  conn.callback{ |c|
80
- c.channels.delete(@channel)
81
- c.close unless c.channels.keys.any?
79
+ c.channels.delete @channel
80
+ c.close if c.channels.empty?
82
81
  }
83
82
  end
84
83
  end
85
84
  end
86
85
 
87
- def send data
88
- data.ticket = @ticket if @ticket and data.respond_to? :ticket
86
+ def send *args
89
87
  conn.callback{ |c|
90
- log :sending, data
91
- c.send data, :channel => @channel
88
+ (@_send_mutex ||= Mutex.new).synchronize do
89
+ args.each do |data|
90
+ data.ticket = @ticket if @ticket and data.respond_to? :ticket=
91
+ log :sending, data
92
+ c.send data, :channel => @channel
93
+ end
94
+ end
92
95
  }
93
96
  end
94
97
 
@@ -145,10 +148,11 @@ class MQ
145
148
  alias :conn :connection
146
149
  end
147
150
 
148
- # convenience wrapper for thread-local MQ object
151
+ # convenience wrapper (read: HACK) for thread-local MQ object
149
152
 
150
153
  class MQ
151
154
  def MQ.default
155
+ # XXX clear this when connection is closed
152
156
  Thread.current[:mq] ||= MQ.new
153
157
  end
154
158
 
@@ -18,16 +18,21 @@ class MQ
18
18
 
19
19
  def publish data, opts = {}
20
20
  @mq.callback{
21
- @mq.send Protocol::Basic::Publish.new({ :exchange => name,
22
- :routing_key => opts.delete(:key) || @key }.merge(opts))
21
+ out = []
22
+
23
+ out << Protocol::Basic::Publish.new({ :exchange => name,
24
+ :routing_key => opts.delete(:key) || @key }.merge(opts))
23
25
 
24
26
  data = data.to_s
25
27
 
26
- @mq.send Protocol::Header.new(Protocol::Basic,
27
- data.length, { :content_type => 'application/octet-stream',
28
- :delivery_mode => (opts.delete(:persistent) ? 2 : 1),
29
- :priority => 0 }.merge(opts))
30
- @mq.send Frame::Body.new(data)
28
+ out << Protocol::Header.new(Protocol::Basic,
29
+ data.length, { :content_type => 'application/octet-stream',
30
+ :delivery_mode => (opts.delete(:persistent) ? 2 : 1),
31
+ :priority => 0 }.merge(opts))
32
+
33
+ out << Frame::Body.new(data)
34
+
35
+ @mq.send *out
31
36
  }
32
37
  self
33
38
  end
@@ -0,0 +1,75 @@
1
+ class MQ
2
+ class Logger
3
+ def initialize *args, &block
4
+ opts = args.pop if args.last.is_a? Hash
5
+ opts ||= {}
6
+
7
+ printer(block) if block
8
+
9
+ @prop = opts
10
+ @tags = ([:timestamp] + args).uniq
11
+ end
12
+
13
+ attr_reader :prop
14
+ alias :base :prop
15
+
16
+ def log severity, *args
17
+ opts = args.pop if args.last.is_a? Hash and args.size != 1
18
+ opts ||= {}
19
+ opts = @prop.clone.update(opts)
20
+
21
+ data = args.shift
22
+
23
+ data = {:type => :exception,
24
+ :name => data.class.to_s.intern,
25
+ :backtrace => data.backtrace,
26
+ :message => data.message} if data.is_a? Exception
27
+
28
+ (@tags + args).each do |tag|
29
+ tag = tag.to_sym
30
+ case tag
31
+ when :timestamp
32
+ opts.update :timestamp => Time.now
33
+ when :hostname
34
+ @hostname ||= { :hostname => `hostname`.strip }
35
+ opts.update @hostname
36
+ when :process
37
+ @process_id ||= { :process_id => Process.pid,
38
+ :process_name => $0,
39
+ :process_parent_id => Process.ppid,
40
+ :thread_id => Thread.current.object_id }
41
+ opts.update :process => @process_id
42
+ else
43
+ (opts[:tags] ||= []) << tag
44
+ end
45
+ end
46
+
47
+ opts.update(:severity => severity,
48
+ :msg => data)
49
+
50
+ print(opts)
51
+ MQ.fanout('logging', :durable => true).publish Marshal.dump(opts)
52
+
53
+ opts
54
+ end
55
+ alias :method_missing :log
56
+
57
+ def print data = nil, &block
58
+ if block
59
+ @printer = block
60
+ elsif data.is_a? Proc
61
+ @printer = data
62
+ elsif data
63
+ (pr = @printer || self.class.printer) and pr.call(data)
64
+ else
65
+ @printer
66
+ end
67
+ end
68
+ alias :printer :print
69
+
70
+ def self.printer &block
71
+ @printer = block if block
72
+ @printer
73
+ end
74
+ end
75
+ end
@@ -21,6 +21,25 @@ class MQ
21
21
  }
22
22
  self
23
23
  end
24
+
25
+ def unbind exchange, opts = {}
26
+ @mq.callback{
27
+ @mq.send Protocol::Queue::Unbind.new({ :queue => name,
28
+ :exchange => exchange.respond_to?(:name) ? exchange.name : exchange,
29
+ :routing_key => opts.delete(:key),
30
+ :nowait => true }.merge(opts))
31
+ }
32
+ self
33
+ end
34
+
35
+ def delete opts = {}
36
+ @mq.callback{
37
+ @mq.send Protocol::Queue::Delete.new({ :queue => name,
38
+ :nowait => true }.merge(opts))
39
+ }
40
+ @mq.queues.delete @name
41
+ nil
42
+ end
24
43
 
25
44
  def subscribe opts = {}, &blk
26
45
  @on_msg = blk
@@ -275,7 +275,18 @@
275
275
  "name": "delete"},
276
276
  {"id": 41,
277
277
  "arguments": [{"type": "long", "name": "message-count"}],
278
- "name": "delete-ok"}],
278
+ "name": "delete-ok"},
279
+ {"id": 50,
280
+ "arguments": [{"type": "short", "name": "ticket"},
281
+ {"type": "shortstr", "name": "queue"},
282
+ {"type": "shortstr", "name": "exchange"},
283
+ {"type": "shortstr", "name": "routing-key"},
284
+ {"type": "table", "name": "arguments"}],
285
+ "name": "unbind"},
286
+ {"id": 51,
287
+ "arguments": [],
288
+ "name": "unbind-ok"}
289
+ ],
279
290
  "name": "queue"
280
291
  },
281
292
  {
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: amqp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.5
4
+ version: 0.5.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aman Gupta
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2008-08-01 00:00:00 -07:00
12
+ date: 2008-09-01 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -51,6 +51,7 @@ files:
51
51
  - lib/ext/em.rb
52
52
  - lib/ext/emfork.rb
53
53
  - lib/mq/exchange.rb
54
+ - lib/mq/logger.rb
54
55
  - lib/mq/queue.rb
55
56
  - lib/mq/rpc.rb
56
57
  - lib/mq.rb