sidekiq-fair_tenant 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +12 -0
- data/LICENSE.txt +21 -0
- data/README.md +160 -0
- data/lib/sidekiq/fair_tenant/client_middleware.rb +100 -0
- data/lib/sidekiq/fair_tenant/config.rb +21 -0
- data/lib/sidekiq/fair_tenant/version.rb +7 -0
- data/lib/sidekiq/fair_tenant.rb +36 -0
- data/sidekiq-fair_tenant.gemspec +37 -0
- metadata +90 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ff58bfdb071ee2b14924f2ff844ccd2ce488fe54e91ee19e7b96834a4b01e6c1
|
4
|
+
data.tar.gz: aba3f768b2b5c612936c336099ded364220943eda5b30ea02e4be2f5817b615d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fe50c83e1ba529bc0bfab3e036cc57dbe96d05285b2d939aa16c2a710a36925b383c9402d075811c365b26cfc4393933d64026e13c2413ecdc2d79dfbc9de1e1
|
7
|
+
data.tar.gz: 3ec788281b6dd892186cdc32bc97b09814964924a1a8feb130e92eb7f783f77bba1d0bc642d619175608accd66f9f3276ae6b43bbc04ef7e9f0f29f89011c5b3
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
All notable changes to this project will be documented in this file.
|
4
|
+
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
7
|
+
|
8
|
+
## [Unreleased]
|
9
|
+
|
10
|
+
## [0.1.0] - 2024-01-12
|
11
|
+
|
12
|
+
- Initial release: multiple rules, configurable throttling window.
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2024 Andrey Novikov
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
# Sidekiq::FairTenant
|
2
|
+
|
3
|
+
Throttle “greedy” clients’ jobs to ensure more or less fair distribution of resources between clients.
|
4
|
+
|
5
|
+
This tiny [Sidekiq] middleware will re-route client's jobs after certain threshold to throttled queues (defined by you), where they will be processed with reduced priority.
|
6
|
+
|
7
|
+
“Weighted queues” feature of Sidekiq allows to de-prioritize jobs in throttled queues, so they will not block jobs from other clients, at the same time preserving overall throughput.
|
8
|
+
|
9
|
+
<a href="https://evilmartians.com/?utm_source=sidekiq-fair_tenant">
|
10
|
+
<picture>
|
11
|
+
<source
|
12
|
+
media="(prefers-color-scheme: dark)"
|
13
|
+
srcset="https://evilmartians.com/badges/sponsored-by-evil-martians_v2.0_for-dark-bg@2x.png"
|
14
|
+
>
|
15
|
+
<img
|
16
|
+
src="https://evilmartians.com/badges/sponsored-by-evil-martians_v2.0@2x.png"
|
17
|
+
alt="Sponsored by Evil Martians"
|
18
|
+
width="236"
|
19
|
+
height="54"
|
20
|
+
>
|
21
|
+
</picture>
|
22
|
+
</a>
|
23
|
+
|
24
|
+
## Installation
|
25
|
+
|
26
|
+
1. Install the gem and add to the application's Gemfile by executing:
|
27
|
+
|
28
|
+
```sh
|
29
|
+
bundle add sidekiq-fair_tenant
|
30
|
+
```
|
31
|
+
|
32
|
+
2. Add `fair_tenant_queues` section to `sidekiq_options` in your job class:
|
33
|
+
|
34
|
+
```diff
|
35
|
+
class SomeJob
|
36
|
+
sidekiq_options \
|
37
|
+
queue: 'default',
|
38
|
+
+ fair_tenant_queues: [
|
39
|
+
+ { queue: 'throttled_2x', threshold: 100, per: 1.hour },
|
40
|
+
+ { queue: 'throttled_4x', threshold: 10, per: 1.minute },
|
41
|
+
+ ]
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
3. Add tenant detection login into your job class:
|
46
|
+
|
47
|
+
```diff
|
48
|
+
class SomeJob
|
49
|
+
+ def self.fair_tenant(*_perform_arguments)
|
50
|
+
+ # Return any string that will be used as tenant name
|
51
|
+
+ "tenant_1"
|
52
|
+
+ end
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
4. Add throttled queues with reduced weights to your Sidekiq configuration:
|
57
|
+
|
58
|
+
```diff
|
59
|
+
# config/sidekiq.yml
|
60
|
+
:queues:
|
61
|
+
- [default, 4]
|
62
|
+
+ - [throttled_2x, 2]
|
63
|
+
+ - [throttled_4x, 1]
|
64
|
+
```
|
65
|
+
|
66
|
+
See [Sidekiq Advanced options for Queues](https://github.com/sidekiq/sidekiq/wiki/Advanced-Options#queues) to learn more about queue weights.
|
67
|
+
|
68
|
+
## Usage
|
69
|
+
|
70
|
+
### Specifying throttling rules
|
71
|
+
|
72
|
+
In your job class, add `fair_tenant_queues` section to `sidekiq_options` as array of hashes with following keys:
|
73
|
+
|
74
|
+
- `queue` - throttled queue name to re-route jobs into.
|
75
|
+
- `threshold` - maximum number of jobs allowed to be enqueued within `per` seconds.
|
76
|
+
- `per` - sliding time window in seconds to count jobs (you can use ActiveSupport Durations in Rails).
|
77
|
+
|
78
|
+
You can specify multiple rules and they all will be checked. _Last_ matching rule will be used, so order rules from least to most restrictive.
|
79
|
+
|
80
|
+
Example:
|
81
|
+
|
82
|
+
```ruby
|
83
|
+
sidekiq_options \
|
84
|
+
queue: 'default',
|
85
|
+
fair_tenant_queues: [
|
86
|
+
# First rule is less restrictive, reacting to a large number of jobs enqueued in a long time window
|
87
|
+
{ queue: 'throttled_2x', threshold: 1_000, per: 1.day },
|
88
|
+
# Next rule is more restrictive, reacting to spikes of jobs in a short time window
|
89
|
+
{ queue: 'throttled_4x', threshold: 10, per: 1.minute },
|
90
|
+
]
|
91
|
+
```
|
92
|
+
|
93
|
+
### Specifying tenant
|
94
|
+
|
95
|
+
1. Explicitly during job enqueuing:
|
96
|
+
|
97
|
+
```ruby
|
98
|
+
SomeJob.set(fair_tenant: 'tenant_1').perform_async
|
99
|
+
```
|
100
|
+
|
101
|
+
2. Dynamically using `fair_tenant` class-level method in your job class (receives same arguments as `perform`)
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
class SomeJob
|
105
|
+
def self.fair_tenant(*_perform_arguments)
|
106
|
+
# Return any string that will be used as tenant name
|
107
|
+
"tenant_1"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
```
|
111
|
+
|
112
|
+
3. Set `fair_tenant` job option in a custom [middleware](https://github.com/sidekiq/sidekiq/wiki/Middleware) earlier in the stack.
|
113
|
+
|
114
|
+
4. Or let this gem automatically pick tenant name from [apartment-sidekiq](https://github.com/influitive/apartment-sidekiq) if you're using apartment gem.
|
115
|
+
|
116
|
+
## Configuration
|
117
|
+
|
118
|
+
Configuration is handled by [anyway_config] gem. With it you can load settings from environment variables (which names are constructed from config key upcased and prefixed with `SIDEKIQ_FAIR_TENANT_`), YAML files, and other sources. See [anyway_config] docs for details.
|
119
|
+
|
120
|
+
| Config key | Type | Default | Description |
|
121
|
+
|----------------------------|----------|---------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
122
|
+
| `max_throttling_window` | integer | `86_400` (1 day) | Maximum throttling window in seconds |
|
123
|
+
| `enqueues_key` | string | `sidekiq-fair_tenant:enqueued:%<job_class>s:tenant:%<fair_tenant>s` | Ruby [format string](https://docs.ruby-lang.org/en/3.3/format_specifications_rdoc.html) used as a name for Redis key holding job ids for throttling window. Available placeholders: `queue`, `job_class`, `fair_tenant` |
|
124
|
+
| `logger` | logger | `Sidekiq.logger` | Logger instance used for warning logging. |
|
125
|
+
|
126
|
+
## How it works
|
127
|
+
|
128
|
+
If number of jobs enqueued by a single client exceeds some threshold per a sliding time window, their jobs would be re-routed to another queue, with lower priority.
|
129
|
+
|
130
|
+
This gem tracks single client's jobs in a Redis [sorted set](https://redis.io/docs/data-types/sorted-sets/) with job id as a key and enqueuing timestamp as a score. When a new job is enqueued, it is added to the set, and then the set is trimmed to contain only jobs enqueued within the last `max_throttling_window` seconds.
|
131
|
+
|
132
|
+
On every enqueue attempt, the set is checked for number of jobs enqueued within the last `per` seconds of every rule. If the number of jobs in this time window exceeds `threshold`, the job is enqueued to a throttled queue, otherwise it is enqueued to the default queue. If multiple rules match, last one is used.
|
133
|
+
|
134
|
+
You are expected to configure Sidekiq to process throttled queues with lower priority using [queue weights](https://github.com/mperham/sidekiq/wiki/Advanced-Options#queues).
|
135
|
+
|
136
|
+
### Advantages
|
137
|
+
- If fast queues are empty then slow queues are processed at full speed (no artificial delays)
|
138
|
+
- If fast queues are full, slow queues are still processed, but slower (configurable), so application doesn’t “stall” for throttled users
|
139
|
+
- Minimal changes to the application code are required.
|
140
|
+
|
141
|
+
### Disadvantages
|
142
|
+
- As Sidekiq does not support mixing ordered and weighted queue modes (as stated in Sidekiq Wiki on queue configuration), you can’t make the same worker process execute some super important queue always first, ignoring other queues. Run separate worker to solve this.
|
143
|
+
- You have to keep track of all your queues and their weights.
|
144
|
+
|
145
|
+
## Development
|
146
|
+
|
147
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
148
|
+
|
149
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
150
|
+
|
151
|
+
## Contributing
|
152
|
+
|
153
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/sidekiq-fair_tenant.
|
154
|
+
|
155
|
+
## License
|
156
|
+
|
157
|
+
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
158
|
+
|
159
|
+
[sidekiq]: https://github.com/sidekiq/sidekiq "Simple, efficient background processing for Ruby"
|
160
|
+
[anyway_config]: https://github.com/palkan/anyway_config "Configuration library for Ruby gems and applications"
|
@@ -0,0 +1,100 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Sidekiq
|
4
|
+
module FairTenant
|
5
|
+
# Client middleware re-routing jobs of overly active tenants to slower queues based on thresholds
|
6
|
+
class ClientMiddleware
|
7
|
+
# Re-routes job to the most appropriate queue, based on tenant's throttling rules
|
8
|
+
# rubocop:disable Metrics/MethodLength
|
9
|
+
def call(worker, job, queue, redis_pool)
|
10
|
+
job_class = job_class(worker, job)
|
11
|
+
arguments = job["wrapped"] ? job.dig("args", 0, "arguments") : job["args"]
|
12
|
+
return yield unless enabled?(job_class, job, queue)
|
13
|
+
|
14
|
+
job["fair_tenant"] ||= tenant_id(job_class, job, arguments)
|
15
|
+
unless job["fair_tenant"]
|
16
|
+
logger.warn "#{job_class} with args #{arguments.inspect} won't be throttled: missing `fair_tenant` in job"
|
17
|
+
return yield
|
18
|
+
end
|
19
|
+
|
20
|
+
redis_pool.then do |redis|
|
21
|
+
register_job(job_class, job, queue, redis)
|
22
|
+
job["queue"] = assign_queue(job_class, job, queue, redis)
|
23
|
+
end
|
24
|
+
|
25
|
+
yield
|
26
|
+
end
|
27
|
+
# rubocop:enable Metrics/MethodLength
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def enabled?(job_class, job, queue)
|
32
|
+
return false if job["fair_tenant_queues"].blank? # Not configured for throttling
|
33
|
+
|
34
|
+
original_queue = original_queue(job_class, job, queue)
|
35
|
+
return false if original_queue != job["queue"] # Someone already rerouted this job, nothing to do here
|
36
|
+
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
40
|
+
# Writes job to sliding window sorted set
|
41
|
+
def register_job(job_class, job, queue, redis)
|
42
|
+
enqueues_key = enqueues_key(job_class, job, queue)
|
43
|
+
max_throttling_window = Sidekiq::FairTenant.max_throttling_window
|
44
|
+
redis.multi do |tx|
|
45
|
+
tx.zremrangebyscore(enqueues_key, "-inf", (Time.now - max_throttling_window).to_i)
|
46
|
+
tx.zadd(enqueues_key, Time.now.to_i, "jid:#{job["jid"]}")
|
47
|
+
tx.expire(enqueues_key, max_throttling_window)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Chooses the last queue, for the most restrictive (threshold/time) rule that is met.
|
52
|
+
# Assumes the slowest queue, with most restrictive rule, comes last in the `fair_tenants` array.
|
53
|
+
def assign_queue(job_class, job, queue, redis)
|
54
|
+
enqueues_key = enqueues_key(job_class, job, queue)
|
55
|
+
|
56
|
+
matching_rules =
|
57
|
+
job["fair_tenant_queues"].map(&:symbolize_keys).filter do |config|
|
58
|
+
threshold = config[:threshold]
|
59
|
+
window_start = Time.now - (config[:per] || Sidekiq::FairTenant.max_throttling_window)
|
60
|
+
threshold < redis.zcount(enqueues_key, window_start.to_i, Time.now.to_i)
|
61
|
+
end
|
62
|
+
|
63
|
+
matching_rules.any? ? matching_rules.last[:queue] : queue
|
64
|
+
end
|
65
|
+
|
66
|
+
def enqueues_key(job_class, job, queue)
|
67
|
+
format(Sidekiq::FairTenant.enqueues_key, queue: queue, fair_tenant: job["fair_tenant"], job_class: job_class)
|
68
|
+
end
|
69
|
+
|
70
|
+
def job_class(worker, job)
|
71
|
+
job_class = job["wrapped"] || worker
|
72
|
+
return job_class if job_class.is_a?(Class)
|
73
|
+
return job_class.constantize if job_class.respond_to?(:constantize)
|
74
|
+
|
75
|
+
Object.const_get(job_class.to_s)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Calculates tenant identifier (`fair_tenant`) for the job
|
79
|
+
def tenant_id(job_class, job, arguments)
|
80
|
+
return job_class.fair_tenant(*arguments) if job_class.respond_to?(:fair_tenant)
|
81
|
+
|
82
|
+
job["apartment"] # for compatibility with sidekiq-apartment
|
83
|
+
end
|
84
|
+
|
85
|
+
def original_queue(job_class, _job, queue)
|
86
|
+
if job_class.respond_to?(:queue_name)
|
87
|
+
job_class.queue_name # ActiveJob
|
88
|
+
elsif job_class.respond_to?(:queue)
|
89
|
+
job_class.queue.to_s # Sidekiq
|
90
|
+
else
|
91
|
+
queue
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def logger
|
96
|
+
Sidekiq::FairTenant.logger
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "anyway"
|
4
|
+
|
5
|
+
module Sidekiq
|
6
|
+
module FairTenant
|
7
|
+
# Runtime configuration for the sidekiq-fair_tenant gem
|
8
|
+
class Config < ::Anyway::Config
|
9
|
+
config_name :sidekiq_fair_tenant
|
10
|
+
|
11
|
+
# Maximum amount of time to store information about tenant enqueues
|
12
|
+
attr_config max_throttling_window: 86_400 # 1 day
|
13
|
+
|
14
|
+
# Sorted set that contains job ids enqueued by each tenant in last 1 day (max throttling window)
|
15
|
+
attr_config enqueues_key: "sidekiq-fair_tenant:enqueued:%<job_class>s:tenant:%<fair_tenant>s"
|
16
|
+
|
17
|
+
# Logger to use for throttling warnings
|
18
|
+
attr_config logger: ::Sidekiq.logger
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "sidekiq"
|
4
|
+
|
5
|
+
require_relative "fair_tenant/version"
|
6
|
+
require_relative "fair_tenant/config"
|
7
|
+
require_relative "fair_tenant/client_middleware"
|
8
|
+
|
9
|
+
module Sidekiq
|
10
|
+
# Client middleware and job DSL for throttling jobs of overly active tenants
|
11
|
+
module FairTenant
|
12
|
+
class Error < ::StandardError; end
|
13
|
+
|
14
|
+
class << self
|
15
|
+
extend ::Forwardable
|
16
|
+
|
17
|
+
def config
|
18
|
+
@config ||= Config.new
|
19
|
+
end
|
20
|
+
|
21
|
+
def_delegators :config, :max_throttling_window, :enqueues_key, :logger
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
Sidekiq.configure_client do |config|
|
27
|
+
config.client_middleware do |chain|
|
28
|
+
chain.add Sidekiq::FairTenant::ClientMiddleware
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
Sidekiq.configure_server do |config|
|
33
|
+
config.client_middleware do |chain|
|
34
|
+
chain.add Sidekiq::FairTenant::ClientMiddleware
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "lib/sidekiq/fair_tenant/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = "sidekiq-fair_tenant"
|
7
|
+
spec.version = Sidekiq::FairTenant::VERSION
|
8
|
+
spec.authors = ["Andrey Novikov"]
|
9
|
+
spec.email = ["envek@envek.name"]
|
10
|
+
|
11
|
+
spec.summary = "Throttle Sidekiq jobs of greedy tenants"
|
12
|
+
spec.description = "Re-route jobs of way too active tenants to slower queues, letting other tenant's jobs to go first"
|
13
|
+
spec.homepage = "https://github.com/Envek/sidekiq-fair_tenant"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.required_ruby_version = ">= 2.6.0"
|
16
|
+
|
17
|
+
spec.metadata["homepage_uri"] = spec.homepage
|
18
|
+
spec.metadata["source_code_uri"] = "https://github.com/Envek/sidekiq-fair_tenant"
|
19
|
+
spec.metadata["changelog_uri"] = "https://github.com/Envek/sidekiq-fair_tenant/blob/master/CHANGELOG.md"
|
20
|
+
spec.metadata["rubygems_mfa_required"] = "true"
|
21
|
+
|
22
|
+
# Specify which files should be added to the gem when it is released.
|
23
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
24
|
+
spec.files = Dir.chdir(__dir__) do
|
25
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
26
|
+
(File.expand_path(f) == __FILE__) ||
|
27
|
+
f.start_with?(*%w[bin/ spec/ Gemfile Rakefile]) ||
|
28
|
+
f.match(/^(\.)/)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
spec.bindir = "exe"
|
32
|
+
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
|
33
|
+
spec.require_paths = ["lib"]
|
34
|
+
|
35
|
+
spec.add_dependency "anyway_config", ">= 1.0", "< 3"
|
36
|
+
spec.add_dependency "sidekiq", ">= 5"
|
37
|
+
end
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sidekiq-fair_tenant
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Andrey Novikov
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-01-12 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: anyway_config
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '3'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '1.0'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '3'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: sidekiq
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '5'
|
40
|
+
type: :runtime
|
41
|
+
prerelease: false
|
42
|
+
version_requirements: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '5'
|
47
|
+
description: Re-route jobs of way too active tenants to slower queues, letting other
|
48
|
+
tenant's jobs to go first
|
49
|
+
email:
|
50
|
+
- envek@envek.name
|
51
|
+
executables: []
|
52
|
+
extensions: []
|
53
|
+
extra_rdoc_files: []
|
54
|
+
files:
|
55
|
+
- CHANGELOG.md
|
56
|
+
- LICENSE.txt
|
57
|
+
- README.md
|
58
|
+
- lib/sidekiq/fair_tenant.rb
|
59
|
+
- lib/sidekiq/fair_tenant/client_middleware.rb
|
60
|
+
- lib/sidekiq/fair_tenant/config.rb
|
61
|
+
- lib/sidekiq/fair_tenant/version.rb
|
62
|
+
- sidekiq-fair_tenant.gemspec
|
63
|
+
homepage: https://github.com/Envek/sidekiq-fair_tenant
|
64
|
+
licenses:
|
65
|
+
- MIT
|
66
|
+
metadata:
|
67
|
+
homepage_uri: https://github.com/Envek/sidekiq-fair_tenant
|
68
|
+
source_code_uri: https://github.com/Envek/sidekiq-fair_tenant
|
69
|
+
changelog_uri: https://github.com/Envek/sidekiq-fair_tenant/blob/master/CHANGELOG.md
|
70
|
+
rubygems_mfa_required: 'true'
|
71
|
+
post_install_message:
|
72
|
+
rdoc_options: []
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: 2.6.0
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
version: '0'
|
85
|
+
requirements: []
|
86
|
+
rubygems_version: 3.5.3
|
87
|
+
signing_key:
|
88
|
+
specification_version: 4
|
89
|
+
summary: Throttle Sidekiq jobs of greedy tenants
|
90
|
+
test_files: []
|