sidekiq-fairplay 0.0.1 → 0.0.2
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 +4 -4
- data/lib/sidekiq/fairplay/version.rb +1 -1
- metadata +2 -16
- data/.github/workflows/ci.yml +0 -76
- data/.gitignore +0 -37
- data/.standard.yml +0 -9
- data/Gemfile +0 -3
- data/Rakefile +0 -7
- data/bin/console +0 -7
- data/bin/setup +0 -6
- data/gemfiles/sidekiq_7.gemfile +0 -5
- data/gemfiles/sidekiq_8.gemfile +0 -5
- data/sidekiq-fairplay.gemspec +0 -37
- data/spec/sidekiq/fairplay_spec.rb +0 -301
- data/spec/spec_helper.rb +0 -63
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 90c65bc475c5878775b1e24fee917f48c7f24021c43846d1d7d4d4659b9cbcca
|
4
|
+
data.tar.gz: 883a02caa000007968db911404f77798cc3f2252360550c8a00146b8ef7e794c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 15705758d8ce779bb448d285a26ac8f79d97c074dd80758ad02eafd90fc2300296c6bfa3f2be28bc4f06fac96bb46f5601ab1f57b7e5684642070c7e7ae90088
|
7
|
+
data.tar.gz: 0ab155ded33d5eeafeb3c5719d88aca244af590f5596cd4e6326a2552f455ac96fffe4d33878a4d5ed90c6aaef45325d3d3654b58c4879f203219a06474f6a07
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq-fairplay
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alexander Baygeldin
|
@@ -179,32 +179,18 @@ dependencies:
|
|
179
179
|
version: '7.0'
|
180
180
|
email:
|
181
181
|
- a.baygeldin@gmail.com
|
182
|
-
executables:
|
183
|
-
- console
|
184
|
-
- setup
|
182
|
+
executables: []
|
185
183
|
extensions: []
|
186
184
|
extra_rdoc_files: []
|
187
185
|
files:
|
188
|
-
- ".github/workflows/ci.yml"
|
189
|
-
- ".gitignore"
|
190
|
-
- ".standard.yml"
|
191
|
-
- Gemfile
|
192
186
|
- LICENSE
|
193
187
|
- README.md
|
194
|
-
- Rakefile
|
195
|
-
- bin/console
|
196
|
-
- bin/setup
|
197
|
-
- gemfiles/sidekiq_7.gemfile
|
198
|
-
- gemfiles/sidekiq_8.gemfile
|
199
188
|
- lib/sidekiq/fairplay.rb
|
200
189
|
- lib/sidekiq/fairplay/config.rb
|
201
190
|
- lib/sidekiq/fairplay/middleware.rb
|
202
191
|
- lib/sidekiq/fairplay/planner.rb
|
203
192
|
- lib/sidekiq/fairplay/redis.rb
|
204
193
|
- lib/sidekiq/fairplay/version.rb
|
205
|
-
- sidekiq-fairplay.gemspec
|
206
|
-
- spec/sidekiq/fairplay_spec.rb
|
207
|
-
- spec/spec_helper.rb
|
208
194
|
homepage: http://github.com/baygeldin/sidekiq-fairplay
|
209
195
|
licenses:
|
210
196
|
- MIT
|
data/.github/workflows/ci.yml
DELETED
@@ -1,76 +0,0 @@
|
|
1
|
-
name: CI
|
2
|
-
|
3
|
-
on:
|
4
|
-
push:
|
5
|
-
branches: [ main, master ]
|
6
|
-
pull_request:
|
7
|
-
branches: [ main, master ]
|
8
|
-
|
9
|
-
jobs:
|
10
|
-
test:
|
11
|
-
name: Test (Ruby ${{ matrix.ruby }}, Sidekiq ${{ matrix.sidekiq }})
|
12
|
-
runs-on: ubuntu-latest
|
13
|
-
timeout-minutes: 15
|
14
|
-
strategy:
|
15
|
-
fail-fast: false
|
16
|
-
matrix:
|
17
|
-
ruby: ['3.4']
|
18
|
-
sidekiq: ['7', '8']
|
19
|
-
|
20
|
-
services:
|
21
|
-
redis:
|
22
|
-
image: redis:7-alpine
|
23
|
-
ports:
|
24
|
-
- 6379:6379
|
25
|
-
options: >-
|
26
|
-
--health-cmd "redis-cli ping || exit 1"
|
27
|
-
--health-interval 10s
|
28
|
-
--health-timeout 5s
|
29
|
-
--health-retries 5
|
30
|
-
|
31
|
-
steps:
|
32
|
-
- name: Checkout
|
33
|
-
uses: actions/checkout@v4
|
34
|
-
|
35
|
-
- name: Set up Ruby
|
36
|
-
uses: ruby/setup-ruby@v1
|
37
|
-
with:
|
38
|
-
ruby-version: ${{ matrix.ruby }}
|
39
|
-
bundler-cache: true
|
40
|
-
|
41
|
-
- name: Select Gemfile for Sidekiq ${{ matrix.sidekiq }}
|
42
|
-
run: |
|
43
|
-
export BUNDLE_GEMFILE="gemfiles/sidekiq_${{ matrix.sidekiq }}.gemfile"
|
44
|
-
echo "BUNDLE_GEMFILE=$BUNDLE_GEMFILE" >> $GITHUB_ENV
|
45
|
-
|
46
|
-
- name: Bundle install
|
47
|
-
run: bundle install --jobs 4 --retry 3
|
48
|
-
|
49
|
-
- name: Run specs
|
50
|
-
env:
|
51
|
-
REDIS_URL: redis://localhost:6379/1
|
52
|
-
run: |
|
53
|
-
bundle exec rspec --format progress
|
54
|
-
|
55
|
-
- uses: qltysh/qlty-action/coverage@v2
|
56
|
-
if: matrix.sidekiq == '8' && matrix.ruby == '3.4'
|
57
|
-
with:
|
58
|
-
token: ${{secrets.QLTY_COVERAGE_TOKEN}}
|
59
|
-
files: coverage/.resultset.json
|
60
|
-
|
61
|
-
lint:
|
62
|
-
name: Lint (standardrb)
|
63
|
-
runs-on: ubuntu-latest
|
64
|
-
continue-on-error: true
|
65
|
-
steps:
|
66
|
-
- name: Checkout
|
67
|
-
uses: actions/checkout@v4
|
68
|
-
|
69
|
-
- name: Set up Ruby
|
70
|
-
uses: ruby/setup-ruby@v1
|
71
|
-
with:
|
72
|
-
ruby-version: '3.4'
|
73
|
-
bundler-cache: true
|
74
|
-
|
75
|
-
- name: Run StandardRB
|
76
|
-
run: bundle exec standardrb
|
data/.gitignore
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
*.gem
|
2
|
-
*.rbc
|
3
|
-
/.config
|
4
|
-
/coverage/
|
5
|
-
/InstalledFiles
|
6
|
-
/pkg/
|
7
|
-
/spec/reports/
|
8
|
-
/spec/examples.txt
|
9
|
-
/test/tmp/
|
10
|
-
/test/version_tmp/
|
11
|
-
/tmp/
|
12
|
-
spec/examples.txt
|
13
|
-
.byebug_history
|
14
|
-
|
15
|
-
## Documentation cache and generated files
|
16
|
-
/.yardoc/
|
17
|
-
/_yardoc/
|
18
|
-
/doc/
|
19
|
-
/rdoc/
|
20
|
-
|
21
|
-
## Environment normalization
|
22
|
-
/.bundle/
|
23
|
-
/vendor/bundle
|
24
|
-
/lib/bundler/man/
|
25
|
-
|
26
|
-
# System files
|
27
|
-
.DS_Store
|
28
|
-
|
29
|
-
# Editors
|
30
|
-
.vscode
|
31
|
-
.ruby-lsp
|
32
|
-
|
33
|
-
# Unnecessary for Ruby gems
|
34
|
-
Gemfile.lock
|
35
|
-
.ruby-version
|
36
|
-
.ruby-gemset
|
37
|
-
.tool-versions
|
data/.standard.yml
DELETED
data/Gemfile
DELETED
data/Rakefile
DELETED
data/bin/console
DELETED
data/bin/setup
DELETED
data/gemfiles/sidekiq_7.gemfile
DELETED
data/gemfiles/sidekiq_8.gemfile
DELETED
data/sidekiq-fairplay.gemspec
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
lib = File.expand_path("lib", __dir__)
|
2
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
-
require "sidekiq/fairplay/version"
|
4
|
-
|
5
|
-
Gem::Specification.new do |spec|
|
6
|
-
spec.name = "sidekiq-fairplay"
|
7
|
-
spec.version = Sidekiq::Fairplay::VERSION
|
8
|
-
spec.authors = ["Alexander Baygeldin"]
|
9
|
-
spec.email = ["a.baygeldin@gmail.com"]
|
10
|
-
spec.summary = <<~SUMMARY
|
11
|
-
Make Sidekiq play fair — dynamic job prioritization for multi-tenant apps.
|
12
|
-
SUMMARY
|
13
|
-
spec.homepage = "http://github.com/baygeldin/sidekiq-fairplay"
|
14
|
-
spec.license = "MIT"
|
15
|
-
|
16
|
-
spec.files = `git ls-files -z`.split("\x0")
|
17
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
-
spec.require_paths = ["lib"]
|
19
|
-
|
20
|
-
spec.required_ruby_version = ">= 3.4.0"
|
21
|
-
|
22
|
-
spec.add_development_dependency "bundler", "~> 2.0"
|
23
|
-
spec.add_development_dependency "pry", "~> 0.15"
|
24
|
-
spec.add_development_dependency "rake", "~> 13.0"
|
25
|
-
spec.add_development_dependency "rspec", "~> 3.0"
|
26
|
-
spec.add_development_dependency "rspec-sidekiq", "~> 5.0"
|
27
|
-
spec.add_development_dependency "standard", "~> 1.0"
|
28
|
-
spec.add_development_dependency "standard-performance", "~> 1.0"
|
29
|
-
spec.add_development_dependency "standard-rspec", "~> 0.3"
|
30
|
-
spec.add_development_dependency "simplecov", "~> 0.22"
|
31
|
-
spec.add_development_dependency "timecop", "~> 0.9"
|
32
|
-
|
33
|
-
spec.add_dependency "activesupport", "~> 7.0"
|
34
|
-
spec.add_runtime_dependency "sidekiq", "~> 7.0"
|
35
|
-
|
36
|
-
spec.metadata["rubygems_mfa_required"] = "true"
|
37
|
-
end
|
@@ -1,301 +0,0 @@
|
|
1
|
-
require "spec_helper"
|
2
|
-
|
3
|
-
class RegularJob
|
4
|
-
include Sidekiq::Job
|
5
|
-
|
6
|
-
def perform(foo)
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
class FairplayJob
|
11
|
-
include Sidekiq::Job
|
12
|
-
include Sidekiq::Fairplay::Job
|
13
|
-
|
14
|
-
def perform(tenant_key, foo)
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
RSpec.describe Sidekiq::Fairplay do
|
19
|
-
before do
|
20
|
-
FairplayJob.sidekiq_fairplay_options \
|
21
|
-
enqueue_interval:,
|
22
|
-
enqueue_jobs:,
|
23
|
-
planner_queue:,
|
24
|
-
planner_lock_ttl:,
|
25
|
-
latency_threshold:,
|
26
|
-
tenant_key:,
|
27
|
-
tenant_weights:
|
28
|
-
end
|
29
|
-
|
30
|
-
let(:enqueue_interval) { 1 }
|
31
|
-
let(:enqueue_jobs) { 10 }
|
32
|
-
let(:planner_queue) { "default" }
|
33
|
-
let(:planner_lock_ttl) { 60 }
|
34
|
-
let(:latency_threshold) { 60 }
|
35
|
-
let(:tenant_key) { ->(tenant_key, *_args) { tenant_key } }
|
36
|
-
let(:tenant_weights) { ->(tenant_keys) { tenant_keys.to_h { |tid| [tid, 1] } } }
|
37
|
-
|
38
|
-
describe "fairness (probabilistic)" do
|
39
|
-
# Seed Ruby's PRNG for deterministic results
|
40
|
-
around do |example|
|
41
|
-
prev = srand(1234)
|
42
|
-
example.run
|
43
|
-
ensure
|
44
|
-
srand(prev)
|
45
|
-
end
|
46
|
-
|
47
|
-
let(:enqueue_jobs) { 1000 }
|
48
|
-
let(:tenant_weights) do
|
49
|
-
->(tenant_ids) do
|
50
|
-
mapping = {"t1" => 1, "t2" => 3, "t3" => 6}
|
51
|
-
tenant_ids.to_h { |tid| [tid, mapping.fetch(tid, 1)] }
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
it "enqueues approximately proportional to weights" do
|
56
|
-
enqueue_jobs.times do |i|
|
57
|
-
FairplayJob.perform_async("t1", "a#{i}")
|
58
|
-
FairplayJob.perform_async("t2", "b#{i}")
|
59
|
-
FairplayJob.perform_async("t3", "c#{i}")
|
60
|
-
end
|
61
|
-
|
62
|
-
Sidekiq::Fairplay::Planner.new.perform("FairplayJob")
|
63
|
-
|
64
|
-
expect(FairplayJob).to have_enqueued_sidekiq_job.exactly(enqueue_jobs)
|
65
|
-
|
66
|
-
jobs_per_tenant = FairplayJob.jobs.each_with_object(Hash.new(0)) do |job, memo|
|
67
|
-
memo[job["args"].first] += 1
|
68
|
-
end
|
69
|
-
|
70
|
-
expected_jobs_per_tenant = {"t1" => 100, "t2" => 300, "t3" => 600}
|
71
|
-
tolerance = 0.25 # 25% tolerance to avoid flakiness across Ruby versions
|
72
|
-
|
73
|
-
expected_jobs_per_tenant.each do |tid, exp|
|
74
|
-
low = (exp * (1 - tolerance)).floor
|
75
|
-
high = (exp * (1 + tolerance)).ceil
|
76
|
-
|
77
|
-
expect(jobs_per_tenant[tid]).to be_between(low, high).inclusive
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
describe "basic functionality" do
|
83
|
-
it "intercepts fairplay jobs and enqueues them later" do
|
84
|
-
FairplayJob.perform_async("t1", "a")
|
85
|
-
FairplayJob.perform_async("t2", "b")
|
86
|
-
FairplayJob.perform_async("t3", "c")
|
87
|
-
|
88
|
-
expect(FairplayJob).not_to have_enqueued_sidekiq_job
|
89
|
-
expect(Sidekiq::Fairplay::Planner)
|
90
|
-
.to have_enqueued_sidekiq_job("FairplayJob")
|
91
|
-
.exactly(1)
|
92
|
-
.immediately
|
93
|
-
|
94
|
-
Sidekiq::Fairplay::Planner.perform_one
|
95
|
-
|
96
|
-
expect(FairplayJob).to have_enqueued_sidekiq_job.exactly(3)
|
97
|
-
expect(FairplayJob).to have_enqueued_sidekiq_job("t1", "a")
|
98
|
-
expect(FairplayJob).to have_enqueued_sidekiq_job("t2", "b")
|
99
|
-
expect(FairplayJob).to have_enqueued_sidekiq_job("t3", "c")
|
100
|
-
end
|
101
|
-
|
102
|
-
context "with custom planner queue" do
|
103
|
-
let(:planner_queue) { "whatever" }
|
104
|
-
|
105
|
-
it "enqueues the planner job on the configured queue" do
|
106
|
-
FairplayJob.perform_async("t1", "a")
|
107
|
-
|
108
|
-
Sidekiq::Fairplay::Planner.perform_one
|
109
|
-
|
110
|
-
expect(Sidekiq::Fairplay::Planner)
|
111
|
-
.to have_enqueued_sidekiq_job("FairplayJob")
|
112
|
-
.on(planner_queue)
|
113
|
-
.in(enqueue_interval.to_i)
|
114
|
-
|
115
|
-
expect(FairplayJob)
|
116
|
-
.to have_enqueued_sidekiq_job("t1", "a")
|
117
|
-
.on("default") # default queue for FairplayJob
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
context "when latency threshold exceeded" do
|
122
|
-
let(:queue) { instance_double(Sidekiq::Queue) }
|
123
|
-
|
124
|
-
before do
|
125
|
-
allow(Sidekiq::Queue).to receive(:new).and_return(queue)
|
126
|
-
allow(queue).to receive(:latency).and_return(latency_threshold.to_i + 1)
|
127
|
-
end
|
128
|
-
|
129
|
-
it "reschedules the planner without enqueuing jobs" do
|
130
|
-
FairplayJob.perform_async("t1", "a")
|
131
|
-
|
132
|
-
Sidekiq::Fairplay::Planner.perform_one
|
133
|
-
|
134
|
-
expect(FairplayJob).not_to have_enqueued_sidekiq_job
|
135
|
-
expect(Sidekiq::Fairplay::Planner)
|
136
|
-
.to have_enqueued_sidekiq_job("FairplayJob")
|
137
|
-
.in(enqueue_interval.to_i)
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
context "with custom weights" do
|
142
|
-
let(:tenant_weights) do
|
143
|
-
->(tenant_ids) do
|
144
|
-
tenant_ids.to_h do |tid|
|
145
|
-
[tid, (tid == "t1") ? 1 : 0]
|
146
|
-
end
|
147
|
-
end
|
148
|
-
end
|
149
|
-
|
150
|
-
it "uses weights to prefer specific tenant" do
|
151
|
-
FairplayJob.perform_async("t1", "a")
|
152
|
-
FairplayJob.perform_async("t2", "b")
|
153
|
-
|
154
|
-
Sidekiq::Fairplay::Planner.perform_one
|
155
|
-
|
156
|
-
expect(FairplayJob).to have_enqueued_sidekiq_job.exactly(1)
|
157
|
-
expect(FairplayJob).to have_enqueued_sidekiq_job("t1", "a")
|
158
|
-
expect(FairplayJob).not_to have_enqueued_sidekiq_job("t2", "b")
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
context "when too many jobs in the queue" do
|
163
|
-
let(:enqueue_jobs) { 1 }
|
164
|
-
|
165
|
-
it "respects the enqueue_jobs limit" do
|
166
|
-
FairplayJob.perform_async("t1", "a")
|
167
|
-
FairplayJob.perform_async("t1", "b")
|
168
|
-
|
169
|
-
Sidekiq::Fairplay::Planner.perform_one
|
170
|
-
|
171
|
-
expect(FairplayJob).to have_enqueued_sidekiq_job.exactly(1)
|
172
|
-
expect(FairplayJob)
|
173
|
-
.to have_enqueued_sidekiq_job("t1", "a")
|
174
|
-
.or have_enqueued_sidekiq_job("t1", "b")
|
175
|
-
end
|
176
|
-
end
|
177
|
-
end
|
178
|
-
|
179
|
-
describe "edge cases" do
|
180
|
-
it "ignores unknown job class" do
|
181
|
-
Sidekiq::Fairplay::Planner.new.perform("UnknownJob")
|
182
|
-
|
183
|
-
expect(Sidekiq::Fairplay::Planner).not_to have_enqueued_sidekiq_job
|
184
|
-
expect(FairplayJob).not_to have_enqueued_sidekiq_job
|
185
|
-
end
|
186
|
-
|
187
|
-
it "has no effect on regular jobs" do
|
188
|
-
RegularJob.perform_async("foo")
|
189
|
-
|
190
|
-
expect(RegularJob).to have_enqueued_sidekiq_job("foo")
|
191
|
-
expect(Sidekiq::Fairplay::Planner).not_to have_enqueued_sidekiq_job
|
192
|
-
end
|
193
|
-
|
194
|
-
it "has no effect on scheduled jobs" do
|
195
|
-
FairplayJob.perform_in(5, "t1", "a")
|
196
|
-
|
197
|
-
expect(FairplayJob).to have_enqueued_sidekiq_job("t1", "a").in(5)
|
198
|
-
expect(Sidekiq::Fairplay::Planner).not_to have_enqueued_sidekiq_job
|
199
|
-
end
|
200
|
-
|
201
|
-
context "with zero weights for all tenants" do
|
202
|
-
let(:tenant_weights) do
|
203
|
-
->(tenant_ids) { tenant_ids.to_h { |tid| [tid, 0] } }
|
204
|
-
end
|
205
|
-
|
206
|
-
it "enqueues no jobs" do
|
207
|
-
FairplayJob.perform_async("t1", "a")
|
208
|
-
FairplayJob.perform_async("t2", "b")
|
209
|
-
|
210
|
-
Sidekiq::Fairplay::Planner.perform_one
|
211
|
-
|
212
|
-
expect(FairplayJob).not_to have_enqueued_sidekiq_job
|
213
|
-
end
|
214
|
-
end
|
215
|
-
end
|
216
|
-
|
217
|
-
describe "errors" do
|
218
|
-
let(:tenant_key) { ->(_tid, *_args) {} }
|
219
|
-
|
220
|
-
it "raises when tenant key resolves to nil" do
|
221
|
-
tenant_key
|
222
|
-
|
223
|
-
expect { FairplayJob.perform_async("t1", "a") }
|
224
|
-
.to raise_error(ArgumentError, /tenant key cannot be nil/)
|
225
|
-
end
|
226
|
-
end
|
227
|
-
|
228
|
-
describe "implementation details" do
|
229
|
-
it "reschedules planning for the next interval" do
|
230
|
-
FairplayJob.perform_async("t1", "a")
|
231
|
-
|
232
|
-
Sidekiq::Fairplay::Planner.perform_one
|
233
|
-
|
234
|
-
expect(Sidekiq::Fairplay::Planner)
|
235
|
-
.to have_enqueued_sidekiq_job("FairplayJob")
|
236
|
-
.in(enqueue_interval.to_i)
|
237
|
-
end
|
238
|
-
|
239
|
-
context "when planner_lock_ttl is being held" do
|
240
|
-
let(:planner_lock_ttl) { 42 }
|
241
|
-
|
242
|
-
before do
|
243
|
-
redis = Sidekiq::Fairplay::Redis.new
|
244
|
-
redis.try_acquire_planner_lock(FairplayJob, "some_jid")
|
245
|
-
end
|
246
|
-
|
247
|
-
it "blocks planning until the TTL expires" do
|
248
|
-
FairplayJob.perform_async("t1", "a")
|
249
|
-
|
250
|
-
Sidekiq::Fairplay::Planner.perform_one
|
251
|
-
|
252
|
-
expect(FairplayJob).not_to have_enqueued_sidekiq_job
|
253
|
-
expect(Sidekiq::Fairplay::Planner)
|
254
|
-
.to have_enqueued_sidekiq_job("FairplayJob")
|
255
|
-
.in(enqueue_interval.to_i)
|
256
|
-
end
|
257
|
-
end
|
258
|
-
|
259
|
-
context "when tenant_key and tenant_weights refer to class methods" do
|
260
|
-
before do
|
261
|
-
class << FairplayJob
|
262
|
-
def static_tenant_key(tid, *_args) = tid
|
263
|
-
def static_tenant_weights(tids) = tids.to_h { |tid| [tid, 1] }
|
264
|
-
end
|
265
|
-
end
|
266
|
-
|
267
|
-
let(:tenant_key) { ->(tid, *args) { static_tenant_key(tid, *args) } }
|
268
|
-
let(:tenant_weights) { ->(tids) { static_tenant_weights(tids) } }
|
269
|
-
|
270
|
-
it "works as expected" do
|
271
|
-
FairplayJob.perform_async("t1", "a")
|
272
|
-
FairplayJob.perform_async("t2", "b")
|
273
|
-
|
274
|
-
Sidekiq::Fairplay::Planner.perform_one
|
275
|
-
|
276
|
-
expect(FairplayJob).to have_enqueued_sidekiq_job.exactly(2)
|
277
|
-
expect(FairplayJob).to have_enqueued_sidekiq_job("t1", "a")
|
278
|
-
expect(FairplayJob).to have_enqueued_sidekiq_job("t2", "b")
|
279
|
-
end
|
280
|
-
end
|
281
|
-
|
282
|
-
context "when using ActiveSupport::Duration" do
|
283
|
-
let(:enqueue_interval) { 1.minute }
|
284
|
-
let(:latency_threshold) { 1.hour }
|
285
|
-
let(:planner_lock_ttl) { 10.seconds }
|
286
|
-
|
287
|
-
it "handles durations correctly" do
|
288
|
-
FairplayJob.perform_async("t1", "a")
|
289
|
-
|
290
|
-
Sidekiq::Fairplay::Planner.perform_one
|
291
|
-
|
292
|
-
expect(Sidekiq::Fairplay::Planner)
|
293
|
-
.to have_enqueued_sidekiq_job("FairplayJob")
|
294
|
-
.in(enqueue_interval.to_i)
|
295
|
-
|
296
|
-
expect(FairplayJob).to have_enqueued_sidekiq_job.exactly(1)
|
297
|
-
expect(FairplayJob).to have_enqueued_sidekiq_job("t1", "a")
|
298
|
-
end
|
299
|
-
end
|
300
|
-
end
|
301
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,63 +0,0 @@
|
|
1
|
-
$LOAD_PATH << "." unless $LOAD_PATH.include?(".")
|
2
|
-
|
3
|
-
require "rubygems"
|
4
|
-
require "bundler/setup"
|
5
|
-
require "timecop"
|
6
|
-
require "simplecov"
|
7
|
-
|
8
|
-
require "sidekiq"
|
9
|
-
require "rspec-sidekiq"
|
10
|
-
require "sidekiq/fairplay"
|
11
|
-
require "pry"
|
12
|
-
|
13
|
-
SimpleCov.start do
|
14
|
-
add_filter "spec"
|
15
|
-
end
|
16
|
-
|
17
|
-
Sidekiq::Fairplay.logger = nil
|
18
|
-
|
19
|
-
Sidekiq.configure_client do |config|
|
20
|
-
config.redis = {db: 1}
|
21
|
-
config.logger = nil
|
22
|
-
|
23
|
-
config.client_middleware do |chain|
|
24
|
-
chain.add Sidekiq::Fairplay::Middleware
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
Sidekiq.configure_server do |config|
|
29
|
-
config.redis = {db: 1}
|
30
|
-
config.logger = nil
|
31
|
-
|
32
|
-
config.client_middleware do |chain|
|
33
|
-
chain.add Sidekiq::Fairplay::Middleware
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
RSpec::Sidekiq.configure do |config|
|
38
|
-
config.clear_all_enqueued_jobs = true
|
39
|
-
config.warn_when_jobs_not_processed_by_sidekiq = false
|
40
|
-
end
|
41
|
-
|
42
|
-
RSpec.configure do |config|
|
43
|
-
config.order = :random
|
44
|
-
config.run_all_when_everything_filtered = true
|
45
|
-
config.example_status_persistence_file_path = "spec/examples.txt"
|
46
|
-
|
47
|
-
config.before do
|
48
|
-
Sidekiq.redis do |conn|
|
49
|
-
keys = conn.call("KEYS", "fairplay*")
|
50
|
-
keys.each { |key| conn.call("DEL", key) }
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
config.before do
|
55
|
-
Timecop.freeze
|
56
|
-
end
|
57
|
-
|
58
|
-
config.after do
|
59
|
-
Timecop.return
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
$LOAD_PATH << File.join(File.dirname(__FILE__), "..", "lib")
|