delay_queue 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +5 -0
- data/.rspec +1 -0
- data/.rvmrc +1 -0
- data/Gemfile +11 -0
- data/Gemfile.lock +45 -0
- data/LICENSE +22 -0
- data/README.md +74 -0
- data/Rakefile +50 -0
- data/VERSION +1 -0
- data/delay_queue.gemspec +67 -0
- data/lib/delay_queue.rb +71 -0
- data/spec/delay_queue_spec.rb +207 -0
- data/spec/spec_helper.rb +15 -0
- metadata +131 -0
data/.document
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm use 1.9.2@delay_queue
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
GEM
|
2
|
+
remote: http://rubygems.org/
|
3
|
+
specs:
|
4
|
+
archive-tar-minitar (0.5.2)
|
5
|
+
columnize (0.3.4)
|
6
|
+
diff-lcs (1.1.3)
|
7
|
+
git (1.2.5)
|
8
|
+
jeweler (1.6.4)
|
9
|
+
bundler (~> 1.0)
|
10
|
+
git (>= 1.2.5)
|
11
|
+
rake
|
12
|
+
linecache19 (0.5.12)
|
13
|
+
ruby_core_source (>= 0.1.4)
|
14
|
+
rake (0.9.2.2)
|
15
|
+
rcov (0.9.11)
|
16
|
+
redis (2.2.2)
|
17
|
+
rspec (2.3.0)
|
18
|
+
rspec-core (~> 2.3.0)
|
19
|
+
rspec-expectations (~> 2.3.0)
|
20
|
+
rspec-mocks (~> 2.3.0)
|
21
|
+
rspec-core (2.3.1)
|
22
|
+
rspec-expectations (2.3.0)
|
23
|
+
diff-lcs (~> 1.1.2)
|
24
|
+
rspec-mocks (2.3.0)
|
25
|
+
ruby-debug-base19 (0.11.25)
|
26
|
+
columnize (>= 0.3.1)
|
27
|
+
linecache19 (>= 0.5.11)
|
28
|
+
ruby_core_source (>= 0.1.4)
|
29
|
+
ruby-debug19 (0.11.6)
|
30
|
+
columnize (>= 0.3.1)
|
31
|
+
linecache19 (>= 0.5.11)
|
32
|
+
ruby-debug-base19 (>= 0.11.19)
|
33
|
+
ruby_core_source (0.1.5)
|
34
|
+
archive-tar-minitar (>= 0.5.2)
|
35
|
+
|
36
|
+
PLATFORMS
|
37
|
+
ruby
|
38
|
+
|
39
|
+
DEPENDENCIES
|
40
|
+
bundler (~> 1.0.0)
|
41
|
+
jeweler (~> 1.6.4)
|
42
|
+
rcov
|
43
|
+
redis (>= 2.2.0)
|
44
|
+
rspec (~> 2.3.0)
|
45
|
+
ruby-debug19
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
Copyright (c) 2011 Daniel W. Nelson
|
3
|
+
Development sponsored by Centresource, Inc.
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
DelayQueue
|
2
|
+
==========
|
3
|
+
|
4
|
+
DelayQueue provides a thread safe, Redis backed queue with two simple properties:
|
5
|
+
|
6
|
+
1. items may be queued with a delay so that they can't be dequeued until some time in the future
|
7
|
+
2. each item in the queue is unique
|
8
|
+
|
9
|
+
|
10
|
+
Use Cases
|
11
|
+
=========
|
12
|
+
|
13
|
+
Throttling
|
14
|
+
----------
|
15
|
+
|
16
|
+
For example, if you want to send notifications to users when something happens, but you don't want users to be flooded with notifications (eg: bug report emails), you could put a user id into a 'bug_notifications' queue every time a bug occurs, setting the dequeue time to @user.last_notified_at + MAX_NOTIFY_FREQUENCY. The uniqueness constraint ensures that the user only gets added once until it is next dequeued, while the time constraint ensures that the user id will only be dequeued once per MAX_NOTIFY_FREQUENCY.
|
17
|
+
|
18
|
+
External Resources
|
19
|
+
------------------
|
20
|
+
|
21
|
+
If you are communicating with an external resource, and that resource is down, you will want to re-queue the job, but you don't want to hit the resource right away. Maybe wait a minute before trying again. If the resource is still down, wait longer. This prevents your system from getting caught up processing jobs that can't complete and is also considerate of the external resource that may be choking under heavy load and won't benefit from a worker continually trying to hit the resource again.
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
Usage
|
26
|
+
=====
|
27
|
+
|
28
|
+
In your Gemfile:
|
29
|
+
|
30
|
+
gem 'delay_queue'
|
31
|
+
|
32
|
+
Example:
|
33
|
+
|
34
|
+
$ irb
|
35
|
+
require 'redis'
|
36
|
+
require 'delay_queue'
|
37
|
+
redis = Redis.new(:host => '127.0.0.1', :port => '6379')
|
38
|
+
queue = DelayQueue.new(redis, 'bug_notification_queue')
|
39
|
+
queue.enqueue('123')
|
40
|
+
queue.dequeue
|
41
|
+
- '123'
|
42
|
+
|
43
|
+
queue.enqueue('123', :delay => 3)
|
44
|
+
queue.dequeue
|
45
|
+
- nil
|
46
|
+
sleep 3
|
47
|
+
queue.dequeue
|
48
|
+
- '123'
|
49
|
+
|
50
|
+
queue.enqueue('123', :until => Time.now + 3)
|
51
|
+
queue.dequeue
|
52
|
+
- nil
|
53
|
+
sleep 3
|
54
|
+
queue.dequeue
|
55
|
+
- '123'
|
56
|
+
|
57
|
+
queue.enqueue('123')
|
58
|
+
queue.enqueue('123')
|
59
|
+
queue.dequeue
|
60
|
+
- '123'
|
61
|
+
queue.dequeue
|
62
|
+
- nil
|
63
|
+
|
64
|
+
|
65
|
+
Contributing to delay_queue
|
66
|
+
==========================
|
67
|
+
|
68
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
69
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
70
|
+
* Fork the project
|
71
|
+
* Start a feature/bugfix branch
|
72
|
+
* Commit and push until you are happy with your contribution
|
73
|
+
* Make sure to add specs for it. This is important so I don't break it in a future version unintentionally.
|
74
|
+
* 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.
|
data/Rakefile
ADDED
@@ -0,0 +1,50 @@
|
|
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 = "delay_queue"
|
18
|
+
gem.homepage = "http://github.com/centresource/delay_queue"
|
19
|
+
gem.license = "MIT"
|
20
|
+
gem.summary = %Q{A thread safe, Redis backed queue with the ability to delay items from being dequeued}
|
21
|
+
gem.description = %Q{A thread safe, Redis backed queue with the ability to delay items from being dequeued}
|
22
|
+
gem.email = "dnelson@centresource.com"
|
23
|
+
gem.authors = ["Daniel Nelson"]
|
24
|
+
# dependencies defined in Gemfile
|
25
|
+
gem.files.exclude 'spec'
|
26
|
+
end
|
27
|
+
Jeweler::RubygemsDotOrgTasks.new
|
28
|
+
|
29
|
+
require 'rspec/core'
|
30
|
+
require 'rspec/core/rake_task'
|
31
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
32
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
33
|
+
end
|
34
|
+
|
35
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
36
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
37
|
+
spec.rcov = true
|
38
|
+
end
|
39
|
+
|
40
|
+
task :default => :spec
|
41
|
+
|
42
|
+
require 'rake/rdoctask'
|
43
|
+
Rake::RDocTask.new do |rdoc|
|
44
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
45
|
+
|
46
|
+
rdoc.rdoc_dir = 'rdoc'
|
47
|
+
rdoc.title = "delay_queue #{version}"
|
48
|
+
rdoc.rdoc_files.include('README*')
|
49
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
50
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/delay_queue.gemspec
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = "delay_queue"
|
8
|
+
s.version = "0.1.0"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Daniel Nelson"]
|
12
|
+
s.date = "2011-11-04"
|
13
|
+
s.description = "A thread safe, Redis backed queue with the ability to delay items from being dequeued"
|
14
|
+
s.email = "dnelson@centresource.com"
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.md"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".rspec",
|
22
|
+
".rvmrc",
|
23
|
+
"Gemfile",
|
24
|
+
"Gemfile.lock",
|
25
|
+
"LICENSE",
|
26
|
+
"README.md",
|
27
|
+
"Rakefile",
|
28
|
+
"VERSION",
|
29
|
+
"delay_queue.gemspec",
|
30
|
+
"lib/delay_queue.rb",
|
31
|
+
"spec/delay_queue_spec.rb",
|
32
|
+
"spec/spec_helper.rb"
|
33
|
+
]
|
34
|
+
s.homepage = "http://github.com/centresource/delay_queue"
|
35
|
+
s.licenses = ["MIT"]
|
36
|
+
s.require_paths = ["lib"]
|
37
|
+
s.rubygems_version = "1.8.10"
|
38
|
+
s.summary = "A thread safe, Redis backed queue with the ability to delay items from being dequeued"
|
39
|
+
|
40
|
+
if s.respond_to? :specification_version then
|
41
|
+
s.specification_version = 3
|
42
|
+
|
43
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
44
|
+
s.add_runtime_dependency(%q<redis>, [">= 2.2.0"])
|
45
|
+
s.add_development_dependency(%q<rspec>, ["~> 2.3.0"])
|
46
|
+
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
47
|
+
s.add_development_dependency(%q<jeweler>, ["~> 1.6.4"])
|
48
|
+
s.add_development_dependency(%q<rcov>, [">= 0"])
|
49
|
+
s.add_development_dependency(%q<ruby-debug19>, [">= 0"])
|
50
|
+
else
|
51
|
+
s.add_dependency(%q<redis>, [">= 2.2.0"])
|
52
|
+
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
53
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
54
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
55
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
56
|
+
s.add_dependency(%q<ruby-debug19>, [">= 0"])
|
57
|
+
end
|
58
|
+
else
|
59
|
+
s.add_dependency(%q<redis>, [">= 2.2.0"])
|
60
|
+
s.add_dependency(%q<rspec>, ["~> 2.3.0"])
|
61
|
+
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
62
|
+
s.add_dependency(%q<jeweler>, ["~> 1.6.4"])
|
63
|
+
s.add_dependency(%q<rcov>, [">= 0"])
|
64
|
+
s.add_dependency(%q<ruby-debug19>, [">= 0"])
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
data/lib/delay_queue.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
class DelayQueue
|
2
|
+
|
3
|
+
def initialize(redis, queue_name)
|
4
|
+
@redis = redis
|
5
|
+
@queue_name = queue_name
|
6
|
+
@lock_name = 'lock.' + @queue_name
|
7
|
+
end
|
8
|
+
|
9
|
+
def delete_all!
|
10
|
+
@redis.zremrangebyrank(@queue_name, 0, -1)
|
11
|
+
end
|
12
|
+
|
13
|
+
def empty?
|
14
|
+
size == 0
|
15
|
+
end
|
16
|
+
|
17
|
+
def size
|
18
|
+
@redis.zcard(@queue_name)
|
19
|
+
end
|
20
|
+
|
21
|
+
# Enqueue a unique item with an optional delay
|
22
|
+
#
|
23
|
+
# <tt>:item</tt>:: A string
|
24
|
+
# <tt>:options</tt>:: An optional hash of one of the following options
|
25
|
+
# <tt>:until</tt>:: Time before which not to allow this item to be dequeued
|
26
|
+
# <tt>:delay</tt>:: Number of seconds to wait before allowing this to be dequeued
|
27
|
+
#
|
28
|
+
def enqueue(item, options={ :delay => 0})
|
29
|
+
if options[:delay]
|
30
|
+
time = Time.now + options[:delay]
|
31
|
+
elsif options[:until]
|
32
|
+
time = options[:until]
|
33
|
+
end
|
34
|
+
@redis.zadd(@queue_name, time.to_i, item)
|
35
|
+
end
|
36
|
+
|
37
|
+
def dequeue
|
38
|
+
if acquire_lock || break_lock
|
39
|
+
array = @redis.zrangebyscore(@queue_name, 0, Time.now.to_i, :limit => [0, 1])
|
40
|
+
item = array.first if array
|
41
|
+
@redis.zrem(@queue_name, item) if item
|
42
|
+
release_lock
|
43
|
+
item
|
44
|
+
else # couldn't acquire or break the lock. wait and try again
|
45
|
+
sleep 1
|
46
|
+
dequeue
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def acquire_lock # :nodoc:
|
51
|
+
@redis.setnx(@lock_name, new_lock_expiration)
|
52
|
+
end
|
53
|
+
|
54
|
+
def release_lock # :nodoc:
|
55
|
+
@redis.del(@lock_name)
|
56
|
+
end
|
57
|
+
|
58
|
+
def break_lock # :nodoc:
|
59
|
+
previous = @redis.getset(@lock_name, new_lock_expiration)
|
60
|
+
previous.nil? || Time.at(previous.to_i) <= Time.now
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
LOCK_DURATION = 3
|
66
|
+
|
67
|
+
def new_lock_expiration
|
68
|
+
(Time.now + LOCK_DURATION).to_i
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
@@ -0,0 +1,207 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "DelayQueue" do
|
4
|
+
before(:each) do
|
5
|
+
redis = Redis.new(:host => '127.0.0.1', :port => '6379')
|
6
|
+
@queue = DelayQueue.new(redis, 'test_delay_queue')
|
7
|
+
end
|
8
|
+
|
9
|
+
after(:each) do
|
10
|
+
@queue.delete_all!
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#enqueue" do
|
14
|
+
it "should enable the specification of a time before which the item may not be dequeued" do
|
15
|
+
@queue.enqueue('a', :until => Time.now + 2)
|
16
|
+
sleep 1
|
17
|
+
@queue.dequeue.should be_nil
|
18
|
+
sleep 2
|
19
|
+
@queue.dequeue.should == 'a'
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should enable the specification of a delay to wait before releasing the item from the queue" do
|
23
|
+
@queue.enqueue('a', :delay => 2)
|
24
|
+
sleep 1
|
25
|
+
@queue.dequeue.should be_nil
|
26
|
+
sleep 2
|
27
|
+
@queue.dequeue.should == 'a'
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when no options are provided" do
|
31
|
+
it "should not delay the item from being dequeued" do
|
32
|
+
@queue.enqueue('a')
|
33
|
+
@queue.dequeue.should == 'a'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context "enqueing an item more than once" do
|
38
|
+
it "should not add the item a second time" do
|
39
|
+
@queue.enqueue('a')
|
40
|
+
@queue.enqueue('a', :delay => 60)
|
41
|
+
@queue.size.should == 1
|
42
|
+
end
|
43
|
+
|
44
|
+
it "should update the time at which to enable the item to be dequeued" do
|
45
|
+
@queue.enqueue('a')
|
46
|
+
@queue.enqueue('a', :delay => 60)
|
47
|
+
@queue.should_not be_empty
|
48
|
+
@queue.dequeue.should be_nil
|
49
|
+
|
50
|
+
@queue.delete_all!
|
51
|
+
|
52
|
+
@queue.enqueue('a', :delay => 60)
|
53
|
+
@queue.enqueue('a')
|
54
|
+
@queue.dequeue.should == 'a'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
describe "#delete_all!" do
|
60
|
+
it "should remove all elements from the queue, whether or not they are ready to be dequeued" do
|
61
|
+
@queue.enqueue('test')
|
62
|
+
@queue.should_not be_empty
|
63
|
+
@queue.delete_all!
|
64
|
+
@queue.should be_empty
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe "#acquire_lock" do
|
69
|
+
after(:each) do
|
70
|
+
@queue.release_lock
|
71
|
+
end
|
72
|
+
|
73
|
+
context "when the lock is not already taken" do
|
74
|
+
it "should return true" do
|
75
|
+
@queue.acquire_lock.should be_true
|
76
|
+
end
|
77
|
+
|
78
|
+
it "should lock the resource" do
|
79
|
+
@queue.acquire_lock
|
80
|
+
@queue.acquire_lock.should be_false
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "when the lock is already taken" do
|
85
|
+
it "should return false" do
|
86
|
+
@queue.acquire_lock
|
87
|
+
@queue.acquire_lock.should be_false
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
describe "#break_lock" do
|
93
|
+
after(:each) do
|
94
|
+
@queue.release_lock
|
95
|
+
end
|
96
|
+
|
97
|
+
context "when the lock is not already taken" do
|
98
|
+
it "should be true" do
|
99
|
+
@queue.break_lock.should be_true
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should lock the resource" do
|
103
|
+
@queue.break_lock
|
104
|
+
@queue.acquire_lock.should be_false
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
context "when the lock is taken and not yet expired" do
|
109
|
+
it "should be false" do
|
110
|
+
@queue.acquire_lock
|
111
|
+
@queue.break_lock.should be_false
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
context "when the lock is taken, but expired" do
|
116
|
+
it "should be true" do
|
117
|
+
@queue.acquire_lock
|
118
|
+
sleep(3)
|
119
|
+
@queue.break_lock.should be_true
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should lock the resource" do
|
123
|
+
@queue.acquire_lock
|
124
|
+
sleep(3)
|
125
|
+
@queue.break_lock
|
126
|
+
@queue.acquire_lock.should be_false
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should be able to break an expired lock acquired through breaking a lock" do
|
131
|
+
@queue.break_lock
|
132
|
+
sleep(3)
|
133
|
+
@queue.break_lock.should be_true
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe "#dequeue" do
|
138
|
+
context "when the queue is empty" do
|
139
|
+
it "should return nil" do
|
140
|
+
@queue.dequeue.should be_nil
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
context "when the queue has an element that is not ready to be dequeued" do
|
145
|
+
it "should return nil" do
|
146
|
+
@queue.enqueue('a', :delay => 2)
|
147
|
+
@queue.dequeue.should be_nil
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
context "when the queue has an element that is ready to be dequeued" do
|
152
|
+
it "should return that element" do
|
153
|
+
@queue.enqueue('a', :delay => 0)
|
154
|
+
@queue.dequeue.should == 'a'
|
155
|
+
end
|
156
|
+
|
157
|
+
it "should remove that element from the queue" do
|
158
|
+
@queue.enqueue('a', :delay => 0)
|
159
|
+
@queue.dequeue.should == 'a'
|
160
|
+
@queue.should be_empty
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe "#size" do
|
166
|
+
context "when the queue is empty" do
|
167
|
+
it "should be 0" do
|
168
|
+
@queue.size.should == 0
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
context "when the queue has N elements, regardless of whether or not they are ready to be dequeued" do
|
173
|
+
it "should match the number of elements" do
|
174
|
+
@queue.enqueue('a')
|
175
|
+
@queue.size.should == 1
|
176
|
+
|
177
|
+
@queue.enqueue('b', :delay => 60)
|
178
|
+
@queue.size.should == 2
|
179
|
+
|
180
|
+
@queue.enqueue('c')
|
181
|
+
@queue.size.should == 3
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
|
186
|
+
describe "#empty?" do
|
187
|
+
context "when the queue is empty" do
|
188
|
+
it "should be true" do
|
189
|
+
@queue.should be_empty
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
context "when the queue has an element that is not ready to be dequeued" do
|
194
|
+
it "should be false" do
|
195
|
+
@queue.enqueue('a', :delay => 0)
|
196
|
+
@queue.should_not be_empty
|
197
|
+
end
|
198
|
+
end
|
199
|
+
|
200
|
+
context "when the queue has an element that is ready to be dequeued" do
|
201
|
+
it "should be false" do
|
202
|
+
@queue.enqueue('a', :delay => 0)
|
203
|
+
@queue.should_not be_empty
|
204
|
+
end
|
205
|
+
end
|
206
|
+
end
|
207
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
3
|
+
require 'rspec'
|
4
|
+
require 'delay_queue'
|
5
|
+
require 'bundler'
|
6
|
+
Bundler.require
|
7
|
+
require 'ruby-debug'
|
8
|
+
|
9
|
+
# Requires supporting files with custom matchers and macros, etc,
|
10
|
+
# in ./support/ and its subdirectories.
|
11
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
|
12
|
+
|
13
|
+
RSpec.configure do |config|
|
14
|
+
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,131 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: delay_queue
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Daniel Nelson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2011-11-04 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: redis
|
16
|
+
requirement: &2169330560 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.2.0
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *2169330560
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: rspec
|
27
|
+
requirement: &2169330020 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 2.3.0
|
33
|
+
type: :development
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2169330020
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: bundler
|
38
|
+
requirement: &2169329440 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ~>
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: 1.0.0
|
44
|
+
type: :development
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2169329440
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: jeweler
|
49
|
+
requirement: &2169328840 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: 1.6.4
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2169328840
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: rcov
|
60
|
+
requirement: &2169328240 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :development
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *2169328240
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: ruby-debug19
|
71
|
+
requirement: &2169327640 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *2169327640
|
80
|
+
description: A thread safe, Redis backed queue with the ability to delay items from
|
81
|
+
being dequeued
|
82
|
+
email: dnelson@centresource.com
|
83
|
+
executables: []
|
84
|
+
extensions: []
|
85
|
+
extra_rdoc_files:
|
86
|
+
- LICENSE
|
87
|
+
- README.md
|
88
|
+
files:
|
89
|
+
- .document
|
90
|
+
- .rspec
|
91
|
+
- .rvmrc
|
92
|
+
- Gemfile
|
93
|
+
- Gemfile.lock
|
94
|
+
- LICENSE
|
95
|
+
- README.md
|
96
|
+
- Rakefile
|
97
|
+
- VERSION
|
98
|
+
- delay_queue.gemspec
|
99
|
+
- lib/delay_queue.rb
|
100
|
+
- spec/delay_queue_spec.rb
|
101
|
+
- spec/spec_helper.rb
|
102
|
+
homepage: http://github.com/centresource/delay_queue
|
103
|
+
licenses:
|
104
|
+
- MIT
|
105
|
+
post_install_message:
|
106
|
+
rdoc_options: []
|
107
|
+
require_paths:
|
108
|
+
- lib
|
109
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
110
|
+
none: false
|
111
|
+
requirements:
|
112
|
+
- - ! '>='
|
113
|
+
- !ruby/object:Gem::Version
|
114
|
+
version: '0'
|
115
|
+
segments:
|
116
|
+
- 0
|
117
|
+
hash: 4129610326982047189
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
none: false
|
120
|
+
requirements:
|
121
|
+
- - ! '>='
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
requirements: []
|
125
|
+
rubyforge_project:
|
126
|
+
rubygems_version: 1.8.10
|
127
|
+
signing_key:
|
128
|
+
specification_version: 3
|
129
|
+
summary: A thread safe, Redis backed queue with the ability to delay items from being
|
130
|
+
dequeued
|
131
|
+
test_files: []
|