reliable-msg 1.0.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/MIT-LICENSE +20 -0
- data/README +123 -0
- data/Rakefile +164 -0
- data/bin/queues +8 -0
- data/lib/reliable-msg.rb +12 -0
- data/lib/reliable-msg/cli.rb +170 -0
- data/lib/reliable-msg/message-store.rb +509 -0
- data/lib/reliable-msg/mysql.sql +8 -0
- data/lib/reliable-msg/queue-manager.rb +409 -0
- data/lib/reliable-msg/queue.rb +500 -0
- data/lib/reliable-msg/selector.rb +109 -0
- data/lib/uuid.rb +384 -0
- data/test/test-queue.rb +144 -0
- data/test/test-uuid.rb +48 -0
- metadata +63 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2005 Assaf Arkin
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
= Reliable Messaging for Ruby
|
2
|
+
|
3
|
+
This package provides reliable messaging and persistent queues for
|
4
|
+
building asynchronous applications in Ruby.
|
5
|
+
|
6
|
+
This release provides the following features:
|
7
|
+
|
8
|
+
* Simple API.
|
9
|
+
|
10
|
+
* Transction processing.
|
11
|
+
|
12
|
+
* Disk-based and MySQL message stores.
|
13
|
+
|
14
|
+
* Best effort, repeated and once-only delivery semantics.
|
15
|
+
|
16
|
+
* Priority queues, message expiration, dead-letter queue.
|
17
|
+
|
18
|
+
* Message selectors.
|
19
|
+
|
20
|
+
* Local and remote queue managers using DRb.
|
21
|
+
|
22
|
+
|
23
|
+
== Download
|
24
|
+
|
25
|
+
The latest version of Reliable Messaging can be found at
|
26
|
+
|
27
|
+
* http://rubyforge.org/projects/reliable-msg/
|
28
|
+
|
29
|
+
For more information (wiki, bug reports)
|
30
|
+
|
31
|
+
* http://trac.labnotes.org/cgi-bin/trac.cgi/wiki/RubyReliableMessaging
|
32
|
+
|
33
|
+
|
34
|
+
== Installation
|
35
|
+
|
36
|
+
You can download the sources directly, or install the GEM package
|
37
|
+
(recommended) with
|
38
|
+
|
39
|
+
gem install --remote reliable-msg
|
40
|
+
|
41
|
+
To create the configuration file and queues for use with the disk-based
|
42
|
+
message store
|
43
|
+
|
44
|
+
queues install disk [<path>]
|
45
|
+
|
46
|
+
The optional <tt>path</tt> argument specifies the directory in which
|
47
|
+
queue index and messages are store. The default directory is
|
48
|
+
<tt>queues</tt>.
|
49
|
+
|
50
|
+
To create the configuration file and queues for use with the MySQL
|
51
|
+
message store
|
52
|
+
|
53
|
+
queues install mysql <host> <user> <password> <database>
|
54
|
+
[--port <port>] [--socket <socket>] [--prefix <prefix>]
|
55
|
+
|
56
|
+
You must have MySQL libraries installed in order to use this message
|
57
|
+
store, either native MySQL libraries or the Rails pure-Ruby adapter.
|
58
|
+
It uses the supplied connection properties and creates tables in your
|
59
|
+
database using the specified prefix. The default prefix is
|
60
|
+
<tt>reliable_msg_</tt>.
|
61
|
+
|
62
|
+
For example
|
63
|
+
|
64
|
+
queues install mysql localhost my-db user secret
|
65
|
+
|
66
|
+
=== Configuration file
|
67
|
+
|
68
|
+
The installation process creates a configuration file
|
69
|
+
(<tt>queues.cfg</tt>) located in the same directory as the library.
|
70
|
+
You can specify a different location for the configuration file using
|
71
|
+
the option <tt>-c</tt> of <tt>--config</tt>.
|
72
|
+
|
73
|
+
When you use the queue manager, it looks for a specified configuration
|
74
|
+
file, or if no configuration file is specified it looks for the
|
75
|
+
<tt>queues.cfg</tt> file, first in the local directory and then in the
|
76
|
+
installation directory. If no file exists, it will create a default one
|
77
|
+
to use the disk-based message store.
|
78
|
+
|
79
|
+
=== UUID state file
|
80
|
+
|
81
|
+
Reliable messaging requires a UUID generator that is able to create
|
82
|
+
universally unique identifiers. The UUID generator uses the
|
83
|
+
<tt>uuid.state</tt> file to hold a unique machine identifier and a
|
84
|
+
rolling sequence number.
|
85
|
+
|
86
|
+
On the first usage, a <tt>uuid.state</tt> file is created in the
|
87
|
+
installation directory. An existing state file will be used if one
|
88
|
+
exists in the local directory or the installation directory.
|
89
|
+
|
90
|
+
The unique machine identifier is obtained from one of the network
|
91
|
+
card's MAC address on your machine, using either the +ipconfig+ or
|
92
|
+
+ifconfig+ commands. If no MAC address can be found, or you want to
|
93
|
+
pick a specific MAC address, create a <tt>uuid.state</tt> file
|
94
|
+
manually.
|
95
|
+
|
96
|
+
|
97
|
+
== Simple Example
|
98
|
+
|
99
|
+
Start the queue manager as a standalone server
|
100
|
+
|
101
|
+
queues manager start
|
102
|
+
|
103
|
+
Use the queue API in your application
|
104
|
+
|
105
|
+
require 'reliable-msg'
|
106
|
+
|
107
|
+
queue = Queue.new 'my-queue'
|
108
|
+
queue.put obj
|
109
|
+
msg = queue.get
|
110
|
+
assert msg.object == obj
|
111
|
+
|
112
|
+
Stop the queue manager
|
113
|
+
|
114
|
+
queues manager stop
|
115
|
+
|
116
|
+
|
117
|
+
== License
|
118
|
+
|
119
|
+
This package is licensed under the MIT license and/or the {Creative
|
120
|
+
Commons Attribution-ShareAlike}[http://creativecommons.org/licenses/by-sa/2.5/legalcode].
|
121
|
+
|
122
|
+
:include: MIT-LICENSE
|
123
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
# Adapted from the rake Rakefile.
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
Gem::manage_gems
|
5
|
+
require 'rake/testtask'
|
6
|
+
require 'rake/rdoctask'
|
7
|
+
require 'rake/gempackagetask'
|
8
|
+
|
9
|
+
|
10
|
+
desc "Default Task"
|
11
|
+
task :default => [:tests, :rdoc]
|
12
|
+
|
13
|
+
|
14
|
+
desc "Run test case for UUID generator"
|
15
|
+
Rake::TestTask.new :test_uuid do |test|
|
16
|
+
test.verbose = true
|
17
|
+
test.test_files = ['test/test-uuid.rb']
|
18
|
+
end
|
19
|
+
desc "Run test case for Queue API generator"
|
20
|
+
Rake::TestTask.new :test_queue do |test|
|
21
|
+
test.verbose = true
|
22
|
+
test.test_files = ['test/test-queue.rb']
|
23
|
+
end
|
24
|
+
desc "Run all test cases"
|
25
|
+
Rake::TestTask.new :tests=>[:test_uuid, :test_queue] do |test|
|
26
|
+
test.verbose = true
|
27
|
+
test.test_files = []
|
28
|
+
#test.warning = true
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
# Create the documentation.
|
33
|
+
Rake::RDocTask.new do |rdoc|
|
34
|
+
rdoc.main = "README"
|
35
|
+
rdoc.rdoc_files.include("README", "lib/**/*.rb")
|
36
|
+
rdoc.title = 'Reliable Messaging'
|
37
|
+
end
|
38
|
+
|
39
|
+
# Handle version number.
|
40
|
+
class Version
|
41
|
+
|
42
|
+
PATTERN = /(\s*)VERSION.*(\d+\.\d+\.\d+)/
|
43
|
+
|
44
|
+
def initialize file, new_version
|
45
|
+
@file = file
|
46
|
+
@version = File.open @file, 'r' do |file|
|
47
|
+
version = nil
|
48
|
+
file.each_line do |line|
|
49
|
+
match = line.match PATTERN
|
50
|
+
if match
|
51
|
+
version = match[2]
|
52
|
+
break
|
53
|
+
end
|
54
|
+
end
|
55
|
+
version
|
56
|
+
end
|
57
|
+
fail "Can't determine version number" unless @version
|
58
|
+
@new_version = new_version || @version
|
59
|
+
end
|
60
|
+
|
61
|
+
def changed?
|
62
|
+
@version != @new_version
|
63
|
+
end
|
64
|
+
|
65
|
+
def number
|
66
|
+
@version
|
67
|
+
end
|
68
|
+
|
69
|
+
def next
|
70
|
+
@new_version
|
71
|
+
end
|
72
|
+
|
73
|
+
def update
|
74
|
+
puts "Updating to version #{@new_version}"
|
75
|
+
copy = "#{@file}.new"
|
76
|
+
open @file, "r" do |input|
|
77
|
+
open copy, "w" do |output|
|
78
|
+
input.each_line do |line|
|
79
|
+
match = line.match PATTERN
|
80
|
+
if match
|
81
|
+
output.puts "#{match[1]}VERSION = '#{@new_version}'"
|
82
|
+
else
|
83
|
+
output.puts line
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
mv copy, @file
|
89
|
+
@version = @new_version
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
93
|
+
version = Version.new 'lib/reliable-msg.rb', ENV['version']
|
94
|
+
|
95
|
+
|
96
|
+
# Create the GEM package.
|
97
|
+
gem_spec = Gem::Specification.new do |spec|
|
98
|
+
spec.name = 'reliable-msg'
|
99
|
+
spec.version = version.next
|
100
|
+
spec.summary = "Reliable messaging and persistent queues for building asynchronous applications in Ruby"
|
101
|
+
spec.description = <<-EOF
|
102
|
+
This package provides reliable messaging and persistent queues for
|
103
|
+
building asynchronous applications in Ruby.
|
104
|
+
|
105
|
+
It supports transaction processing, message selectors, priorities,
|
106
|
+
delivery semantics, remote queue managers, disk-based and MySQL message
|
107
|
+
stores and more.
|
108
|
+
EOF
|
109
|
+
spec.author = "Assaf Arkin"
|
110
|
+
spec.email = "assaf@labnotes.org"
|
111
|
+
spec.homepage = "http://trac.labnotes.org/cgi-bin/trac.cgi/wiki/RubyReliableMessaging"
|
112
|
+
|
113
|
+
spec.files = FileList["{bin,test,lib,docs}/**/*", "README", "MIT-LICENSE", "Rakefile"].to_a
|
114
|
+
spec.require_path = "lib"
|
115
|
+
spec.autorequire = 'reliable-msg.rb'
|
116
|
+
spec.bindir = "bin"
|
117
|
+
spec.executables = ["queues"]
|
118
|
+
spec.default_executable = "queues"
|
119
|
+
spec.requirements << "MySQL for database store, otherwise uses the file system"
|
120
|
+
spec.has_rdoc = true
|
121
|
+
spec.rdoc_options << '--main' << 'README' << '--title' << 'Reliable Messaging for Ruby' << '--line-numbers'
|
122
|
+
spec.extra_rdoc_files = ["README"]
|
123
|
+
end
|
124
|
+
|
125
|
+
gem = Rake::GemPackageTask.new(gem_spec) do |pkg|
|
126
|
+
pkg.need_tar_gz = true
|
127
|
+
pkg.need_zip = true
|
128
|
+
end
|
129
|
+
|
130
|
+
|
131
|
+
desc "Look for TODO and FIXME tags in the code"
|
132
|
+
task :todo do
|
133
|
+
FileList['**/*.rb'].egrep /#.*(FIXME|TODO|TBD)/
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
# --------------------------------------------------------------------
|
138
|
+
# Creating a release
|
139
|
+
|
140
|
+
desc "Make a new release"
|
141
|
+
task :release => [:tests, :prerelease, :clobber, :update_version, :package] do
|
142
|
+
puts
|
143
|
+
puts "**************************************************************"
|
144
|
+
puts "* Release #{version.number} Complete."
|
145
|
+
puts "* Packages ready to upload."
|
146
|
+
puts "**************************************************************"
|
147
|
+
puts
|
148
|
+
end
|
149
|
+
|
150
|
+
task :prerelease do
|
151
|
+
if !version.changed? && ENV['reuse'] != version.number
|
152
|
+
fail "Current version is #{version.number}, must specify reuse=ver to reuse existing version"
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
task :update_version => [:prerelease] do
|
157
|
+
if !version.changed?
|
158
|
+
puts "No version change ... skipping version update"
|
159
|
+
else
|
160
|
+
version.update
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
|
data/bin/queues
ADDED
data/lib/reliable-msg.rb
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
$:.unshift(File.dirname(__FILE__)) unless
|
2
|
+
$:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
module ReliableMsg
|
5
|
+
|
6
|
+
PACKAGE = "reliable-msg"
|
7
|
+
VERSION = '1.0.0'
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
require 'reliable-msg/queue'
|
12
|
+
require 'reliable-msg/cli'
|
@@ -0,0 +1,170 @@
|
|
1
|
+
#
|
2
|
+
# = cli.rb - Reliable messaging command-line interface
|
3
|
+
#
|
4
|
+
# Author:: Assaf Arkin assaf@labnotes.org
|
5
|
+
# Documentation:: http://trac.labnotes.org/cgi-bin/trac.cgi/wiki/RubyReliableMessaging
|
6
|
+
# Copyright:: Copyright (c) 2005 Assaf Arkin
|
7
|
+
# License:: MIT and/or Creative Commons Attribution-ShareAlike
|
8
|
+
#
|
9
|
+
#--
|
10
|
+
# Changes:
|
11
|
+
#++
|
12
|
+
|
13
|
+
|
14
|
+
require 'drb'
|
15
|
+
require 'optparse'
|
16
|
+
require 'rdoc/usage'
|
17
|
+
require 'reliable-msg/queue-manager'
|
18
|
+
|
19
|
+
module ReliableMsg
|
20
|
+
|
21
|
+
class CLI #:nodoc:
|
22
|
+
|
23
|
+
USAGE = <<-EOF
|
24
|
+
usage: queues [-c config] command [args]
|
25
|
+
|
26
|
+
To see list of available commands and options
|
27
|
+
queues help
|
28
|
+
EOF
|
29
|
+
|
30
|
+
HELP = <<-EOF
|
31
|
+
usage: queues [-c config] command [args]
|
32
|
+
|
33
|
+
Reliable messaging queue manager, version #{VERSION}
|
34
|
+
|
35
|
+
Available commands:
|
36
|
+
|
37
|
+
help
|
38
|
+
Display this help message.
|
39
|
+
|
40
|
+
manager start
|
41
|
+
Start the queue manager as a standalone server
|
42
|
+
|
43
|
+
manager stop
|
44
|
+
Stop a running queue manager.
|
45
|
+
|
46
|
+
install disk [<path>]
|
47
|
+
Configure queue manager to use disk-based message store
|
48
|
+
using the specified directory. Uses 'queues' by default.
|
49
|
+
|
50
|
+
install mysql <host> <username> <password> <database> [options]
|
51
|
+
[--port <port>] [--socket <socket>] [--prefix <prefix>]
|
52
|
+
Configure queue manager to use MySQL for message store,
|
53
|
+
using the specified connection properties. Updates database
|
54
|
+
schema.
|
55
|
+
|
56
|
+
Options for install mysql are (defaults apply if missing):
|
57
|
+
|
58
|
+
--port Port to connect to
|
59
|
+
--socket Socket to connect to
|
60
|
+
--prefix Prefix for table names
|
61
|
+
|
62
|
+
EOF
|
63
|
+
|
64
|
+
class InvalidUsage < Exception
|
65
|
+
end
|
66
|
+
|
67
|
+
def initialize
|
68
|
+
end
|
69
|
+
|
70
|
+
def run
|
71
|
+
begin
|
72
|
+
config_file = nil
|
73
|
+
opts = OptionParser.new
|
74
|
+
opts.on("-c FILE", "--config FILE", String) { |value| config_file = value }
|
75
|
+
opts.on("-v", "--version") do
|
76
|
+
puts "Reliable messaging queue manager, version #{VERSION}"
|
77
|
+
exit
|
78
|
+
end
|
79
|
+
opts.on("-h", "--help") do
|
80
|
+
puts HELP
|
81
|
+
exit
|
82
|
+
end
|
83
|
+
|
84
|
+
args = opts.parse(ARGV)
|
85
|
+
|
86
|
+
raise InvalidUsage if args.length < 1
|
87
|
+
case args[0]
|
88
|
+
when 'help'
|
89
|
+
puts HELP
|
90
|
+
|
91
|
+
when 'manager'
|
92
|
+
case args[1]
|
93
|
+
when 'start', nil
|
94
|
+
manager = QueueManager.new({:config=>config_file})
|
95
|
+
manager.start
|
96
|
+
begin
|
97
|
+
while manager.alive?
|
98
|
+
sleep 3
|
99
|
+
end
|
100
|
+
rescue Interrupt
|
101
|
+
manager.stop
|
102
|
+
end
|
103
|
+
when 'stop'
|
104
|
+
if config_file
|
105
|
+
config = Config.new config_file, nil
|
106
|
+
unless config.load_no_create || config_file.nil?
|
107
|
+
puts "Could not find configuration file #{config.path}"
|
108
|
+
exit
|
109
|
+
end
|
110
|
+
drb = Config::DEFAULT_DRB
|
111
|
+
drb.merge(config.drb) if config.drb
|
112
|
+
drb_uri = "druby://localhost:#{drb['port']}"
|
113
|
+
else
|
114
|
+
drb_uri = Queue::DEFAULT_DRB
|
115
|
+
end
|
116
|
+
begin
|
117
|
+
DRbObject.new(nil, drb_uri).stop
|
118
|
+
rescue DRb::DRbConnError =>error
|
119
|
+
puts "No queue manager at #{drb_uri}"
|
120
|
+
end
|
121
|
+
else
|
122
|
+
raise InvalidUsage
|
123
|
+
end
|
124
|
+
|
125
|
+
when 'install'
|
126
|
+
config = Config.new config_file, nil
|
127
|
+
case args[1]
|
128
|
+
when 'disk'
|
129
|
+
store = MessageStore::Disk.new({}, nil)
|
130
|
+
config.store = store.configuration
|
131
|
+
if config.create_if_none
|
132
|
+
store.setup
|
133
|
+
puts "Created queues configuration file: #{config.path}"
|
134
|
+
else
|
135
|
+
puts "Found existing queues configuration file: #{config.path}"
|
136
|
+
puts "No changes made"
|
137
|
+
end
|
138
|
+
when 'mysql'
|
139
|
+
host, username, password, database = args[2], args[3], args[4], args[5]
|
140
|
+
raise InvalidUsage unless host && database && username && password
|
141
|
+
conn = { "host"=>host, "username"=>username, "password"=>password, "database"=>database }
|
142
|
+
store = MessageStore::MySQL.new(conn, nil)
|
143
|
+
config.store = store.configuration
|
144
|
+
if config.create_if_none
|
145
|
+
puts "Created queues configuration file: #{config.path}"
|
146
|
+
if store.setup
|
147
|
+
puts "Created queue manager tables in database '#{database}'"
|
148
|
+
end
|
149
|
+
else
|
150
|
+
puts "Found existing queues configuration file: #{config.path}"
|
151
|
+
puts "No changes made"
|
152
|
+
end
|
153
|
+
else
|
154
|
+
raise InvalidUsage
|
155
|
+
end
|
156
|
+
else
|
157
|
+
raise InvalidUsage
|
158
|
+
end
|
159
|
+
rescue InvalidUsage
|
160
|
+
puts USAGE
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
end
|
165
|
+
|
166
|
+
end
|
167
|
+
|
168
|
+
if __FILE__ == $0
|
169
|
+
ReliableMsg::CLI.new.run
|
170
|
+
end
|