reliable-msg 1.0.1 → 1.1.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
@@ -28,7 +28,7 @@ The latest version of Reliable Messaging can be found at
28
28
 
29
29
  For more information
30
30
 
31
- * http://trac.labnotes.org/cgi-bin/trac.cgi/wiki/RubyReliableMessaging
31
+ * http://trac.labnotes.org/cgi-bin/trac.cgi/wiki/Ruby/ReliableMessaging
32
32
 
33
33
 
34
34
  == Installation
@@ -113,6 +113,10 @@ Stop the queue manager
113
113
 
114
114
  queues manager stop
115
115
 
116
+ == Change log
117
+
118
+ :include: changelog.txt
119
+
116
120
 
117
121
  == License
118
122
 
data/Rakefile CHANGED
@@ -1,30 +1,35 @@
1
1
  # Adapted from the rake Rakefile.
2
2
 
3
- require 'rubygems'
3
+ require "rubygems"
4
4
  Gem::manage_gems
5
- require 'rake/testtask'
6
- require 'rake/rdoctask'
7
- require 'rake/gempackagetask'
5
+ require "rake/testtask"
6
+ require "rake/rdoctask"
7
+ require "rake/gempackagetask"
8
8
 
9
9
 
10
10
  desc "Default Task"
11
11
  task :default => [:tests, :rdoc]
12
12
 
13
13
 
14
- desc "Run test case for UUID generator"
15
- Rake::TestTask.new :test_uuid do |test|
14
+ desc "Run test case for Queue API"
15
+ Rake::TestTask.new :test_queue do |test|
16
16
  test.verbose = true
17
- test.test_files = ['test/test-uuid.rb']
17
+ test.test_files = ["test/test-queue.rb"]
18
18
  end
19
- desc "Run test case for Queue API generator"
20
- Rake::TestTask.new :test_queue do |test|
19
+ desc "Run test case for Topic API"
20
+ Rake::TestTask.new :test_topic do |test|
21
+ test.verbose = true
22
+ test.test_files = ["test/test-topic.rb"]
23
+ end
24
+ desc "Run test case for Rails integration"
25
+ Rake::TestTask.new :test_rails do |test|
21
26
  test.verbose = true
22
- test.test_files = ['test/test-queue.rb']
27
+ test.test_files = ["test/test-rails.rb"]
23
28
  end
24
29
  desc "Run all test cases"
25
- Rake::TestTask.new :tests=>[:test_uuid, :test_queue] do |test|
30
+ Rake::TestTask.new :tests do |test|
26
31
  test.verbose = true
27
- test.test_files = []
32
+ test.test_files = ["test/*.rb"]
28
33
  #test.warning = true
29
34
  end
30
35
 
@@ -33,7 +38,7 @@ end
33
38
  Rake::RDocTask.new do |rdoc|
34
39
  rdoc.main = "README"
35
40
  rdoc.rdoc_files.include("README", "lib/**/*.rb")
36
- rdoc.title = 'Reliable Messaging'
41
+ rdoc.title = "Reliable Messaging"
37
42
  end
38
43
 
39
44
  # Handle version number.
@@ -43,7 +48,7 @@ class Version
43
48
 
44
49
  def initialize file, new_version
45
50
  @file = file
46
- @version = File.open @file, 'r' do |file|
51
+ @version = File.open @file, "r" do |file|
47
52
  version = nil
48
53
  file.each_line do |line|
49
54
  match = line.match PATTERN
@@ -78,7 +83,7 @@ class Version
78
83
  input.each_line do |line|
79
84
  match = line.match PATTERN
80
85
  if match
81
- output.puts "#{match[1]}VERSION = '#{@new_version}'"
86
+ output.puts "#{match[1]}VERSION = \"#{@new_version}\""
82
87
  else
83
88
  output.puts line
84
89
  end
@@ -90,12 +95,12 @@ class Version
90
95
  end
91
96
 
92
97
  end
93
- version = Version.new 'lib/reliable-msg.rb', ENV['version']
98
+ version = Version.new "lib/reliable-msg.rb", ENV["version"]
94
99
 
95
100
 
96
101
  # Create the GEM package.
97
102
  gem_spec = Gem::Specification.new do |spec|
98
- spec.name = 'reliable-msg'
103
+ spec.name = "reliable-msg"
99
104
  spec.version = version.next
100
105
  spec.summary = "Reliable messaging and persistent queues for building asynchronous applications in Ruby"
101
106
  spec.description = <<-EOF
@@ -108,18 +113,20 @@ gem_spec = Gem::Specification.new do |spec|
108
113
  EOF
109
114
  spec.author = "Assaf Arkin"
110
115
  spec.email = "assaf@labnotes.org"
111
- spec.homepage = "http://trac.labnotes.org/cgi-bin/trac.cgi/wiki/RubyReliableMessaging"
116
+ spec.homepage = "http://trac.labnotes.org/cgi-bin/trac.cgi/wiki/Ruby/ReliableMessaging"
112
117
 
113
- spec.files = FileList["{bin,test,lib,docs}/**/*", "README", "MIT-LICENSE", "Rakefile"].to_a
118
+ spec.files = FileList["{bin,test,lib,docs}/**/*", "README", "MIT-LICENSE", "Rakefile", "changelog.txt"].to_a
114
119
  spec.require_path = "lib"
115
- spec.autorequire = 'reliable-msg.rb'
120
+ spec.autorequire = "reliable-msg.rb"
116
121
  spec.bindir = "bin"
117
122
  spec.executables = ["queues"]
118
123
  spec.default_executable = "queues"
119
124
  spec.requirements << "MySQL for database store, otherwise uses the file system"
120
125
  spec.has_rdoc = true
121
- spec.rdoc_options << '--main' << 'README' << '--title' << 'Reliable Messaging for Ruby' << '--line-numbers'
126
+ spec.rdoc_options << "--main" << "README" << "--title" << "Reliable Messaging for Ruby" << "--line-numbers"
122
127
  spec.extra_rdoc_files = ["README"]
128
+ spec.rubyforge_project = "reliable-msg"
129
+ spec.add_dependency(%q<uuid>, [">= 1.0.0"])
123
130
  end
124
131
 
125
132
  gem = Rake::GemPackageTask.new(gem_spec) do |pkg|
@@ -130,7 +137,7 @@ end
130
137
 
131
138
  desc "Look for TODO and FIXME tags in the code"
132
139
  task :todo do
133
- FileList['**/*.rb'].egrep /#.*(FIXME|TODO|TBD)/
140
+ FileList["**/*.rb"].egrep /#.*(FIXME|TODO|TBD)/
134
141
  end
135
142
 
136
143
 
@@ -148,7 +155,7 @@ task :release => [:tests, :prerelease, :clobber, :update_version, :package] do
148
155
  end
149
156
 
150
157
  task :prerelease do
151
- if !version.changed? && ENV['reuse'] != version.number
158
+ if !version.changed? && ENV["reuse"] != version.number
152
159
  fail "Current version is #{version.number}, must specify reuse=ver to reuse existing version"
153
160
  end
154
161
  end
@@ -0,0 +1,32 @@
1
+ Release 1.1.0 (Nov 26, 2005)
2
+
3
+ * Added: Topic class for publishing messages on a topic.
4
+ * Added: Can set delivery option when creating a queue.
5
+ * Added: Queue.name() returns the queue's name.
6
+ * Added: Command line options to list or delete all messages
7
+ in named queue.
8
+ * Added: Rails integration for easily accessing queues/topics
9
+ from a Rails controller.
10
+ * Changed: Quque and Topic both extend the base class Client.
11
+ * Changed: Cannot start two queue managers in the same process.
12
+ * Changed: Each message has a created header indicating date/time
13
+ of creation. Received header no longer exists.
14
+ * Changed: Header retry renamed to delivered, to prevent clash with
15
+ reserved Ruby keyword.
16
+ * Changed: Selectors are now executed in the client process.
17
+ Selectors can rely on client variables, methods and constants.
18
+ * Changed: Specify maximum delivery attempts with the header
19
+ max_deliveries; get the redelivery attempt from the header
20
+ redelivery; the later is only set on the first redelivery attempt.
21
+ * Fixed: Documentation errors in Queue.
22
+ * Removed: Cannot associate default selector with queue.
23
+
24
+
25
+ Release 1.0.1 (Nov 10, 2005)
26
+
27
+ * Added: Test cases test put/get in memory and by reloading.
28
+ * Fixed: Messages not retrieved in order after queue manager
29
+ recovers when using MySQL message store.
30
+ * Fixed: Queue manager fails if stopped and then started again.
31
+
32
+
@@ -1,12 +1,17 @@
1
- $:.unshift(File.dirname(__FILE__)) unless
2
- $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
3
 
4
4
  module ReliableMsg
5
5
 
6
6
  PACKAGE = "reliable-msg"
7
- VERSION = '1.0.1'
7
+ VERSION = "1.1.0"
8
8
 
9
9
  end
10
10
 
11
- require 'reliable-msg/queue'
12
- require 'reliable-msg/cli'
11
+ require "reliable-msg/queue"
12
+ require "reliable-msg/topic"
13
+ require "reliable-msg/cli"
14
+ begin
15
+ require "reliable-msg/rails"
16
+ rescue LoadError
17
+ end
@@ -2,12 +2,11 @@
2
2
  # = cli.rb - Reliable messaging command-line interface
3
3
  #
4
4
  # Author:: Assaf Arkin assaf@labnotes.org
5
- # Documentation:: http://trac.labnotes.org/cgi-bin/trac.cgi/wiki/RubyReliableMessaging
5
+ # Documentation:: http://trac.labnotes.org/cgi-bin/trac.cgi/wiki/Ruby/ReliableMessaging
6
6
  # Copyright:: Copyright (c) 2005 Assaf Arkin
7
7
  # License:: MIT and/or Creative Commons Attribution-ShareAlike
8
8
  #
9
9
  #--
10
- # Changes:
11
10
  #++
12
11
 
13
12
 
@@ -43,6 +42,12 @@ Available commands:
43
42
  manager stop
44
43
  Stop a running queue manager.
45
44
 
45
+ list <queue>
46
+ List headers of messages in the named queue.
47
+
48
+ empty <queue>
49
+ Empty (delete all messages from) the named queue.
50
+
46
51
  install disk [<path>]
47
52
  Configure queue manager to use disk-based message store
48
53
  using the specified directory. Uses 'queues' by default.
@@ -68,7 +73,9 @@ Available options:
68
73
 
69
74
  EOF
70
75
 
71
- class InvalidUsage < Exception
76
+ MAX_STRING = 50
77
+
78
+ class InvalidUsage < Exception #:nodoc:
72
79
  end
73
80
 
74
81
  def initialize
@@ -149,6 +156,43 @@ EOF
149
156
  raise InvalidUsage
150
157
  end
151
158
 
159
+ when 'list'
160
+ queue = args[1]
161
+ raise InvalidUsage unless queue
162
+ begin
163
+ qm = queue_manager(config_file)
164
+ list = qm.list(:queue=>queue)
165
+ puts "Found #{list.size} messages in queue #{queue}"
166
+ list.each do |headers|
167
+ puts "Message #{headers[:id]}"
168
+ headers.each do |name, value|
169
+ unless name==:id
170
+ case value
171
+ when String
172
+ value = value[0..MAX_STRING - 3] << "..." if value.length > MAX_STRING
173
+ value = '"' << value.gsub('"', '\"') << '"'
174
+ when Symbol
175
+ value = ":#{value.to_s}"
176
+ end
177
+ puts " :#{name} => #{value}"
178
+ end
179
+ end
180
+ end
181
+ rescue DRb::DRbConnError =>error
182
+ puts "Cannot access queue manager: is it running?"
183
+ end
184
+
185
+ when 'empty'
186
+ queue = args[1]
187
+ raise InvalidUsage unless queue
188
+ begin
189
+ qm = queue_manager(config_file)
190
+ while msg = qm.enqueue(:queue=>queue)
191
+ end
192
+ rescue DRb::DRbConnError =>error
193
+ puts "Cannot access queue manager: is it running?"
194
+ end
195
+
152
196
  else
153
197
  raise InvalidUsage
154
198
  end
@@ -0,0 +1,213 @@
1
+ #
2
+ # = client.rb - Base class for queue/topic API
3
+ #
4
+ # Author:: Assaf Arkin assaf@labnotes.org
5
+ # Documentation:: http://trac.labnotes.org/cgi-bin/trac.cgi/wiki/Ruby/ReliableMessaging
6
+ # Copyright:: Copyright (c) 2005 Assaf Arkin
7
+ # License:: MIT and/or Creative Commons Attribution-ShareAlike
8
+ #
9
+ #--
10
+ #++
11
+
12
+ require 'drb'
13
+ require 'reliable-msg/selector'
14
+
15
+
16
+ module ReliableMsg
17
+
18
+ # Base class for both Queue and Topic client APIs.
19
+ class Client
20
+
21
+ ERROR_INVALID_SELECTOR = "Selector must be message identifier (String), set of header name/value pairs (Hash), Selector object, or nil" # :nodoc:
22
+
23
+ ERROR_INVALID_TX_TIMEOUT = "Invalid transaction timeout: must be a non-zero positive integer" # :nodoc:
24
+
25
+ ERROR_INVALID_CONNECT_COUNT = "Invalid connection count: must be a non-zero positive integer" # :nodoc:
26
+
27
+ ERROR_SELECTOR_VALUE_OR_BLOCK = "You can either pass a Selector object, or use a block" # :nodoc:
28
+
29
+ ERROR_INVALID_INIT_OPTION = "Unrecognized initialization option %s" #:nodoc:
30
+
31
+ # The default DRb port used to connect to the queue manager.
32
+ DRB_PORT = 6438
33
+
34
+ DEFAULT_DRB_URI = "druby://localhost:#{DRB_PORT}" #:nodoc:
35
+
36
+ # Number of times to retry a connecting to the queue manager.
37
+ DEFAULT_CONNECT_RETRY = 5
38
+
39
+ # Default transaction timeout.
40
+ DEFAULT_TX_TIMEOUT = 120
41
+
42
+ # Thread.current entry for queue transaction.
43
+ THREAD_CURRENT_TX = :reliable_msg_tx #:nodoc:
44
+
45
+ # The name of the dead letter queue (<tt>DLQ</tt>). Messages that expire or fail
46
+ # to process are automatically sent to the dead letter queue.
47
+ DLQ = DEAD_LETTER_QUEUE = "$dlq"
48
+
49
+ # DRb URI for queue manager. You can override this to change the URI globally,
50
+ # for all Queue objects that are not instantiated with an alternative URI.
51
+ @@drb_uri = DEFAULT_DRB_URI
52
+
53
+ # Reference to the local queue manager. Defaults to a DRb object, unless
54
+ # the queue manager is running locally.
55
+ @@qm = nil #:nodoc:
56
+
57
+ # Cache of queue managers referenced by their URI.
58
+ @@qm_cache = {} #:nodoc:
59
+
60
+ # Returns the transaction timeout (in seconds).
61
+ def tx_timeout
62
+ @tx_timeout || DEFAULT_TX_TIMEOUT
63
+ end
64
+
65
+ # Sets the transaction timeout (in seconds). Affects future transactions started
66
+ # by Queue.get. Use +nil+ to restore the default timeout.
67
+ def tx_timeout= timeout
68
+ if timeout
69
+ raise ArgumentError, ERROR_INVALID_TX_TIMEOUT unless timeout.instance_of?(Integer) and timeout > 0
70
+ @tx_timeout = timeout
71
+ else
72
+ @tx_timeout = nil
73
+ end
74
+ end
75
+
76
+ # Returns the number of connection attempts, before operations fail.
77
+ def connect_count
78
+ @connect_count || DEFAULT_CONNECT_RETRY
79
+ end
80
+
81
+ # Sets the number of connection attempts, before operations fail. The minimum is one.
82
+ # Use +nil+ to restore the default connection count.
83
+ def connect_count= count
84
+ if count
85
+ raise ArgumentError, ERROR_INVALID_CONNECT_COUNT unless count.instance_of?(Integer) and count > 0
86
+ @connect_count = count
87
+ else
88
+ @connect_count = nil
89
+ end
90
+ end
91
+
92
+ # Create and return a new selector based on the block expression. Same as
93
+ # Selector.new. For example:
94
+ # selector = Queue.selector { priority >= 2 and received > Time.new.to_i - 60 }
95
+ def self.selector &block
96
+ raise ArgumentError, ERROR_NO_SELECTOR_BLOCK unless block
97
+ Selector.new &block
98
+ end
99
+
100
+ # Create and return a new selector based on the block expression. Same as
101
+ # Selector.new. For example:
102
+ # selector = Queue.selector { priority >= 2 and received > Time.new.to_i - 60 }
103
+ def selector & block
104
+ raise ArgumentError, ERROR_NO_SELECTOR_BLOCK unless block
105
+ Selector.new &block
106
+ end
107
+
108
+ private
109
+
110
+ # Returns the active queue manager. You can override this method to implement
111
+ # load balancing.
112
+ def qm
113
+ if uri = @drb_uri
114
+ # Queue specifies queue manager's URI: use that queue manager.
115
+ @@qm_cache[uri] ||= DRbObject.new(nil, uri)
116
+ else
117
+ # Use the same queue manager for all queues, and cache it.
118
+ # Create only the first time.
119
+ @@qm ||= DRbObject.new(nil, @@drb_uri || DEFAULT_DRB_URI)
120
+ end
121
+ end
122
+
123
+ # Called to execute the operation repeatedly and avoid connection failures. This only
124
+ # makes sense if we have a load balancing algorithm.
125
+ def repeated &block
126
+ count = connect_count
127
+ begin
128
+ block.call qm
129
+ rescue DRb::DRbConnError=>error
130
+ warn error
131
+ warn error.backtrace
132
+ retry if (count -= 1) > 0
133
+ raise error
134
+ end
135
+ end
136
+
137
+ class << self
138
+ private
139
+ # Sets the active queue manager. Used when the queue manager is running in the
140
+ # same process to bypass DRb calls.
141
+ def qm= qm
142
+ @@qm = qm
143
+ end
144
+ end
145
+
146
+ end
147
+
148
+
149
+ # == Retrieved Message
150
+ #
151
+ # Returned from Queue.get holding the last message retrieved from the
152
+ # queue and providing access to the message identifier, headers and object.
153
+ #
154
+ # For example:
155
+ # while queue.get do |msg|
156
+ # print "Message #{msg.id}"
157
+ # print "Headers: #{msg[:created]}"
158
+ # print "Headers: #{msg.headers.inspect}"
159
+ # print msg.object
160
+ # true
161
+ # end
162
+ class Message
163
+
164
+ def initialize id, headers, object # :nodoc:
165
+ @id, @object, @headers = id, object, headers
166
+ end
167
+
168
+ # Returns the message identifier.
169
+ #
170
+ # :call-seq:
171
+ # msg.id -> id
172
+ #
173
+ def id
174
+ @id
175
+ end
176
+
177
+ # Returns the message object.
178
+ #
179
+ # :call-seq:
180
+ # msg.object -> obj
181
+ #
182
+ def object
183
+ @object
184
+ end
185
+
186
+ # Returns the message headers.
187
+ #
188
+ # :call-seq:
189
+ # msg.headers -> hash
190
+ #
191
+ def headers
192
+ @headers
193
+ end
194
+
195
+ # Returns the message header.
196
+ #
197
+ # :call-seq:
198
+ # msg[symbol] -> obj
199
+ #
200
+ def [] symbol
201
+ @headers[symbol]
202
+ end
203
+
204
+ private
205
+ def method_missing symbol, *args, &block
206
+ raise ArgumentError, "Wrong number of arguments (#{args.length} for 0)" unless args.empty?
207
+ @headers[symbol]
208
+ end
209
+
210
+ end
211
+
212
+ end
213
+