restrainer 1.1.1 → 1.1.3

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b1cd37f4ccca910bb1a619d15cd176f656eae9c28832a493ae0ce14901afabaf
4
- data.tar.gz: f55d26dfa66944e52fe1de59d791b7f8215f7afd4b0f13bb2c4cc77833c908d8
3
+ metadata.gz: fd2f59427326450c5159980282e4d463d275dac6fceaa2a31423a5433ff1502f
4
+ data.tar.gz: ddf65e8c8915e920a9689f78bce879d6feae920740890acc7c3df5f5c8ccb2d4
5
5
  SHA512:
6
- metadata.gz: 073671e4736562c7619f732b4fd4af031afc04617e294e4ff779f8b2c4a815c090c5ccc8bb9a7426a8c7777a86258a84c28733458b0e56c34fb2c64aa2763aec
7
- data.tar.gz: d48174a050a831d91dc1b237aa63a584ad831936a3c310b999af7ac96f418b06c04251b98963c581a41833a95577b21b5573c7d1c5b53928e9fc432d3a169656
6
+ metadata.gz: 4166271f5f617a48286024f8e57ab7ebc662c0edfd357ced9e4e40d3998b975db1abcb4db6a1c8de2922ffc57ace7593e752798f39a6f552659877a146fff1b5
7
+ data.tar.gz: 032357eb1992399ba5d10681b7194e667d852ca000b51dcc6ac592f8d10b4734306225208c918d9c3f73faec11adf690a6d0a1ffccefab57deef09438854437a
data/CHANGELOG.md ADDED
@@ -0,0 +1,44 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## 1.1.3
8
+
9
+ ### Added
10
+
11
+ - Support for using fractional seconds in the lock timeout.
12
+
13
+ ## 1.1.2
14
+
15
+ ### Changed
16
+
17
+ - Redis instance will now default to a Redis instance with the default options
18
+ instead of throwing an error if it was not set.
19
+ - Minumum Ruby version set to 2.5
20
+
21
+ ## 1.1.1
22
+
23
+ ### Fixed
24
+
25
+ - Circular reference warning
26
+
27
+ ## 1.1.0
28
+
29
+ ### Added
30
+
31
+ - Expose manually locking and unlocking processes.
32
+ - Allow passing in a redis connection in the constructor.
33
+
34
+ ## 1.0.1
35
+
36
+ ### Fixed
37
+
38
+ - Use Lua script to avoid race conditions and ensure no extra processes slip through.
39
+
40
+ ## 1.0.0
41
+
42
+ ### Added
43
+
44
+ - Initial release.
data/MIT_LICENSE.txt CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2015 WHI, Inc.
1
+ Copyright (c) 2015 Brian Durand
2
2
 
3
3
  MIT License
4
4
 
data/README.md CHANGED
@@ -1,3 +1,8 @@
1
+ [![Continuous Integration](https://github.com/bdurand/restrainer/actions/workflows/continuous_integration.yml/badge.svg)](https://github.com/bdurand/restrainer/actions/workflows/continuous_integration.yml)
2
+ [![Regression Test](https://github.com/bdurand/restrainer/actions/workflows/regression_test.yml/badge.svg)](https://github.com/bdurand/restrainer/actions/workflows/regression_test.yml)
3
+ [![Ruby Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://github.com/testdouble/standard)
4
+ [![Gem Version](https://badge.fury.io/rb/restrainer.svg)](https://badge.fury.io/rb/restrainer)
5
+
1
6
  This gem provides a method of throttling calls across processes that can be very useful if you have to call an external service with limited resources.
2
7
 
3
8
  A [redis server](http://redis.io/) is required to use this gem.
@@ -59,3 +64,31 @@ restrainer = Restrainer.new(:my_service, 100, timeout: 10)
59
64
  ```
60
65
 
61
66
  This gem does clean up after itself nicely, so that it won't ever leave unused data lying around in redis.
67
+
68
+ ## Installation
69
+
70
+ Add this line to your application's Gemfile:
71
+
72
+ ```ruby
73
+ gem 'restrainer'
74
+ ```
75
+
76
+ And then execute:
77
+ ```bash
78
+ $ bundle
79
+ ```
80
+
81
+ Or install it yourself as:
82
+ ```bash
83
+ $ gem install restrainer
84
+ ```
85
+
86
+ ## Contributing
87
+
88
+ Open a pull request on GitHub.
89
+
90
+ Please use the [standardrb](https://github.com/testdouble/standard) syntax and lint your code with `standardrb --fix` before submitting.
91
+
92
+ ## License
93
+
94
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.1.1
1
+ 1.1.3
data/lib/restrainer.rb CHANGED
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'redis'
4
- require 'securerandom'
3
+ require "redis"
4
+ require "securerandom"
5
5
 
6
6
  # Redis backed throttling mechanism to ensure that only a limited number of processes can
7
7
  # be executed at any one time.
@@ -14,7 +14,6 @@ require 'securerandom'
14
14
  # If more than the specified number of processes as identified by the name argument is currently
15
15
  # running, then the throttle block will raise an error.
16
16
  class Restrainer
17
-
18
17
  attr_reader :name, :limit
19
18
 
20
19
  ADD_PROCESS_SCRIPT = <<-LUA
@@ -39,7 +38,7 @@ class Restrainer
39
38
  -- Success so add to the list and set a global expiration so the list cleans up after itself.
40
39
  if process_count < limit then
41
40
  redis.call('zadd', sorted_set, now, process_id)
42
- redis.call('expire', sorted_set, ttl)
41
+ redis.call('pexpire', sorted_set, math.ceil(ttl * 1000))
43
42
  end
44
43
 
45
44
  -- Return the number of processes running before the process was added.
@@ -53,54 +52,69 @@ class Restrainer
53
52
  class ThrottledError < StandardError
54
53
  end
55
54
 
55
+ @redis = nil
56
+
56
57
  class << self
57
58
  # Either configure the redis instance using a block or yield the instance. Configuring with
58
59
  # a block allows you to use things like connection pools etc. without hard coding a single
59
60
  # instance.
60
61
  #
61
- # Example: `Restrainer.redis { redis_pool.instance }`
62
+ # @param block [Proc] A block that returns a redis instance.
63
+ # @return [Redis] The redis instance.
64
+ # @example
65
+ # Restrainer.redis { redis_pool.instance }
62
66
  def redis(&block)
63
67
  if block
64
68
  @redis = block
65
- elsif defined?(@redis) && @redis
66
- @redis.call
67
69
  else
68
- raise "#{self.class.name}.redis not configured"
70
+ unless @redis
71
+ client = Redis.new
72
+ @redis = lambda { client }
73
+ end
74
+ @redis.call
69
75
  end
70
76
  end
71
77
 
72
- # Set the redis instance to a specific instance. It is usually preferable to use the block
73
- # form for configurating the instance so that it can be evaluated at runtime.
78
+ # Set the redis instance to a specific instance. It is usually preferable to use
79
+ # the block form for configurating the instance so that it can be evaluated at
80
+ # runtime.
74
81
  #
75
- # Example: `Restrainer.redis = Redis.new`
82
+ # @param conn [Redis]
83
+ # @return [void]
84
+ # @example
85
+ # Restrainer.redis = Redis.new
76
86
  def redis=(conn)
77
- @redis = lambda{ conn }
87
+ @redis = lambda { conn }
78
88
  end
79
89
  end
80
90
 
81
- # Create a new restrainer. The name is used to identify the Restrainer and group processes together.
82
- # You can create any number of Restrainers with different names.
91
+ # Create a new restrainer. The name is used to identify the Restrainer and group
92
+ # processes together. You can create any number of Restrainers with different names.
83
93
  #
84
- # The required limit parameter specifies the maximum number of processes that will be allowed to execute the
85
- # throttle block at any point in time.
94
+ # The required limit parameter specifies the maximum number of processes that
95
+ # will be allowed to execute the throttle block at any point in time.
86
96
  #
87
- # The timeout parameter is used for cleaning up internal data structures so that jobs aren't orphaned
88
- # if their process is killed. Processes will automatically be removed from the running jobs list after the
89
- # specified number of seconds. Note that the Restrainer will not handle timing out any code itself. This
97
+ # The timeout parameter is used for cleaning up internal data structures so that
98
+ # jobs aren't orphaned if their process is killed. Processes will automatically
99
+ # be removed from the running jobs list after the specified number of seconds.
100
+ # Note that the Restrainer will not handle timing out any code itself. This
90
101
  # value is just used to insure the integrity of internal data structures.
91
102
  def initialize(name, limit:, timeout: 60, redis: nil)
92
103
  @name = name
93
104
  @limit = limit
94
105
  @timeout = timeout
95
- @key = "#{self.class.name}.#{name.to_s}"
96
- @redis ||= redis
106
+ @key = "#{self.class.name}.#{name}"
107
+ @redis = redis
97
108
  end
98
109
 
99
- # Wrap a block with this method to throttle concurrent execution. If more than the alotted number
100
- # of processes (as identified by the name) are currently executing, then a Restrainer::ThrottledError
101
- # will be raised.
110
+ # Wrap a block with this method to throttle concurrent execution. If more than the
111
+ # alotted number of processes (as identified by the name) are currently executing,
112
+ # then a Restrainer::ThrottledError will be raised.
102
113
  #
103
- # The limit argument can be used to override the value set in the constructor.
114
+ # @param limit [Integer] The maximum number of processes that can be executing
115
+ # at any one time. Defaults to the value passed to the constructor.
116
+ # @return [void]
117
+ # @raise [Restrainer::ThrottledError] If the throttle would be exceeded.
104
118
  def throttle(limit: nil)
105
119
  limit ||= self.limit
106
120
 
@@ -119,9 +133,12 @@ class Restrainer
119
133
  # identifier that must be passed to the release! to release the lock.
120
134
  # You can pass in a unique identifier if you already have one.
121
135
  #
122
- # Raises a Restrainer::ThrottledError if the lock cannot be obtained.
123
- #
124
- # The limit argument can be used to override the value set in the constructor.
136
+ # @param process_id [String] A unique identifier for the process. If none is
137
+ # passed, a unique value will be generated.
138
+ # @param limit [Integer] The maximum number of processes that can be executing
139
+ # at any one time. Defaults to the value passed to the constructor.
140
+ # @return [String] The process identifier.
141
+ # @raise [Restrainer::ThrottledError] If the throttle would be exceeded.
125
142
  def lock!(process_id = nil, limit: nil)
126
143
  process_id ||= SecureRandom.uuid
127
144
  limit ||= self.limit
@@ -134,17 +151,30 @@ class Restrainer
134
151
  process_id
135
152
  end
136
153
 
137
- # release one of the allowed processes. You must pass in a process id returned by the lock method.
154
+ def lock(process_id = nil, limit: nil)
155
+ end
156
+
157
+ # Release one of the allowed processes. You must pass in a process id
158
+ # returned by the lock method.
159
+ #
160
+ # @param process_id [String] The process identifier returned by the lock call.
161
+ # @return [Boolean] True if the process was released, false if it was not found.
138
162
  def release!(process_id)
139
- remove_process!(redis, process_id) unless process_id.nil?
163
+ return false if process_id.nil?
164
+
165
+ remove_process!(redis, process_id)
140
166
  end
141
167
 
142
168
  # Get the number of processes currently being executed for this restrainer.
169
+ #
170
+ # @return [Integer] The number of processes currently being executed.
143
171
  def current
144
172
  redis.zcard(key).to_i
145
173
  end
146
174
 
147
- # Clear all locks
175
+ # Clear all locks.
176
+ #
177
+ # @return [void]
148
178
  def clear!
149
179
  redis.del(key)
150
180
  end
@@ -156,9 +186,7 @@ class Restrainer
156
186
  end
157
187
 
158
188
  # Hash key in redis to story a sorted set of current processes.
159
- def key
160
- @key
161
- end
189
+ attr_reader :key
162
190
 
163
191
  # Add a process to the currently run set.
164
192
  def add_process!(redis, process_id, throttle_limit)
@@ -168,23 +196,25 @@ class Restrainer
168
196
  end
169
197
  end
170
198
 
171
- # Remove a process to the currently run set.
199
+ # Remove a process to the currently run set. Returns true if the process was removed.
172
200
  def remove_process!(redis, process_id)
173
- redis.zrem(key, process_id)
201
+ result = redis.zrem(key, process_id)
202
+ result = true if result == 1
203
+ result
174
204
  end
175
205
 
176
206
  # Evaluate and execute a Lua script on the redis server.
177
207
  def eval_script(redis, process_id, throttle_limit)
178
208
  sha1 = @add_process_sha1
179
- if sha1 == nil
209
+ if sha1.nil?
180
210
  sha1 = redis.script(:load, ADD_PROCESS_SCRIPT)
181
211
  @add_process_sha1 = sha1
182
212
  end
183
213
 
184
214
  begin
185
- redis.evalsha(sha1, [], [key, process_id, throttle_limit, @timeout, Time.now.to_i])
215
+ redis.evalsha(sha1, [], [key, process_id, throttle_limit, @timeout, Time.now.to_f])
186
216
  rescue Redis::CommandError => e
187
- if e.message.include?('NOSCRIPT')
217
+ if e.message.include?("NOSCRIPT")
188
218
  sha1 = redis.script(:load, ADD_PROCESS_SCRIPT)
189
219
  @add_process_sha1 = sha1
190
220
  retry
data/restrainer.gemspec CHANGED
@@ -1,27 +1,34 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
-
5
1
  Gem::Specification.new do |spec|
6
- spec.name = "restrainer"
7
- spec.version = File.read(File.expand_path("../VERSION", __FILE__)).chomp
8
- spec.authors = ["We Heart It", "Brian Durand"]
9
- spec.email = ["dev@weheartit.com", "bbdurand@gmail.com"]
10
- spec.summary = "Code for throttling workloads so as not to overwhelm external services"
11
- spec.description = "Code for throttling workloads so as not to overwhelm external services."
12
- spec.homepage = "https://github.com/weheartit/restrainer"
13
- spec.license = "MIT"
14
- spec.files = `git ls-files`.split($/)
15
- spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
16
- spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
2
+ spec.name = "restrainer"
3
+ spec.version = File.read(File.expand_path("VERSION", __dir__)).strip
4
+ spec.authors = ["Brian Durand"]
5
+ spec.email = ["bbdurand@gmail.com"]
6
+
7
+ spec.summary = "Code for throttling workloads so as not to overwhelm external services"
8
+ spec.homepage = "https://github.com/bdurand/restrainer"
9
+ spec.license = "MIT"
10
+
11
+ # Specify which files should be added to the gem when it is released.
12
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
13
+ ignore_files = %w[
14
+ .
15
+ Appraisals
16
+ Gemfile
17
+ Gemfile.lock
18
+ Rakefile
19
+ bin/
20
+ gemfiles/
21
+ spec/
22
+ ]
23
+ spec.files = Dir.chdir(__dir__) do
24
+ `git ls-files -z`.split("\x0").reject { |f| ignore_files.any? { |path| f.start_with?(path) } }
25
+ end
26
+
17
27
  spec.require_paths = ["lib"]
18
28
 
19
- spec.required_ruby_version = '>=2.0'
29
+ spec.required_ruby_version = ">= 2.5"
20
30
 
21
- spec.add_dependency('redis')
31
+ spec.add_dependency("redis")
22
32
 
23
- spec.add_development_dependency "bundler", "~> 1.3"
24
- spec.add_development_dependency "rake"
25
- spec.add_development_dependency "rspec"
26
- spec.add_development_dependency "timecop"
33
+ spec.add_development_dependency "bundler"
27
34
  end
metadata CHANGED
@@ -1,15 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: restrainer
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.1.1
4
+ version: 1.1.3
5
5
  platform: ruby
6
6
  authors:
7
- - We Heart It
8
7
  - Brian Durand
9
- autorequire:
8
+ autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2019-07-17 00:00:00.000000000 Z
11
+ date: 2023-12-22 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: redis
@@ -27,48 +26,6 @@ dependencies:
27
26
  version: '0'
28
27
  - !ruby/object:Gem::Dependency
29
28
  name: bundler
30
- requirement: !ruby/object:Gem::Requirement
31
- requirements:
32
- - - "~>"
33
- - !ruby/object:Gem::Version
34
- version: '1.3'
35
- type: :development
36
- prerelease: false
37
- version_requirements: !ruby/object:Gem::Requirement
38
- requirements:
39
- - - "~>"
40
- - !ruby/object:Gem::Version
41
- version: '1.3'
42
- - !ruby/object:Gem::Dependency
43
- name: rake
44
- requirement: !ruby/object:Gem::Requirement
45
- requirements:
46
- - - ">="
47
- - !ruby/object:Gem::Version
48
- version: '0'
49
- type: :development
50
- prerelease: false
51
- version_requirements: !ruby/object:Gem::Requirement
52
- requirements:
53
- - - ">="
54
- - !ruby/object:Gem::Version
55
- version: '0'
56
- - !ruby/object:Gem::Dependency
57
- name: rspec
58
- requirement: !ruby/object:Gem::Requirement
59
- requirements:
60
- - - ">="
61
- - !ruby/object:Gem::Version
62
- version: '0'
63
- type: :development
64
- prerelease: false
65
- version_requirements: !ruby/object:Gem::Requirement
66
- requirements:
67
- - - ">="
68
- - !ruby/object:Gem::Version
69
- version: '0'
70
- - !ruby/object:Gem::Dependency
71
- name: timecop
72
29
  requirement: !ruby/object:Gem::Requirement
73
30
  requirements:
74
31
  - - ">="
@@ -81,29 +38,24 @@ dependencies:
81
38
  - - ">="
82
39
  - !ruby/object:Gem::Version
83
40
  version: '0'
84
- description: Code for throttling workloads so as not to overwhelm external services.
41
+ description:
85
42
  email:
86
- - dev@weheartit.com
87
43
  - bbdurand@gmail.com
88
44
  executables: []
89
45
  extensions: []
90
46
  extra_rdoc_files: []
91
47
  files:
92
- - ".gitignore"
93
- - CHANGE_LOG.md
48
+ - CHANGELOG.md
94
49
  - MIT_LICENSE.txt
95
50
  - README.md
96
- - Rakefile
97
51
  - VERSION
98
52
  - lib/restrainer.rb
99
53
  - restrainer.gemspec
100
- - spec/restrainer_spec.rb
101
- - spec/spec_helper.rb
102
- homepage: https://github.com/weheartit/restrainer
54
+ homepage: https://github.com/bdurand/restrainer
103
55
  licenses:
104
56
  - MIT
105
57
  metadata: {}
106
- post_install_message:
58
+ post_install_message:
107
59
  rdoc_options: []
108
60
  require_paths:
109
61
  - lib
@@ -111,17 +63,15 @@ required_ruby_version: !ruby/object:Gem::Requirement
111
63
  requirements:
112
64
  - - ">="
113
65
  - !ruby/object:Gem::Version
114
- version: '2.0'
66
+ version: '2.5'
115
67
  required_rubygems_version: !ruby/object:Gem::Requirement
116
68
  requirements:
117
69
  - - ">="
118
70
  - !ruby/object:Gem::Version
119
71
  version: '0'
120
72
  requirements: []
121
- rubygems_version: 3.0.3
122
- signing_key:
73
+ rubygems_version: 3.4.20
74
+ signing_key:
123
75
  specification_version: 4
124
76
  summary: Code for throttling workloads so as not to overwhelm external services
125
- test_files:
126
- - spec/restrainer_spec.rb
127
- - spec/spec_helper.rb
77
+ test_files: []
data/.gitignore DELETED
@@ -1,17 +0,0 @@
1
- *.gem
2
- *.rbc
3
- .bundle
4
- .config
5
- .yardoc
6
- Gemfile.lock
7
- InstalledFiles
8
- _yardoc
9
- coverage
10
- doc/
11
- lib/bundler/man
12
- pkg
13
- rdoc
14
- spec/reports
15
- test/tmp
16
- test/version_tmp
17
- tmp
data/CHANGE_LOG.md DELETED
@@ -1,13 +0,0 @@
1
- # 1.1.1
2
-
3
- * Circular reference warning fix
4
-
5
- # 1.1.0
6
-
7
- * Expose manually locking and unlocking processes.
8
-
9
- * Allow passing in a redis connection in the constructor.
10
-
11
- # 1.0.1
12
-
13
- * Use Lua script to avoid race conditions and ensure no extra processes slip through.
data/Rakefile DELETED
@@ -1,6 +0,0 @@
1
- require "bundler/gem_tasks"
2
- require "rspec/core/rake_task"
3
-
4
- RSpec::Core::RakeTask.new(:spec)
5
-
6
- task :default => :spec
@@ -1,138 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require 'spec_helper'
4
-
5
- describe Restrainer do
6
-
7
- before(:each) do
8
- Restrainer.new(:restrainer_test, limit: 1).clear!
9
- end
10
-
11
- it "should have a name and max_processes" do
12
- restrainer = Restrainer.new(:restrainer_test, limit: 1)
13
- expect(restrainer.name).to eq(:restrainer_test)
14
- expect(restrainer.limit).to eq(1)
15
- end
16
-
17
- it "should run a block!" do
18
- restrainer = Restrainer.new(:restrainer_test, limit: 1)
19
- x = nil
20
- expect(restrainer.throttle{ x = restrainer.current }).to eq(1)
21
- expect(x).to eq(1)
22
- expect(restrainer.current).to eq(0)
23
- end
24
-
25
- it "should throw an error if too many processes are already running" do
26
- restrainer = Restrainer.new(:restrainer_test, limit: 5)
27
- x = nil
28
- restrainer.throttle do
29
- restrainer.throttle do
30
- restrainer.throttle do
31
- restrainer.throttle do
32
- restrainer.throttle do
33
- expect(lambda{restrainer.throttle{ x = 1 }}).to raise_error(Restrainer::ThrottledError)
34
- end
35
- end
36
- end
37
- end
38
- end
39
- expect(x).to eq(nil)
40
- end
41
-
42
- it "should not throw an error if the number of processes is under the limit" do
43
- restrainer = Restrainer.new(:restrainer_test, limit: 2)
44
- x = nil
45
- restrainer.throttle do
46
- restrainer.throttle{ x = 1 }
47
- end
48
- expect(x).to eq(1)
49
- end
50
-
51
- it "should let the throttle method override the limit" do
52
- restrainer = Restrainer.new(:restrainer_test, limit: 1)
53
- x = nil
54
- restrainer.throttle do
55
- restrainer.throttle(limit: 2){ x = 1 }
56
- end
57
- expect(x).to eq(1)
58
- end
59
-
60
- it "should allow processing to be turned off entirely by setting the limit to zero" do
61
- restrainer = Restrainer.new(:restrainer_test, limit: 1)
62
- x = nil
63
- expect(lambda{restrainer.throttle(limit: 0){ x = 1 }}).to raise_error(Restrainer::ThrottledError)
64
- expect(x).to eq(nil)
65
- end
66
-
67
- it "should allow the throttle to be opened up entirely with a negative limit" do
68
- restrainer = Restrainer.new(:restrainer_test, limit: 0)
69
- x = nil
70
- restrainer.throttle(limit: -1){ x = 1 }
71
- expect(x).to eq(1)
72
- end
73
-
74
- it "should cleanup the running process list if orphaned processes exist" do
75
- restrainer = Restrainer.new(:restrainer_test, limit: 1, timeout: 10)
76
- x = nil
77
- restrainer.throttle do
78
- Timecop.travel(11) do
79
- restrainer.throttle{ x = 1 }
80
- end
81
- end
82
- expect(x).to eq(1)
83
- end
84
-
85
- it "should be able to lock! and release! processes manually" do
86
- restrainer = Restrainer.new(:restrainer_test, limit: 5)
87
- p1 = restrainer.lock!
88
- begin
89
- p2 = restrainer.lock!
90
- begin
91
- p3 = restrainer.lock!
92
- begin
93
- p4 = restrainer.lock!
94
- begin
95
- p5 = restrainer.lock!
96
- begin
97
- expect{ restrainer.lock! }.to raise_error(Restrainer::ThrottledError)
98
- ensure
99
- restrainer.release!(p5)
100
- end
101
- p6 = restrainer.lock!
102
- restrainer.release!(p6)
103
- ensure
104
- restrainer.release!(p4)
105
- end
106
- ensure
107
- restrainer.release!(p3)
108
- end
109
- ensure
110
- restrainer.release!(p2)
111
- end
112
- ensure
113
- restrainer.release!(p1)
114
- end
115
- end
116
-
117
- it "should be able to pass in the process id" do
118
- restrainer = Restrainer.new(:restrainer_test, limit: 1)
119
- expect(restrainer.lock!("foo")).to eq "foo"
120
- end
121
-
122
- it "should not get a lock! if the limit is 0" do
123
- restrainer = Restrainer.new(:restrainer_test, limit: 0)
124
- expect{ restrainer.lock! }.to raise_error(Restrainer::ThrottledError)
125
- end
126
-
127
- it "should get a lock! if the limit is negative" do
128
- restrainer = Restrainer.new(:restrainer_test, limit: -1)
129
- process_id = restrainer.lock!
130
- expect(process_id).to eq nil
131
- restrainer.release!(nil)
132
- end
133
-
134
- it "should be able to override the limit in lock!" do
135
- restrainer = Restrainer.new(:restrainer_test, limit: 0)
136
- restrainer.lock!(limit: 1)
137
- end
138
- end
data/spec/spec_helper.rb DELETED
@@ -1,19 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require File.expand_path('../../lib/restrainer', __FILE__)
4
- require 'timecop'
5
-
6
- RSpec.configure do |config|
7
- config.run_all_when_everything_filtered = true
8
- config.filter_run :focus
9
-
10
- # Run specs in random order to surface order dependencies. If you find an
11
- # order dependency and want to debug it, you can fix the order by providing
12
- # the seed, which is printed after each run.
13
- # --seed 1234
14
- config.order = 'random'
15
-
16
- redis_opts = {}
17
- redis_opts = {url: ENV["REDIS_URL"]} if ENV["REDIS_URL"]
18
- Restrainer.redis = Redis.new(redis_opts)
19
- end