refilling_queue 0.0.4 → 0.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.
- checksums.yaml +7 -0
- data/lib/refilling_queue/version.rb +1 -1
- data/lib/refilling_queue.rb +40 -7
- metadata +64 -29
- data/.travis.yml +0 -4
- data/Appraisals +0 -5
- data/Gemfile +0 -8
- data/Gemfile.lock +0 -34
- data/Rakefile +0 -11
- data/Readme.md +0 -34
- data/gemfiles/redis2.gemfile +0 -11
- data/gemfiles/redis2.gemfile.lock +0 -34
- data/gemfiles/redis3.gemfile +0 -11
- data/gemfiles/redis3.gemfile.lock +0 -34
- data/refilling_queue.gemspec +0 -12
- data/spec/refilling_queue_spec.rb +0 -112
- data/spec/spec_helper.rb +0 -3
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: eb46dfea534dbaac56b171c985c0182bb9b766a7
|
4
|
+
data.tar.gz: 432cec3c6c0d9eb76218be864a86a012b4bab0d1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 2e309d6f2d14c1234b0e8bfdbc6bcdd8d67a6e8a42451d63d3f155ee5004a7d1864a00d41ac753149c908098c5caec729e194afc0b7bc03e62f937f7608c6703
|
7
|
+
data.tar.gz: 7050b24da1fd1e3b06098d63c747c20f6218f930fb3f0aff111bd9fd15b8b6e410c2bd76c3db56b54ad563ee6e89d18a3dd33ff477db570fa3fb212d49a33868
|
data/lib/refilling_queue.rb
CHANGED
@@ -6,11 +6,13 @@ class RefillingQueue
|
|
6
6
|
|
7
7
|
DEFAULT_OPTIONS = {
|
8
8
|
:lock_timeout => 60,
|
9
|
-
:refresh_every => nil
|
9
|
+
:refresh_every => nil,
|
10
|
+
:paginate => false
|
10
11
|
}
|
11
12
|
|
12
13
|
def initialize(client, name, options={}, &block)
|
13
14
|
@client, @name, @block = client, name, block
|
15
|
+
@page_name = name + "/page"
|
14
16
|
@options = DEFAULT_OPTIONS.merge(options)
|
15
17
|
raise "Invalid keys" if (options.keys - DEFAULT_OPTIONS.keys).any?
|
16
18
|
end
|
@@ -22,21 +24,48 @@ class RefillingQueue
|
|
22
24
|
_pop
|
23
25
|
end
|
24
26
|
|
27
|
+
def clear
|
28
|
+
lock do
|
29
|
+
mark_as_empty
|
30
|
+
_refill
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
25
34
|
private
|
26
35
|
|
36
|
+
def paginate?
|
37
|
+
@options[:paginate]
|
38
|
+
end
|
39
|
+
|
27
40
|
def _pop
|
28
41
|
@client.lpop @name
|
29
42
|
end
|
30
43
|
|
31
44
|
def refill
|
32
45
|
lock do
|
33
|
-
|
34
|
-
|
46
|
+
_refill
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def _refill
|
51
|
+
results = if paginate?
|
52
|
+
page = (@client.get(@page_name) || 0).to_i
|
53
|
+
@block.call(page + 1)
|
54
|
+
else
|
55
|
+
@block.call
|
56
|
+
end
|
57
|
+
if results.empty?
|
58
|
+
mark_as_empty
|
59
|
+
return
|
60
|
+
end
|
35
61
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
62
|
+
@client.pipelined do
|
63
|
+
@client.del @name
|
64
|
+
@client.rpush @name, results
|
65
|
+
@client.expire @name, @options[:refresh_every] if @options[:refresh_every]
|
66
|
+
if paginate?
|
67
|
+
@client.incr @page_name
|
68
|
+
@client.expire @page_name, @options[:refresh_every] if @options[:refresh_every]
|
40
69
|
end
|
41
70
|
end
|
42
71
|
end
|
@@ -45,6 +74,10 @@ class RefillingQueue
|
|
45
74
|
@client.llen(@name) == 0
|
46
75
|
end
|
47
76
|
|
77
|
+
def mark_as_empty
|
78
|
+
@client.del @page_name if paginate?
|
79
|
+
end
|
80
|
+
|
48
81
|
def lock
|
49
82
|
lock = "#{@name}_lock"
|
50
83
|
|
metadata
CHANGED
@@ -1,67 +1,102 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: refilling_queue
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
5
|
-
prerelease:
|
4
|
+
version: 0.1.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Michael Grosser
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
13
|
-
dependencies:
|
11
|
+
date: 2014-11-08 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: redis
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: bump
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rake
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2'
|
14
69
|
description:
|
15
70
|
email: michael@grosser.it
|
16
71
|
executables: []
|
17
72
|
extensions: []
|
18
73
|
extra_rdoc_files: []
|
19
74
|
files:
|
20
|
-
- .travis.yml
|
21
|
-
- Appraisals
|
22
|
-
- Gemfile
|
23
|
-
- Gemfile.lock
|
24
|
-
- Rakefile
|
25
|
-
- Readme.md
|
26
|
-
- gemfiles/redis2.gemfile
|
27
|
-
- gemfiles/redis2.gemfile.lock
|
28
|
-
- gemfiles/redis3.gemfile
|
29
|
-
- gemfiles/redis3.gemfile.lock
|
30
75
|
- lib/refilling_queue.rb
|
31
76
|
- lib/refilling_queue/version.rb
|
32
|
-
- refilling_queue.gemspec
|
33
|
-
- spec/refilling_queue_spec.rb
|
34
|
-
- spec/spec_helper.rb
|
35
77
|
homepage: http://github.com/grosser/refilling_queue
|
36
78
|
licenses:
|
37
79
|
- MIT
|
80
|
+
metadata: {}
|
38
81
|
post_install_message:
|
39
82
|
rdoc_options: []
|
40
83
|
require_paths:
|
41
84
|
- lib
|
42
85
|
required_ruby_version: !ruby/object:Gem::Requirement
|
43
|
-
none: false
|
44
86
|
requirements:
|
45
|
-
- -
|
87
|
+
- - ">="
|
46
88
|
- !ruby/object:Gem::Version
|
47
89
|
version: '0'
|
48
|
-
segments:
|
49
|
-
- 0
|
50
|
-
hash: 949949052394646117
|
51
90
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
52
|
-
none: false
|
53
91
|
requirements:
|
54
|
-
- -
|
92
|
+
- - ">="
|
55
93
|
- !ruby/object:Gem::Version
|
56
94
|
version: '0'
|
57
|
-
segments:
|
58
|
-
- 0
|
59
|
-
hash: 949949052394646117
|
60
95
|
requirements: []
|
61
96
|
rubyforge_project:
|
62
|
-
rubygems_version:
|
97
|
+
rubygems_version: 2.2.2
|
63
98
|
signing_key:
|
64
|
-
specification_version:
|
99
|
+
specification_version: 4
|
65
100
|
summary: A queue that refreshes itself when it gets empty or stale, so you can keep
|
66
101
|
popping
|
67
102
|
test_files: []
|
data/.travis.yml
DELETED
data/Appraisals
DELETED
data/Gemfile
DELETED
data/Gemfile.lock
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
refilling_queue (0.0.4)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: http://rubygems.org/
|
8
|
-
specs:
|
9
|
-
appraisal (0.5.1)
|
10
|
-
bundler
|
11
|
-
rake
|
12
|
-
bump (0.3.5)
|
13
|
-
diff-lcs (1.1.3)
|
14
|
-
rake (0.9.2)
|
15
|
-
redis (3.0.1)
|
16
|
-
rspec (2.6.0)
|
17
|
-
rspec-core (~> 2.6.0)
|
18
|
-
rspec-expectations (~> 2.6.0)
|
19
|
-
rspec-mocks (~> 2.6.0)
|
20
|
-
rspec-core (2.6.4)
|
21
|
-
rspec-expectations (2.6.0)
|
22
|
-
diff-lcs (~> 1.1.2)
|
23
|
-
rspec-mocks (2.6.0)
|
24
|
-
|
25
|
-
PLATFORMS
|
26
|
-
ruby
|
27
|
-
|
28
|
-
DEPENDENCIES
|
29
|
-
appraisal
|
30
|
-
bump
|
31
|
-
rake
|
32
|
-
redis
|
33
|
-
refilling_queue!
|
34
|
-
rspec (~> 2)
|
data/Rakefile
DELETED
data/Readme.md
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
A queue that refreshes itself when it gets empty or stale, so you can keep popping
|
2
|
-
|
3
|
-
Install
|
4
|
-
=======
|
5
|
-
|
6
|
-
gem install refilling_queue
|
7
|
-
|
8
|
-
Usage
|
9
|
-
=====
|
10
|
-
|
11
|
-
queue = RefillingQueue.new resque_client, "my_queue", :refresh_every => 30.seconds do
|
12
|
-
expensive_operation.map(&:id)
|
13
|
-
end
|
14
|
-
|
15
|
-
begin
|
16
|
-
queue.pop
|
17
|
-
rescue RefillingQueue::Locked
|
18
|
-
# queue was empty, refilling failed because other process is already trying it
|
19
|
-
end
|
20
|
-
|
21
|
-
queue.pop -> return id
|
22
|
-
... # queue empty ?
|
23
|
-
queue.pop -> run block -> store new ids -> return id
|
24
|
-
... # 30 seconds elapsed (global expires_at stored in reque_client) ?
|
25
|
-
queue.pop -> run block -> store new ids -> return id
|
26
|
-
...
|
27
|
-
queue.pop -> run block -> empty result -> return nil
|
28
|
-
|
29
|
-
Author
|
30
|
-
======
|
31
|
-
[Michael Grosser](http://grosser.it)<br/>
|
32
|
-
michael@grosser.it<br/>
|
33
|
-
License: MIT<br/>
|
34
|
-
[](http://travis-ci.org/grosser/refilling_queue)
|
data/gemfiles/redis2.gemfile
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: /Users/mgrosser/code/tools/refilling_queue
|
3
|
-
specs:
|
4
|
-
refilling_queue (0.0.3)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: http://rubygems.org/
|
8
|
-
specs:
|
9
|
-
appraisal (0.5.1)
|
10
|
-
bundler
|
11
|
-
rake
|
12
|
-
bump (0.3.5)
|
13
|
-
diff-lcs (1.1.3)
|
14
|
-
rake (10.0.2)
|
15
|
-
redis (2.2.2)
|
16
|
-
rspec (2.11.0)
|
17
|
-
rspec-core (~> 2.11.0)
|
18
|
-
rspec-expectations (~> 2.11.0)
|
19
|
-
rspec-mocks (~> 2.11.0)
|
20
|
-
rspec-core (2.11.1)
|
21
|
-
rspec-expectations (2.11.3)
|
22
|
-
diff-lcs (~> 1.1.3)
|
23
|
-
rspec-mocks (2.11.3)
|
24
|
-
|
25
|
-
PLATFORMS
|
26
|
-
ruby
|
27
|
-
|
28
|
-
DEPENDENCIES
|
29
|
-
appraisal
|
30
|
-
bump
|
31
|
-
rake
|
32
|
-
redis (~> 2.0)
|
33
|
-
refilling_queue!
|
34
|
-
rspec (~> 2)
|
data/gemfiles/redis3.gemfile
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: /Users/mgrosser/code/tools/refilling_queue
|
3
|
-
specs:
|
4
|
-
refilling_queue (0.0.3)
|
5
|
-
|
6
|
-
GEM
|
7
|
-
remote: http://rubygems.org/
|
8
|
-
specs:
|
9
|
-
appraisal (0.5.1)
|
10
|
-
bundler
|
11
|
-
rake
|
12
|
-
bump (0.3.5)
|
13
|
-
diff-lcs (1.1.3)
|
14
|
-
rake (10.0.2)
|
15
|
-
redis (3.0.2)
|
16
|
-
rspec (2.11.0)
|
17
|
-
rspec-core (~> 2.11.0)
|
18
|
-
rspec-expectations (~> 2.11.0)
|
19
|
-
rspec-mocks (~> 2.11.0)
|
20
|
-
rspec-core (2.11.1)
|
21
|
-
rspec-expectations (2.11.3)
|
22
|
-
diff-lcs (~> 1.1.3)
|
23
|
-
rspec-mocks (2.11.3)
|
24
|
-
|
25
|
-
PLATFORMS
|
26
|
-
ruby
|
27
|
-
|
28
|
-
DEPENDENCIES
|
29
|
-
appraisal
|
30
|
-
bump
|
31
|
-
rake
|
32
|
-
redis (~> 3.0)
|
33
|
-
refilling_queue!
|
34
|
-
rspec (~> 2)
|
data/refilling_queue.gemspec
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
2
|
-
name = "refilling_queue"
|
3
|
-
require "#{name}/version"
|
4
|
-
|
5
|
-
Gem::Specification.new name, RefillingQueue::VERSION do |s|
|
6
|
-
s.summary = "A queue that refreshes itself when it gets empty or stale, so you can keep popping"
|
7
|
-
s.authors = ["Michael Grosser"]
|
8
|
-
s.email = "michael@grosser.it"
|
9
|
-
s.homepage = "http://github.com/grosser/#{name}"
|
10
|
-
s.files = `git ls-files`.split("\n")
|
11
|
-
s.license = 'MIT'
|
12
|
-
end
|
@@ -1,112 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe RefillingQueue do
|
4
|
-
def kill_all_threads
|
5
|
-
Thread.list.each {|thread| thread.exit unless thread == Thread.current }
|
6
|
-
end
|
7
|
-
|
8
|
-
let(:client){ Redis.new }
|
9
|
-
|
10
|
-
before do
|
11
|
-
kill_all_threads
|
12
|
-
client.flushdb
|
13
|
-
end
|
14
|
-
|
15
|
-
after :all do
|
16
|
-
`rm -f dump.rdb`
|
17
|
-
end
|
18
|
-
|
19
|
-
it "has a VERSION" do
|
20
|
-
RefillingQueue::VERSION.should =~ /^[\.\da-z]+$/
|
21
|
-
end
|
22
|
-
|
23
|
-
context "#initialize" do
|
24
|
-
it "does not fill itself when started full" do
|
25
|
-
x = 0
|
26
|
-
RefillingQueue.new(client, "x"){ x = 1 }
|
27
|
-
x.should == 0
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
context "#pop" do
|
32
|
-
it "removes an element" do
|
33
|
-
queue = RefillingQueue.new(client, "x"){ [1,2,3,4] }
|
34
|
-
queue.pop.should == "1"
|
35
|
-
queue.pop.should == "2"
|
36
|
-
queue.pop.should == "3"
|
37
|
-
end
|
38
|
-
|
39
|
-
it "only tries to refill once" do
|
40
|
-
calls = []
|
41
|
-
RefillingQueue.new(client, "x"){ calls << 1; [] }.pop.should == nil
|
42
|
-
calls.should == [1]
|
43
|
-
end
|
44
|
-
|
45
|
-
it "refills itself if queue gets empty" do
|
46
|
-
content = [1]
|
47
|
-
queue = RefillingQueue.new(client, "x"){ content }
|
48
|
-
queue.pop.should == "1"
|
49
|
-
content.replace [4,5]
|
50
|
-
queue.pop.should == "4"
|
51
|
-
queue.pop.should == "5"
|
52
|
-
queue.pop.should == "4"
|
53
|
-
end
|
54
|
-
|
55
|
-
it "refills itself when it expires" do
|
56
|
-
content = [1,2,3]
|
57
|
-
queue = RefillingQueue.new(client, "x", :refresh_every => 1){ content }
|
58
|
-
|
59
|
-
queue.pop.should == "1"
|
60
|
-
content.replace [4,5]
|
61
|
-
queue.pop.should == "2"
|
62
|
-
sleep 2
|
63
|
-
|
64
|
-
queue.pop.should == "4"
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
context "with multiple actors" do
|
69
|
-
it "only refills once" do
|
70
|
-
called = []
|
71
|
-
|
72
|
-
# lock-blocker
|
73
|
-
Thread.new do
|
74
|
-
RefillingQueue.new(client, "x"){ called << 1; sleep 0.3; called << 2; [] }.pop
|
75
|
-
end
|
76
|
-
sleep 0.1
|
77
|
-
|
78
|
-
# blocked
|
79
|
-
locked = false
|
80
|
-
queue = RefillingQueue.new(client, "x"){ called << 3; [] }
|
81
|
-
begin
|
82
|
-
queue.pop
|
83
|
-
fail
|
84
|
-
rescue RefillingQueue::Locked
|
85
|
-
locked = true
|
86
|
-
end
|
87
|
-
sleep 0.3
|
88
|
-
|
89
|
-
called.should == [1, 2]
|
90
|
-
locked.should == true
|
91
|
-
end
|
92
|
-
|
93
|
-
it "can refill after refill is complete" do
|
94
|
-
called = []
|
95
|
-
RefillingQueue.new(client, "x"){ called << 1; [1] }.pop
|
96
|
-
RefillingQueue.new(client, "x"){ called << 2; [1] }.pop
|
97
|
-
called.should == [1,2]
|
98
|
-
end
|
99
|
-
|
100
|
-
it "can refill if lock expired" do
|
101
|
-
called = []
|
102
|
-
RefillingQueue.new(client, "x", :lock_timeout => 1){ called << 1; [1] }.pop
|
103
|
-
Thread.new do
|
104
|
-
# lock-blocker
|
105
|
-
RefillingQueue.new(client, "x", :lock_timeout => 1){ sleep 3; called << 2; [1] }.pop
|
106
|
-
end
|
107
|
-
sleep 2
|
108
|
-
RefillingQueue.new(client, "x", :lock_timeout => 1){ called << 3; [1] }.pop
|
109
|
-
called.should == [1,3]
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
data/spec/spec_helper.rb
DELETED