refilling_queue 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,3 +1,3 @@
1
1
  class RefillingQueue
2
- VERSION = '0.0.4'
2
+ VERSION = '0.1.0'
3
3
  end
@@ -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
- results = @block.call
34
- return if results.empty?
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
- @client.pipelined do
37
- @client.del @name
38
- results.each{ |r| @client.rpush @name, r } # TODO https://github.com/redis/redis-rb/issues/253
39
- @client.expire @name, @options[:refresh_every] if @options[:refresh_every]
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.4
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: 2012-11-20 00:00:00.000000000 Z
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: 1.8.24
97
+ rubygems_version: 2.2.2
63
98
  signing_key:
64
- specification_version: 3
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
@@ -1,4 +0,0 @@
1
- rvm:
2
- - ree
3
- - 1.9.2
4
- - 1.9.3
data/Appraisals DELETED
@@ -1,5 +0,0 @@
1
- ["2", "3"].each do |version|
2
- appraise "redis#{version}" do
3
- gem "redis", "~>#{version}.0"
4
- end
5
- end
data/Gemfile DELETED
@@ -1,8 +0,0 @@
1
- source :rubygems
2
- gemspec
3
-
4
- gem 'appraisal'
5
- gem 'bump'
6
- gem 'rake'
7
- gem 'rspec', '~>2'
8
- gem 'redis'
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
@@ -1,11 +0,0 @@
1
- require 'bundler/gem_tasks'
2
- require 'appraisal'
3
- require 'bump/tasks'
4
-
5
- task :spec do
6
- sh "rspec spec/"
7
- end
8
-
9
- task :default do
10
- sh "bundle exec rake appraisal:install && bundle exec rake appraisal spec"
11
- end
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
- [![Build Status](https://secure.travis-ci.org/grosser/refilling_queue.png)](http://travis-ci.org/grosser/refilling_queue)
@@ -1,11 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source :rubygems
4
-
5
- gem "appraisal"
6
- gem "bump"
7
- gem "rake"
8
- gem "rspec", "~>2"
9
- gem "redis", "~>2.0"
10
-
11
- gemspec :path=>"../"
@@ -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)
@@ -1,11 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source :rubygems
4
-
5
- gem "appraisal"
6
- gem "bump"
7
- gem "rake"
8
- gem "rspec", "~>2"
9
- gem "redis", "~>3.0"
10
-
11
- gemspec :path=>"../"
@@ -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)
@@ -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
@@ -1,3 +0,0 @@
1
- $LOAD_PATH.unshift 'lib'
2
- require 'refilling_queue'
3
- require 'redis'