karait 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +13 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +24 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +74 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/lib/karait.rb +5 -0
- data/lib/message.rb +85 -0
- data/lib/queue.rb +123 -0
- data/test/helper.rb +18 -0
- data/test/test_message.rb +124 -0
- data/test/test_queue.rb +214 -0
- metadata +79 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
source "http://rubygems.org"
|
2
|
+
|
3
|
+
gem "mongo", "~> 1.3.1"
|
4
|
+
|
5
|
+
# Add dependencies to develop your gem here.
|
6
|
+
# Include everything needed to run rake, tests, features, etc.
|
7
|
+
group :development do
|
8
|
+
gem "shoulda", ">= 0"
|
9
|
+
gem "bundler", "~> 1.0.0"
|
10
|
+
gem "jeweler", "~> 1.6.4"
|
11
|
+
gem "rcov", ">= 0"
|
12
|
+
end
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
bson (1.3.1)
|
5
|
+
git (1.2.5)
|
6
|
+
jeweler (1.6.4)
|
7
|
+
bundler (~> 1.0)
|
8
|
+
git (>= 1.2.5)
|
9
|
+
rake
|
10
|
+
mongo (1.3.1)
|
11
|
+
bson (>= 1.3.1)
|
12
|
+
rake (0.9.2)
|
13
|
+
rcov (0.9.10)
|
14
|
+
shoulda (2.11.3)
|
15
|
+
|
16
|
+
PLATFORMS
|
17
|
+
ruby
|
18
|
+
|
19
|
+
DEPENDENCIES
|
20
|
+
bundler (~> 1.0.0)
|
21
|
+
jeweler (~> 1.6.4)
|
22
|
+
mongo (~> 1.3.1)
|
23
|
+
rcov
|
24
|
+
shoulda
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 bcoe
|
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.markdown
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
Karait
|
2
|
+
======
|
3
|
+
|
4
|
+
A ridiculously simple queuing system, with clients in various languages, built on top of MongoDB.
|
5
|
+
|
6
|
+
Contributing to karait
|
7
|
+
----------------------
|
8
|
+
|
9
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
10
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
11
|
+
* Fork the project
|
12
|
+
* Start a feature/bugfix branch
|
13
|
+
* Commit and push until you are happy with your contribution
|
14
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
15
|
+
* Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
16
|
+
|
17
|
+
Usage
|
18
|
+
-----
|
19
|
+
|
20
|
+
_Writing to a queue_
|
21
|
+
|
22
|
+
```ruby
|
23
|
+
require 'karait'
|
24
|
+
|
25
|
+
queue = Karait::Queue.new(
|
26
|
+
:host => 'localhost', # MongoDB host. Defaults to localhost.
|
27
|
+
:port => 27017, # MongoDB port. Defaults to 27017.
|
28
|
+
:database => 'karait', # Database that will store the karait queue. Defaults to karait.
|
29
|
+
:queue => 'messages', # The capped collection that karait writes to. Defaults to messages.
|
30
|
+
:average_message_size => 8192, # How big do you expect the messages will be in bytes? Defaults to 8192.
|
31
|
+
:queue_size => 4096 # How many messages should be allowed in the queue. Defaults to 4096.
|
32
|
+
)
|
33
|
+
|
34
|
+
queue.write({
|
35
|
+
:name => 'Benjamin',
|
36
|
+
:action => 'Rock'
|
37
|
+
})
|
38
|
+
|
39
|
+
# or
|
40
|
+
|
41
|
+
message = Karait::Message.new
|
42
|
+
message.name = 'Benjamin'
|
43
|
+
message.action = 'Rock!'
|
44
|
+
|
45
|
+
queue.write(message, :routing_key => 'my_routing_key', :expire => 3.0)
|
46
|
+
```
|
47
|
+
|
48
|
+
_Reading from a queue_
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
require 'karait'
|
52
|
+
|
53
|
+
queue = Karait::Queue.new
|
54
|
+
|
55
|
+
message = queue.read().first
|
56
|
+
print "#{message.name}"
|
57
|
+
|
58
|
+
message.delete
|
59
|
+
|
60
|
+
# or
|
61
|
+
|
62
|
+
message = queue.read(:routing_key => 'my_routing_key').first
|
63
|
+
print "#{message.action}"
|
64
|
+
|
65
|
+
message.delete
|
66
|
+
```
|
67
|
+
|
68
|
+
See unit tests for more documentation.
|
69
|
+
|
70
|
+
Copyright
|
71
|
+
---------
|
72
|
+
|
73
|
+
Copyright (c) 2011 Attachments.me. See LICENSE.txt for
|
74
|
+
further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'bundler'
|
5
|
+
begin
|
6
|
+
Bundler.setup(:default, :development)
|
7
|
+
rescue Bundler::BundlerError => e
|
8
|
+
$stderr.puts e.message
|
9
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
10
|
+
exit e.status_code
|
11
|
+
end
|
12
|
+
require 'rake'
|
13
|
+
|
14
|
+
require 'jeweler'
|
15
|
+
Jeweler::Tasks.new do |gem|
|
16
|
+
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
17
|
+
gem.name = "karait"
|
18
|
+
gem.homepage = "http://github.com/bcoe/karait"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{A ridiculously simple cross-language queuing system, built on top of MongoDB.}
|
21
|
+
gem.description = %Q{A ridiculously simple cross-language queuing system, built on top of MongoDB.}
|
22
|
+
gem.email = "bencoe@gmail.com"
|
23
|
+
gem.authors = ["bcoe"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
end
|
26
|
+
Jeweler::RubygemsDotOrgTasks.new
|
27
|
+
|
28
|
+
require 'rake/testtask'
|
29
|
+
Rake::TestTask.new(:test) do |test|
|
30
|
+
test.libs << 'lib' << 'test'
|
31
|
+
test.pattern = 'test/**/test_*.rb'
|
32
|
+
test.verbose = true
|
33
|
+
end
|
34
|
+
|
35
|
+
require 'rcov/rcovtask'
|
36
|
+
Rcov::RcovTask.new do |test|
|
37
|
+
test.libs << 'test'
|
38
|
+
test.pattern = 'test/**/test_*.rb'
|
39
|
+
test.verbose = true
|
40
|
+
test.rcov_opts << '--exclude "gems/*"'
|
41
|
+
end
|
42
|
+
|
43
|
+
task :default => :test
|
44
|
+
|
45
|
+
require 'rake/rdoctask'
|
46
|
+
Rake::RDocTask.new do |rdoc|
|
47
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
48
|
+
|
49
|
+
rdoc.rdoc_dir = 'rdoc'
|
50
|
+
rdoc.title = "karait #{version}"
|
51
|
+
rdoc.rdoc_files.include('README*')
|
52
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
53
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.1
|
data/lib/karait.rb
ADDED
data/lib/message.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
module Karait
|
2
|
+
class Message
|
3
|
+
|
4
|
+
include Karait
|
5
|
+
|
6
|
+
ASSIGN_VARIABLE_REGEX = /^([a-z_][a-zA-Z_0-9]*)=$/
|
7
|
+
VARIABLE_REGEX = /^([a-z_][a-zA-Z_0-9]*)$/
|
8
|
+
BLACKLIST = {
|
9
|
+
'_meta' => true,
|
10
|
+
'_id' => true,
|
11
|
+
'_expired' => true
|
12
|
+
}
|
13
|
+
|
14
|
+
def initialize(raw_message={}, queue_collection=nil)
|
15
|
+
@source = raw_message
|
16
|
+
@queue_collection = queue_collection
|
17
|
+
@variables_to_serialize = {}
|
18
|
+
set_expired
|
19
|
+
add_accessors raw_message
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_hash
|
23
|
+
return @variables_to_serialize
|
24
|
+
end
|
25
|
+
|
26
|
+
def delete
|
27
|
+
@queue_collection.update(
|
28
|
+
{
|
29
|
+
'_id' => @source['_id']
|
30
|
+
},
|
31
|
+
{
|
32
|
+
'$set' => {
|
33
|
+
'_meta.expired' => true
|
34
|
+
}
|
35
|
+
}
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
def expired?
|
40
|
+
return @expired
|
41
|
+
end
|
42
|
+
|
43
|
+
def get(key)
|
44
|
+
return @variables_to_serialize[key.to_s]
|
45
|
+
end
|
46
|
+
|
47
|
+
def _get_id
|
48
|
+
return @source['_id']
|
49
|
+
end
|
50
|
+
|
51
|
+
private
|
52
|
+
|
53
|
+
def set_expired
|
54
|
+
@expired = false
|
55
|
+
|
56
|
+
current_time = Time.now().to_f
|
57
|
+
meta = @source.fetch('_meta', {})
|
58
|
+
|
59
|
+
return if meta.fetch('expire', -1.0) == -1.0
|
60
|
+
|
61
|
+
if current_time - meta.fetch('timestamp', 0.0) > meta.fetch('expire', -1.0):
|
62
|
+
@expired = true
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def add_accessors(hash)
|
67
|
+
hash.each do |k, v|
|
68
|
+
if not Message::BLACKLIST.has_key? k
|
69
|
+
@variables_to_serialize[k.to_s] = v
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
def method_missing(sym, *args, &block)
|
75
|
+
if matches = sym.to_s.match(Message::ASSIGN_VARIABLE_REGEX) and args.count == 1
|
76
|
+
@variables_to_serialize[matches[1]] = args[0]
|
77
|
+
elsif matches = sym.to_s.match(Message::VARIABLE_REGEX) and args.count == 0
|
78
|
+
return @variables_to_serialize[matches[1]]
|
79
|
+
else
|
80
|
+
super(sym, *args, &block)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
data/lib/queue.rb
ADDED
@@ -0,0 +1,123 @@
|
|
1
|
+
require 'mongo'
|
2
|
+
|
3
|
+
module Karait
|
4
|
+
class Queue
|
5
|
+
|
6
|
+
include Karait
|
7
|
+
|
8
|
+
MESSAGES_READ = 10
|
9
|
+
|
10
|
+
def initialize(opts={})
|
11
|
+
set_instance_variables opts
|
12
|
+
create_mongo_connection
|
13
|
+
end
|
14
|
+
|
15
|
+
def write(message, opts={})
|
16
|
+
if message.class == Hash
|
17
|
+
message_dict = message
|
18
|
+
else
|
19
|
+
message_dict = message.to_hash
|
20
|
+
end
|
21
|
+
|
22
|
+
message_dict[:_meta] = {
|
23
|
+
:expire => opts.fetch(:expire, -1.0),
|
24
|
+
:timestamp => Time.now().to_f,
|
25
|
+
:expired => false
|
26
|
+
}
|
27
|
+
|
28
|
+
message_dict[:_meta][:routing_key] = opts.fetch(:routing_key) if opts[:routing_key]
|
29
|
+
|
30
|
+
@queue_collection.insert(message_dict, :safe => true)
|
31
|
+
end
|
32
|
+
|
33
|
+
def read(opts={})
|
34
|
+
messages = []
|
35
|
+
|
36
|
+
conditions = {
|
37
|
+
'_meta.expired' => false
|
38
|
+
}
|
39
|
+
|
40
|
+
if opts[:routing_key]
|
41
|
+
conditions['_meta.routing_key'] = opts[:routing_key]
|
42
|
+
else
|
43
|
+
conditions['_meta.routing_key'] = {
|
44
|
+
'$exists' => false
|
45
|
+
}
|
46
|
+
end
|
47
|
+
|
48
|
+
@queue_collection.find(conditions).limit(opts.fetch(:messages_read, Queue::MESSAGES_READ)).each do |raw_message|
|
49
|
+
message = Karait::Message.new(raw_message=raw_message, queue_collection=@queue_collection)
|
50
|
+
if message.expired?
|
51
|
+
message.delete()
|
52
|
+
else
|
53
|
+
messages << message
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
return messages
|
58
|
+
end
|
59
|
+
|
60
|
+
def delete_messages(messages)
|
61
|
+
ids = []
|
62
|
+
messages.each {|message| ids << message._get_id}
|
63
|
+
@queue_collection.update(
|
64
|
+
{
|
65
|
+
'_id' => {
|
66
|
+
'$in' => ids
|
67
|
+
}
|
68
|
+
},
|
69
|
+
{
|
70
|
+
'$set' => {
|
71
|
+
'_meta.expired' => true
|
72
|
+
}
|
73
|
+
},
|
74
|
+
:multi => true,
|
75
|
+
:safe => true
|
76
|
+
)
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def set_instance_variables(opts)
|
82
|
+
|
83
|
+
defaults = {
|
84
|
+
:host => 'localhost',
|
85
|
+
:port => 27017,
|
86
|
+
:database => 'karait',
|
87
|
+
:queue => 'messages',
|
88
|
+
:average_message_size => 8192,
|
89
|
+
:queue_size => 4096
|
90
|
+
}.merge(opts)
|
91
|
+
|
92
|
+
@host = defaults[:host]
|
93
|
+
@port = defaults[:port]
|
94
|
+
@database = defaults[:database]
|
95
|
+
@queue = defaults[:queue]
|
96
|
+
@average_message_size = defaults[:average_message_size]
|
97
|
+
@queue_size = defaults[:queue_size]
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
def create_mongo_connection
|
102
|
+
@connection = Mongo::Connection.new(
|
103
|
+
@host,
|
104
|
+
@port
|
105
|
+
)
|
106
|
+
@database = @connection[@database]
|
107
|
+
create_capped_collection
|
108
|
+
@queue_collection = @database[@queue]
|
109
|
+
@queue_collection.create_index('_id')
|
110
|
+
@queue_collection.create_index('_meta.routing_key')
|
111
|
+
end
|
112
|
+
|
113
|
+
def create_capped_collection
|
114
|
+
@database.create_collection(
|
115
|
+
@queue,
|
116
|
+
:size => (@average_message_size * @queue_size),
|
117
|
+
:capped => true,
|
118
|
+
:max => @queue_size
|
119
|
+
)
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
|
13
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
14
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
15
|
+
require 'karait'
|
16
|
+
|
17
|
+
class Test::Unit::TestCase
|
18
|
+
end
|
@@ -0,0 +1,124 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'karait'
|
3
|
+
require 'yaml'
|
4
|
+
|
5
|
+
class TestMessage < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
Mongo::Connection.new()['karait_test']['queue_test'].drop()
|
9
|
+
end
|
10
|
+
|
11
|
+
should "should add attribute accessors when initialized with a raw message" do
|
12
|
+
message = Karait::Message.new(
|
13
|
+
raw_message={
|
14
|
+
:apple => 5,
|
15
|
+
:banana => 3
|
16
|
+
}
|
17
|
+
)
|
18
|
+
|
19
|
+
message.apple = 6
|
20
|
+
assert_equal 6, message.apple
|
21
|
+
assert_equal 3, message.banana
|
22
|
+
end
|
23
|
+
|
24
|
+
should "add new attribute accessors for missing methods" do
|
25
|
+
message = Karait::Message.new
|
26
|
+
message.foo = 9
|
27
|
+
assert_equal 9, message.foo
|
28
|
+
end
|
29
|
+
|
30
|
+
should "return a hash of appropriate instance variables when to_hash is called" do
|
31
|
+
message = Karait::Message.new(
|
32
|
+
raw_message={
|
33
|
+
:apple => 5,
|
34
|
+
:banana => 3
|
35
|
+
}
|
36
|
+
)
|
37
|
+
message.apple = 6
|
38
|
+
message.foo = {'bar' => 9}
|
39
|
+
message.bar = [27]
|
40
|
+
|
41
|
+
hash = message.to_hash
|
42
|
+
|
43
|
+
assert_equal 6, hash['apple']
|
44
|
+
assert_equal 3, hash['banana']
|
45
|
+
assert_equal 9, hash['foo']['bar']
|
46
|
+
assert_equal 27, hash['bar'][0]
|
47
|
+
assert_equal 4, hash.keys.count
|
48
|
+
end
|
49
|
+
|
50
|
+
should "not copy blacklisted keys when to_hash called" do
|
51
|
+
raw_message = {
|
52
|
+
'_id' => 'foobar',
|
53
|
+
'_meta' => {
|
54
|
+
'foo' => 2
|
55
|
+
}
|
56
|
+
}
|
57
|
+
message = Karait::Message.new(raw_message=raw_message)
|
58
|
+
hash = message.to_hash
|
59
|
+
|
60
|
+
assert_equal 0, hash.keys.count
|
61
|
+
end
|
62
|
+
|
63
|
+
should "set expired to true when delete is called on a message" do
|
64
|
+
collection = Mongo::Connection.new()['karait_test']['queue_test']
|
65
|
+
collection.insert({
|
66
|
+
'routing_key' => 'foobar',
|
67
|
+
'apple' => 3,
|
68
|
+
'banana' => 5,
|
69
|
+
'_meta' => {
|
70
|
+
'timestamp' => 2523939,
|
71
|
+
'expire' => 20393,
|
72
|
+
'expired' => false
|
73
|
+
}
|
74
|
+
})
|
75
|
+
raw_message = collection.find_one({'_meta.expired' => false})
|
76
|
+
assert_equal 3, raw_message['apple']
|
77
|
+
message = Karait::Message.new(raw_message=raw_message, queue_collection=collection)
|
78
|
+
message.delete()
|
79
|
+
assert_equal 0, collection.find({'_meta.expired' => false}).count
|
80
|
+
end
|
81
|
+
|
82
|
+
should "set expired to true if current time minus timestamp is greater than expire" do
|
83
|
+
raw_message = {
|
84
|
+
'routing_key' => 'foobar',
|
85
|
+
'apple' => 3,
|
86
|
+
'banana' => 5,
|
87
|
+
'_meta' => {
|
88
|
+
'timestamp' => 0,
|
89
|
+
'expire' => 10,
|
90
|
+
'expired' => false
|
91
|
+
}
|
92
|
+
}
|
93
|
+
|
94
|
+
message = Karait::Message.new(raw_message=raw_message)
|
95
|
+
assert_equal true, message.expired?
|
96
|
+
end
|
97
|
+
|
98
|
+
should "not set expired to true if expire is -1.0" do
|
99
|
+
raw_message = {
|
100
|
+
'routing_key' => 'foobar',
|
101
|
+
'apple' => 3,
|
102
|
+
'banana' => 5,
|
103
|
+
'_meta' => {
|
104
|
+
'timestamp' => 0,
|
105
|
+
'expire' => -1.0,
|
106
|
+
'expired' => false
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
message = Karait::Message.new(raw_message=raw_message)
|
111
|
+
assert_equal false, message.expired?
|
112
|
+
end
|
113
|
+
|
114
|
+
should "allow a get method to be called to retrieve keys that conflict with class variables, e.g., send" do
|
115
|
+
message = Karait::Message.new(
|
116
|
+
raw_message={
|
117
|
+
:send => 5,
|
118
|
+
:banana => 3
|
119
|
+
}
|
120
|
+
)
|
121
|
+
assert_equal 3, message.get(:banana)
|
122
|
+
assert_equal 5, message.get(:send)
|
123
|
+
end
|
124
|
+
end
|
data/test/test_queue.rb
ADDED
@@ -0,0 +1,214 @@
|
|
1
|
+
require 'helper'
|
2
|
+
require 'mongo'
|
3
|
+
require 'karait'
|
4
|
+
|
5
|
+
class TestQueue < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
Mongo::Connection.new()['karait_test']['queue_test'].drop()
|
9
|
+
end
|
10
|
+
|
11
|
+
should "initialize a capped collection when a queue is created" do
|
12
|
+
queue = Karait::Queue.new(
|
13
|
+
:database => 'karait_test',
|
14
|
+
:queue => 'queue_test',
|
15
|
+
:average_message_size => 8192,
|
16
|
+
:queue_size => 4096
|
17
|
+
)
|
18
|
+
|
19
|
+
options = Mongo::Connection.new()['karait_test']['queue_test'].options
|
20
|
+
|
21
|
+
assert_equal true, options['capped']
|
22
|
+
assert_equal 4096, options['max']
|
23
|
+
assert_equal (8192 * 4096), options['size']
|
24
|
+
end
|
25
|
+
|
26
|
+
should "attach to a mongo queue collection that already exists" do
|
27
|
+
collection = Mongo::Connection.new()['karait_test']['queue_test']
|
28
|
+
collection.insert({
|
29
|
+
:message => {
|
30
|
+
:apple => 3,
|
31
|
+
:banana => 5
|
32
|
+
},
|
33
|
+
:_meta => {
|
34
|
+
:timestamp => 2523939,
|
35
|
+
:expire => 20393,
|
36
|
+
:routing_key => 'foo_key'
|
37
|
+
}
|
38
|
+
})
|
39
|
+
assert_equal 1, collection.count()
|
40
|
+
|
41
|
+
queue = Karait::Queue.new(
|
42
|
+
:database => 'karait_test',
|
43
|
+
:queue => 'queue_test'
|
44
|
+
)
|
45
|
+
|
46
|
+
collection = Mongo::Connection.new()['karait_test']['queue_test']
|
47
|
+
assert_equal 1, collection.count()
|
48
|
+
assert_equal nil, collection.options()
|
49
|
+
end
|
50
|
+
|
51
|
+
should "write a dictionary into the mongo queue collection" do
|
52
|
+
queue = Karait::Queue.new(
|
53
|
+
:database => 'karait_test',
|
54
|
+
:queue => 'queue_test',
|
55
|
+
:average_message_size => 8192,
|
56
|
+
:queue_size => 4096
|
57
|
+
)
|
58
|
+
|
59
|
+
queue.write({
|
60
|
+
:apple => 5,
|
61
|
+
:banana => 6,
|
62
|
+
:inner_object => {
|
63
|
+
:foo => 1,
|
64
|
+
:bar => 2
|
65
|
+
}
|
66
|
+
})
|
67
|
+
|
68
|
+
collection = Mongo::Connection.new()['karait_test']['queue_test']
|
69
|
+
obj = collection.find_one()
|
70
|
+
assert_equal 6, obj['banana']
|
71
|
+
assert_equal 2, obj['inner_object']['bar']
|
72
|
+
assert obj['_meta']['expire']
|
73
|
+
assert obj['_meta']['timestamp']
|
74
|
+
end
|
75
|
+
|
76
|
+
should "write a message object into the mongo queue collection" do
|
77
|
+
queue = Karait::Queue.new(
|
78
|
+
:database => 'karait_test',
|
79
|
+
:queue => 'queue_test'
|
80
|
+
)
|
81
|
+
message = Karait::Message.new
|
82
|
+
message.apple = 5
|
83
|
+
message.banana = {
|
84
|
+
:foo => 2
|
85
|
+
}
|
86
|
+
queue.write message
|
87
|
+
|
88
|
+
collection = Mongo::Connection.new()['karait_test']['queue_test']
|
89
|
+
obj = collection.find_one
|
90
|
+
assert_equal 5, obj['apple']
|
91
|
+
assert_equal 2, obj['banana']['foo']
|
92
|
+
end
|
93
|
+
|
94
|
+
should "read a message object from the mongo queue collection" do
|
95
|
+
queue = Karait::Queue.new(
|
96
|
+
:database => 'karait_test',
|
97
|
+
:queue => 'queue_test'
|
98
|
+
)
|
99
|
+
|
100
|
+
write_message = Karait::Message.new
|
101
|
+
write_message.apple = 5
|
102
|
+
write_message.banana = 6
|
103
|
+
write_message.inner_object = {
|
104
|
+
'foo' => 1,
|
105
|
+
'bar' => 2
|
106
|
+
}
|
107
|
+
queue.write write_message
|
108
|
+
|
109
|
+
read_message = queue.read()[0]
|
110
|
+
assert_equal 5, read_message.apple
|
111
|
+
assert_equal 2, read_message.inner_object['bar']
|
112
|
+
assert_equal 3, read_message.to_hash.keys.count
|
113
|
+
end
|
114
|
+
|
115
|
+
should "return messages in lifo order" do
|
116
|
+
queue = Karait::Queue.new(
|
117
|
+
:database => 'karait_test',
|
118
|
+
:queue => 'queue_test'
|
119
|
+
)
|
120
|
+
|
121
|
+
queue.write Karait::Message.new({'foo' => 1})
|
122
|
+
queue.write Karait::Message.new({:foo => 2})
|
123
|
+
queue.write Karait::Message.new({'foo' => 3})
|
124
|
+
messages = queue.read()
|
125
|
+
|
126
|
+
assert_equal 1, messages[0].foo
|
127
|
+
assert_equal 2, messages[1].foo
|
128
|
+
assert_equal 3, messages[2].foo
|
129
|
+
end
|
130
|
+
|
131
|
+
should "only return messages with the appropriate routing key when it's provided" do
|
132
|
+
queue = Karait::Queue.new(
|
133
|
+
:database => 'karait_test',
|
134
|
+
:queue => 'queue_test'
|
135
|
+
)
|
136
|
+
|
137
|
+
queue.write(Karait::Message.new({:foo => 1}), :routing_key => 'foobar')
|
138
|
+
queue.write Karait::Message.new({:foo => 2})
|
139
|
+
|
140
|
+
messages = queue.read(:routing_key => 'foobar')
|
141
|
+
assert_equal 1, messages.count
|
142
|
+
assert_equal 1, messages[0].foo
|
143
|
+
end
|
144
|
+
|
145
|
+
should "only return messages with no routing key when none is provided" do
|
146
|
+
queue = Karait::Queue.new(
|
147
|
+
:database => 'karait_test',
|
148
|
+
:queue => 'queue_test'
|
149
|
+
)
|
150
|
+
|
151
|
+
queue.write(Karait::Message.new({:foo => 1}), :routing_key => 'foobar')
|
152
|
+
queue.write Karait::Message.new({:foo => 2})
|
153
|
+
|
154
|
+
messages = queue.read()
|
155
|
+
assert_equal 1, messages.count
|
156
|
+
assert_equal 2, messages[0].foo
|
157
|
+
end
|
158
|
+
|
159
|
+
should "should no longer return a message when delete is called on it" do
|
160
|
+
queue = Karait::Queue.new(
|
161
|
+
:database => 'karait_test',
|
162
|
+
:queue => 'queue_test'
|
163
|
+
)
|
164
|
+
|
165
|
+
queue.write Karait::Message.new({:foo => 1})
|
166
|
+
messages = queue.read()
|
167
|
+
assert_equal 1, messages.count
|
168
|
+
assert_equal 1, messages[0].foo
|
169
|
+
|
170
|
+
messages[0].delete
|
171
|
+
messages = queue.read()
|
172
|
+
assert_equal 0, messages.count
|
173
|
+
end
|
174
|
+
|
175
|
+
should "not remove message immediately with expire set" do
|
176
|
+
queue = Karait::Queue.new(
|
177
|
+
:database => 'karait_test',
|
178
|
+
:queue => 'queue_test'
|
179
|
+
)
|
180
|
+
|
181
|
+
queue.write(Karait::Message.new({:foo => 1}), :expire => 0.5)
|
182
|
+
sleep(0.1)
|
183
|
+
messages = queue.read()
|
184
|
+
assert_equal 1, messages.count
|
185
|
+
end
|
186
|
+
|
187
|
+
should "remove message once expire time is passed" do
|
188
|
+
queue = Karait::Queue.new(
|
189
|
+
:database => 'karait_test',
|
190
|
+
:queue => 'queue_test'
|
191
|
+
)
|
192
|
+
|
193
|
+
queue.write(Karait::Message.new({:foo => 1}), :expire => 0.1)
|
194
|
+
sleep(0.2)
|
195
|
+
messages = queue.read()
|
196
|
+
assert_equal 0, messages.count
|
197
|
+
end
|
198
|
+
|
199
|
+
|
200
|
+
should "remove all messages in array when delete messages called" do
|
201
|
+
queue = Karait::Queue.new(
|
202
|
+
:database => 'karait_test',
|
203
|
+
:queue => 'queue_test'
|
204
|
+
)
|
205
|
+
|
206
|
+
queue.write Karait::Message.new({'foo' => 1})
|
207
|
+
queue.write Karait::Message.new({:foo => 2})
|
208
|
+
queue.write Karait::Message.new({'foo' => 3})
|
209
|
+
messages = queue.read()
|
210
|
+
queue.delete_messages messages
|
211
|
+
messages = queue.read()
|
212
|
+
assert_equal 0, messages.count
|
213
|
+
end
|
214
|
+
end
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: karait
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- bcoe
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-08-31 00:00:00 -04:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: A ridiculously simple cross-language queuing system, built on top of MongoDB.
|
23
|
+
email: bencoe@gmail.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files:
|
29
|
+
- README.markdown
|
30
|
+
files:
|
31
|
+
- .gitignore
|
32
|
+
- Gemfile
|
33
|
+
- Gemfile.lock
|
34
|
+
- LICENSE.txt
|
35
|
+
- README.markdown
|
36
|
+
- Rakefile
|
37
|
+
- VERSION
|
38
|
+
- lib/karait.rb
|
39
|
+
- lib/message.rb
|
40
|
+
- lib/queue.rb
|
41
|
+
- test/helper.rb
|
42
|
+
- test/test_message.rb
|
43
|
+
- test/test_queue.rb
|
44
|
+
has_rdoc: true
|
45
|
+
homepage: http://github.com/bcoe/karait
|
46
|
+
licenses:
|
47
|
+
- MIT
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options: []
|
50
|
+
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
none: false
|
55
|
+
requirements:
|
56
|
+
- - ">="
|
57
|
+
- !ruby/object:Gem::Version
|
58
|
+
hash: 3
|
59
|
+
segments:
|
60
|
+
- 0
|
61
|
+
version: "0"
|
62
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
63
|
+
none: false
|
64
|
+
requirements:
|
65
|
+
- - ">="
|
66
|
+
- !ruby/object:Gem::Version
|
67
|
+
hash: 3
|
68
|
+
segments:
|
69
|
+
- 0
|
70
|
+
version: "0"
|
71
|
+
requirements: []
|
72
|
+
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 1.4.2
|
75
|
+
signing_key:
|
76
|
+
specification_version: 3
|
77
|
+
summary: A ridiculously simple cross-language queuing system, built on top of MongoDB.
|
78
|
+
test_files: []
|
79
|
+
|