merge 6.5
This commit is contained in:
commit
2ee7e27697
|
@ -90,6 +90,11 @@ rails s
|
|||
git checkout -b new_feature_name
|
||||
```
|
||||
|
||||
### 11. Keep your forked branch up to date with changes in main repo
|
||||
```
|
||||
git pull upstream main
|
||||
```
|
||||
|
||||
## Legal
|
||||
|
||||
By submitting a Pull Request, you disavow any rights or claims to any changes
|
||||
|
|
|
@ -0,0 +1,6 @@
|
|||
version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
interval: "weekly"
|
|
@ -6,6 +6,9 @@ on:
|
|||
pull_request:
|
||||
branches: [ "main", "7-0" ]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
test:
|
||||
|
||||
|
@ -27,7 +30,7 @@ jobs:
|
|||
- 6379:6379
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Ruby
|
||||
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
||||
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
name: 'Dependency Review'
|
||||
on: [pull_request]
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
dependency-review:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: 'Checkout Repository'
|
||||
uses: actions/checkout@v3
|
||||
- name: 'Dependency Review'
|
||||
uses: actions/dependency-review-action@v1
|
|
@ -16,3 +16,4 @@ development.log
|
|||
/Makefile
|
||||
/docker-compose.yml
|
||||
Gemfile.lock
|
||||
*.DS_Store
|
||||
|
|
|
@ -2,12 +2,12 @@ ruby_version: 2.7.0
|
|||
fix: true
|
||||
parallel: true
|
||||
ignore:
|
||||
- test/**/*
|
||||
- examples/**/*
|
||||
- myapp/**/*
|
||||
- 'lib/sidekiq.rb':
|
||||
- Lint/InheritException
|
||||
- 'lib/**/*':
|
||||
- '**/*':
|
||||
- Lint/RescueException
|
||||
- Security/YAMLLoad
|
||||
- Style/GlobalVars
|
||||
- 'test/test*.rb':
|
||||
- Lint/ConstantDefinitionInBlock
|
||||
|
||||
|
|
12
Changes.md
12
Changes.md
|
@ -2,20 +2,22 @@
|
|||
|
||||
[Sidekiq Changes](https://github.com/mperham/sidekiq/blob/main/Changes.md) | [Sidekiq Pro Changes](https://github.com/mperham/sidekiq/blob/main/Pro-Changes.md) | [Sidekiq Enterprise Changes](https://github.com/mperham/sidekiq/blob/main/Ent-Changes.md)
|
||||
|
||||
HEAD
|
||||
6.5.0
|
||||
---------
|
||||
|
||||
- Add **beta** support for the `redis-client` gem**. This will become the default Redis driver in Sidekiq 7.0. [#5298]
|
||||
- Substantial refactoring of Sidekiq server internals, part of a larger effort
|
||||
to reduce Sidekiq's internal usage of global methods and data, see [docs/global_to_local.md](docs/global_to_local.md) and [docs/middleware.md](docs/middleware.md).
|
||||
- **Add beta support for the `redis-client` gem**. This will become the default Redis driver in Sidekiq 7.0. [#5298]
|
||||
Read more: https://github.com/mperham/sidekiq/wiki/Using-redis-client
|
||||
- Add **beta** support for DB transaction-aware client [#5291]
|
||||
- **Add beta support for DB transaction-aware client** [#5291]
|
||||
Add this line to your initializer and any jobs created during a transaction
|
||||
will only be pushed to Redis **after the transaction commits**. You will need to add the
|
||||
`after_commit_everywhere` gem to your Gemfile.
|
||||
```ruby
|
||||
Sidekiq.transactional_push!
|
||||
```
|
||||
This feature is still beta quality; please try it out and let us know if you
|
||||
have any issues. It will be fully supported in Sidekiq 7.0 or removed if it
|
||||
This feature does not have a lot of production usage yet; please try it out and let us
|
||||
know if you have any issues. It will be fully supported in Sidekiq 7.0 or removed if it
|
||||
proves problematic.
|
||||
- Fix regression with middleware arguments [#5312]
|
||||
|
||||
|
|
|
@ -4,6 +4,14 @@
|
|||
|
||||
Please see [sidekiq.org](https://sidekiq.org) for more details and how to buy.
|
||||
|
||||
2.5.0
|
||||
-------------
|
||||
|
||||
- Per the 2.0 upgrade notes, Sidekiq Enterprise will stop if you do not have valid
|
||||
credentials configured on startup.
|
||||
- Internal refactoring for Sidekiq 6.5.
|
||||
- Requires Sidekiq 6.5, Pro 5.5.
|
||||
|
||||
2.3.1
|
||||
-------------
|
||||
|
||||
|
|
3
Gemfile
3
Gemfile
|
@ -4,7 +4,7 @@ gemspec
|
|||
|
||||
gem "rake"
|
||||
gem "rails"
|
||||
gem "redis-client", github: "redis-rb/redis-client"
|
||||
gem "redis-client"
|
||||
|
||||
# Required for Ruby 3.1
|
||||
# https://github.com/mikel/mail/pull/1439
|
||||
|
@ -15,6 +15,7 @@ gem "net-pop"
|
|||
gem "sqlite3", platforms: :ruby
|
||||
gem "activerecord-jdbcsqlite3-adapter", platforms: :jruby
|
||||
gem "after_commit_everywhere"
|
||||
gem "yard"
|
||||
|
||||
group :test do
|
||||
gem "minitest"
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
|
||||
Please see [sidekiq.org](https://sidekiq.org/) for more details and how to buy.
|
||||
|
||||
HEAD
|
||||
5.5.0
|
||||
---------
|
||||
|
||||
- DEPRECATION: remove support for statsd-ruby via `Sidekiq::Pro.statsd`.
|
||||
|
@ -20,6 +20,8 @@ end
|
|||
- Excise "worker" terminology from codebase [#4955]
|
||||
- Ensure batch callback metrics are always fired [#5217]
|
||||
- Added `error_type` tag for `job.failures` metrics [#5211]
|
||||
- Internal refactoring for Sidekiq 6.5.
|
||||
- Requires Sidekiq 6.5.
|
||||
|
||||
5.3.1
|
||||
---------
|
||||
|
|
10
Rakefile
10
Rakefile
|
@ -1,6 +1,16 @@
|
|||
require "bundler/gem_tasks"
|
||||
require "rake/testtask"
|
||||
require "standard/rake"
|
||||
require "rdoc/task"
|
||||
|
||||
RDoc::Task.new do |rdoc|
|
||||
rdoc.main = "docs/rdoc.rdoc"
|
||||
rdoc.rdoc_files.include("docs/rdoc.rdoc",
|
||||
"lib/sidekiq/api.rb",
|
||||
"lib/sidekiq/client.rb",
|
||||
"lib/sidekiq/worker.rb",
|
||||
"lib/sidekiq/job.rb")
|
||||
end
|
||||
|
||||
Rake::TestTask.new(:test) do |test|
|
||||
test.warning = true
|
||||
|
|
|
@ -52,7 +52,7 @@ Both Heroku and ECS now use 30 second shutdown timeout
|
|||
by default and we want Sidekiq to take advantage of this time. If you
|
||||
have deployment scripts which depend on the old default timeout, use `-t 8` to
|
||||
get the old behavior. [#3968]
|
||||
* **Rails <5** is no longer supported. Rails 6+ only works in zeitwerk mode.
|
||||
* **Rails <5** is no longer supported.
|
||||
* **Ruby <2.5** is no longer supported.
|
||||
* **Redis <4** is no longer supported.
|
||||
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
# Sidekiq 7.0 Components
|
||||
|
||||
Sidekiq 7.0 contains the largest internal refactoring since Sidekiq 4.0.
|
||||
This refactoring is designed to improve deployment flexibility and allow
|
||||
new use cases.
|
||||
|
||||
# The Problem
|
||||
|
||||
Sidekiq today uses a large number of class-level methods to access things
|
||||
like the Redis connection pool, the logger, and process configuration, e.g.
|
||||
|
||||
```ruby
|
||||
Sidekiq.logger.info "Hello world"
|
||||
Sidekiq.redis {|c| c.sadd("some_set", "new_member") }
|
||||
Sidekiq.configure_server {|config| config... }
|
||||
```
|
||||
|
||||
The problem is that this pattern implies a global, mutable singleton.
|
||||
It does not work with Ractors. It does not allow multiple instances in one process.
|
||||
It does not allow embedding within another Ruby process (e.g. puma).
|
||||
Today the only supported Sidekiq deployment pattern is running `bundle exec sidekiq`.
|
||||
|
||||
# The Solution
|
||||
|
||||
Sidekiq 7.0 aims to refactor Sidekiq internals to allow more flexibility in how
|
||||
Sidekiq can be used.
|
||||
|
||||
## Sidekiq::Config
|
||||
|
||||
`Sidekiq::Config` represents the configuration for an instance of Sidekiq. Sidekiq::CLI
|
||||
creates a `Sidekiq::Config` instance and mutates it according to the command line parameters
|
||||
and the data in `config/sidekiq.yml`.
|
||||
|
||||
`Sidekiq::Launcher` is the top-level component which takes a `Sidekiq::Config` and creates the
|
||||
tree of runtime components. Once passed to Launcher, the Config is frozen and immutable.
|
||||
|
||||
Every internal component of Sidekiq takes a `Sidekiq::Config` instance and uses it. The Config
|
||||
holds previously "global" state like the connection pool, error handlers, lifecycle callbacks, etc.
|
||||
|
||||
## Sidekiq::Component
|
||||
|
||||
`Sidekiq::Component` is a module which provides helpful methods based on a `config` reader:
|
||||
|
||||
```ruby
|
||||
module Sidekiq::Component
|
||||
def config
|
||||
@config
|
||||
end
|
||||
|
||||
def redis(&block)
|
||||
config.redis(&block)
|
||||
end
|
||||
|
||||
def logger
|
||||
config.logger
|
||||
end
|
||||
|
||||
def handle_exception(ex, ctx)
|
||||
# avoids calling `Sidekiq.error_handlers...`
|
||||
config.handle_exception(ex, ctx)
|
||||
end
|
||||
end
|
||||
|
||||
class Sidekiq::Processor
|
||||
include Sidekiq::Component
|
||||
|
||||
def initialize(config)
|
||||
@config = config
|
||||
end
|
||||
|
||||
def ...
|
||||
# old
|
||||
Sidekiq.redis {|c| ... }
|
||||
Sidekiq.logger.info "Hello world!"
|
||||
# new
|
||||
redis {|c| ... }
|
||||
logger.info "Hello world!"
|
||||
rescue => ex
|
||||
handle_exception(ex, ...)
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
With this pattern, we greatly reduce the use of global APIs throughout Sidekiq internals.
|
||||
Where beforefore we'd call `Sidekiq.xyz`, we instead provide similar functionality like
|
||||
`config.xyz`.
|
|
@ -0,0 +1,56 @@
|
|||
# Reducing Global API usage in Sidekiq 7.0
|
||||
|
||||
In Sidekiq 6.x, we rely heavily on top-level APIs and options within the Sidekiq module itself. APIs like `Sidekiq.options` are used everywhere to pull dynamic configuration.
|
||||
This makes Sidekiq incompatible with Ractors or embedding within other processes.
|
||||
|
||||
# Implicit Configuration
|
||||
|
||||
Since the beginning, Sidekiq has used a global singleton for configuration. This was
|
||||
accessed via `Sidekiq.configure_{client,server} do |config|`. You don't create a Sidekiq
|
||||
instance but one is implicitly provided for you to configure.
|
||||
|
||||
Moving forward we want move to a more explicit `Sidekiq::Config` API which encapsulates this data. We provide backwards compatibility for the most widely used patterns but a few things
|
||||
will need to change:
|
||||
|
||||
```ruby
|
||||
# In 6.x `config` points to the Sidekiq module directly.
|
||||
# In 7.x it will be an instance of Sidekiq::Config.
|
||||
Sidekiq.configure_server do |config|
|
||||
config.options[:concurrency] = 5 # Sidekiq.options is deprecated
|
||||
config.concurrency = 5 # new
|
||||
end
|
||||
```
|
||||
|
||||
To be clear: `Sidekiq.configure_{client,server}` will remain supported for the
|
||||
foreseeable future. How Sidekiq works by default will remain very, very similar but these
|
||||
small tweaks will allow a new mode of operation for Sidekiq and unlock a few, new usecases...
|
||||
|
||||
# Explicit Configuration
|
||||
|
||||
Sidekiq 7.0 is expected to provide a new Ruby API for configuring and launching Sidekiq
|
||||
instances within an existing Ruby process. For instance, you could launch Sidekiq
|
||||
within a Puma process if you wanted to minimize the memory required for two separate
|
||||
processes (of course, the normal GIL caveats apply: one core can only handle so many requests and jobs). I call this **embedded mode**.
|
||||
|
||||
Another idea: you could start a second, small instance within your main Sidekiq process
|
||||
to limit concurrent job execution for a special queue. Maybe those jobs aren't thread-safe
|
||||
or use a 3rd party service which imposes a very limited access policy.
|
||||
|
||||
```ruby
|
||||
cfg = Sidekiq::Config.new
|
||||
cfg.concurrency = 1
|
||||
cfg.queues = %w[limited]
|
||||
|
||||
launcher = Sidekiq::Launcher.new(cfg) # cfg is now frozen!
|
||||
launcher.start
|
||||
# processing jobs!
|
||||
launcher.stop
|
||||
```
|
||||
|
||||
## Notes
|
||||
|
||||
- Every `Sidekiq::Launcher` instance is considered a separate "process" in the Web UI. You
|
||||
could launch N instances within one Ruby process and the Web UI will show N "processes". Why you'd want to do this, I don't know. "Just because you can doesn't mean you should" remains true.
|
||||
- How this configuration refactoring affects Sidekiq Pro and Sidekiq Enterprise remains to be
|
||||
seen. Existing functionality will remain supported and any breakage will be
|
||||
documented in the major version upgrade notes.
|
|
@ -0,0 +1,87 @@
|
|||
# Middleware Changes in Sidekiq 7.0
|
||||
|
||||
With the internal refactoring coming in Sidekiq 7.0 it is necessary
|
||||
to make minor changes to the Middleware API.
|
||||
|
||||
> tl;dr - middleware should now include Sidekiq::ClientMiddleware or Sidekiq::ServerMiddleware.
|
||||
|
||||
Currently the middleware API looks like this:
|
||||
|
||||
## Existing Client API
|
||||
|
||||
Client middleware is run when pushing a job to Redis.
|
||||
|
||||
```ruby
|
||||
class Client
|
||||
def initialize(optional_args)
|
||||
@args = optional_args
|
||||
end
|
||||
def call(worker, job, queue, redis_pool)
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
Sidekiq.configure_client do |config|
|
||||
config.client_middleware do |chain|
|
||||
chain.add Client, optional_args
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
## Server
|
||||
|
||||
Server middleware is run around job execution.
|
||||
|
||||
```ruby
|
||||
class Server
|
||||
def initialize(optional_args)
|
||||
@args = optional_args
|
||||
end
|
||||
def call(worker, job, queue)
|
||||
Sidekiq.redis {|c| c.do_something }
|
||||
Sidekiq.logger.info { "Some message" }
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
Sidekiq.configure_server do |config|
|
||||
config.server_middleware do |chain|
|
||||
chain.add Server, optional_args
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
## Updated API
|
||||
|
||||
The updated middleware API requires the middleware class to include
|
||||
a helper module.
|
||||
|
||||
```ruby
|
||||
class Client
|
||||
include Sidekiq::ClientMiddleware
|
||||
|
||||
def initialize(optional_args)
|
||||
@args = optional_args
|
||||
end
|
||||
def call(worker, job, queue, redis_pool)
|
||||
yield
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
```ruby
|
||||
class Server
|
||||
include Sidekiq::ServerMiddleware
|
||||
|
||||
def initialize(optional_args)
|
||||
@args = optional_args
|
||||
end
|
||||
def call(worker, job, queue)
|
||||
# note we no longer need to use the global Sidekiq module
|
||||
# to access Redis and the logger
|
||||
redis {|c| c.do_something }
|
||||
logger.info { "Some message" }
|
||||
yield
|
||||
end
|
||||
end
|
||||
```
|
|
@ -1,4 +1,4 @@
|
|||
require 'sidekiq'
|
||||
require "sidekiq"
|
||||
|
||||
# Start up sidekiq via
|
||||
# ./bin/sidekiq -r ./examples/por.rb
|
||||
|
@ -10,7 +10,7 @@ require 'sidekiq'
|
|||
class PlainOldRuby
|
||||
include Sidekiq::Job
|
||||
|
||||
def perform(how_hard="super hard", how_long=1)
|
||||
def perform(how_hard = "super hard", how_long = 1)
|
||||
sleep how_long
|
||||
puts "Workin' #{how_hard}"
|
||||
end
|
||||
|
|
|
@ -5,6 +5,7 @@ fail "Sidekiq #{Sidekiq::VERSION} does not support Ruby versions below 2.7.0." i
|
|||
|
||||
require "sidekiq/logger"
|
||||
require "sidekiq/client"
|
||||
require "sidekiq/transaction_aware_client"
|
||||
require "sidekiq/job"
|
||||
require "sidekiq/worker_compatibility_alias"
|
||||
require "sidekiq/redis_client_adapter"
|
||||
|
@ -51,19 +52,79 @@ module Sidekiq
|
|||
puts "Take a deep breath and count to ten..."
|
||||
end
|
||||
|
||||
# config.concurrency = 5
|
||||
def self.concurrency=(val)
|
||||
self[:concurrency] = Integer(val)
|
||||
end
|
||||
|
||||
# config.queues = %w( high default low ) # strict
|
||||
# config.queues = %w( high,3 default,2 low,1 ) # weighted
|
||||
# config.queues = %w( feature1,1 feature2,1 feature3,1 ) # random
|
||||
#
|
||||
# With weighted priority, queue will be checked first (weight / total) of the time.
|
||||
# high will be checked first (3/6) or 50% of the time.
|
||||
# I'd recommend setting weights between 1-10. Weights in the hundreds or thousands
|
||||
# are ridiculous and unnecessarily expensive. You can get random queue ordering
|
||||
# by explicitly setting all weights to 1.
|
||||
def self.queues=(val)
|
||||
self[:queues] = Array(val).each_with_object([]) do |qstr, memo|
|
||||
name, weight = qstr.split(",")
|
||||
self[:strict] = false if weight.to_i > 0
|
||||
[weight.to_i, 1].max.times do
|
||||
memo << name
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
### Private APIs
|
||||
def self.default_error_handler(ex, ctx)
|
||||
logger.warn(dump_json(ctx)) unless ctx.empty?
|
||||
logger.warn("#{ex.class.name}: #{ex.message}")
|
||||
logger.warn(ex.backtrace.join("\n")) unless ex.backtrace.nil?
|
||||
end
|
||||
|
||||
@config = DEFAULTS.dup
|
||||
def self.options
|
||||
@options ||= DEFAULTS.dup
|
||||
logger.warn "`config.options[:key] = value` is deprecated, use `config[:key] = value`: #{caller(1..2)}"
|
||||
@config
|
||||
end
|
||||
|
||||
def self.options=(opts)
|
||||
@options = opts
|
||||
logger.warn "config.options = hash` is deprecated, use `config.merge!(hash)`: #{caller(1..2)}"
|
||||
@config = opts
|
||||
end
|
||||
|
||||
def self.[](key)
|
||||
@config[key]
|
||||
end
|
||||
|
||||
def self.[]=(key, val)
|
||||
@config[key] = val
|
||||
end
|
||||
|
||||
def self.merge!(hash)
|
||||
@config.merge!(hash)
|
||||
end
|
||||
|
||||
def self.fetch(...)
|
||||
@config.fetch(...)
|
||||
end
|
||||
|
||||
def self.handle_exception(ex, ctx = {})
|
||||
self[:error_handlers].each do |handler|
|
||||
handler.call(ex, ctx)
|
||||
rescue => ex
|
||||
logger.error "!!! ERROR HANDLER THREW AN ERROR !!!"
|
||||
logger.error ex
|
||||
logger.error ex.backtrace.join("\n") unless ex.backtrace.nil?
|
||||
end
|
||||
end
|
||||
###
|
||||
|
||||
##
|
||||
# Configuration for Sidekiq server, use like:
|
||||
#
|
||||
# Sidekiq.configure_server do |config|
|
||||
# config.redis = { :size => 25, :url => 'redis://myhost:8877/0' }
|
||||
# config.server_middleware do |chain|
|
||||
# chain.add MyServerHook
|
||||
# end
|
||||
|
@ -76,7 +137,7 @@ module Sidekiq
|
|||
# Configuration for Sidekiq client, use like:
|
||||
#
|
||||
# Sidekiq.configure_client do |config|
|
||||
# config.redis = { :size => 1, :url => 'redis://myhost:8877/0' }
|
||||
# config.redis = { size: 1, url: 'redis://myhost:8877/0' }
|
||||
# end
|
||||
def self.configure_client
|
||||
yield self unless server?
|
||||
|
@ -131,7 +192,7 @@ module Sidekiq
|
|||
end
|
||||
|
||||
def self.client_middleware
|
||||
@client_chain ||= Middleware::Chain.new
|
||||
@client_chain ||= Middleware::Chain.new(self)
|
||||
yield @client_chain if block_given?
|
||||
@client_chain
|
||||
end
|
||||
|
@ -143,7 +204,7 @@ module Sidekiq
|
|||
end
|
||||
|
||||
def self.default_server_middleware
|
||||
Middleware::Chain.new
|
||||
Middleware::Chain.new(self)
|
||||
end
|
||||
|
||||
def self.default_worker_options=(hash) # deprecated
|
||||
|
@ -172,7 +233,7 @@ module Sidekiq
|
|||
# end
|
||||
# end
|
||||
def self.death_handlers
|
||||
options[:death_handlers]
|
||||
self[:death_handlers]
|
||||
end
|
||||
|
||||
def self.load_json(string)
|
||||
|
@ -225,7 +286,7 @@ module Sidekiq
|
|||
#
|
||||
# See sidekiq/scheduled.rb for an in-depth explanation of this value
|
||||
def self.average_scheduled_poll_interval=(interval)
|
||||
options[:average_scheduled_poll_interval] = interval
|
||||
self[:average_scheduled_poll_interval] = interval
|
||||
end
|
||||
|
||||
# Register a proc to handle any error which occurs within the Sidekiq process.
|
||||
|
@ -236,7 +297,7 @@ module Sidekiq
|
|||
#
|
||||
# The default error handler logs errors to Sidekiq.logger.
|
||||
def self.error_handlers
|
||||
options[:error_handlers]
|
||||
self[:error_handlers]
|
||||
end
|
||||
|
||||
# Register a block to run at a point in the Sidekiq lifecycle.
|
||||
|
@ -249,12 +310,12 @@ module Sidekiq
|
|||
# end
|
||||
def self.on(event, &block)
|
||||
raise ArgumentError, "Symbols only please: #{event}" unless event.is_a?(Symbol)
|
||||
raise ArgumentError, "Invalid event name: #{event}" unless options[:lifecycle_events].key?(event)
|
||||
options[:lifecycle_events][event] << block
|
||||
raise ArgumentError, "Invalid event name: #{event}" unless self[:lifecycle_events].key?(event)
|
||||
self[:lifecycle_events][event] << block
|
||||
end
|
||||
|
||||
def self.strict_args!(mode = :raise)
|
||||
options[:on_complex_arguments] = mode
|
||||
self[:on_complex_arguments] = mode
|
||||
end
|
||||
|
||||
# We are shutting down Sidekiq but what about threads that
|
||||
|
|
Binary file not shown.
|
@ -217,24 +217,30 @@ module Sidekiq
|
|||
include Enumerable
|
||||
|
||||
##
|
||||
# Return all known queues within Redis.
|
||||
# Fetch all known queues within Redis.
|
||||
#
|
||||
# @return [Array<Sidekiq::Queue>]
|
||||
def self.all
|
||||
Sidekiq.redis { |c| c.sscan_each("queues").to_a }.sort.map { |q| Sidekiq::Queue.new(q) }
|
||||
end
|
||||
|
||||
attr_reader :name
|
||||
|
||||
# @param name [String] the name of the queue
|
||||
def initialize(name = "default")
|
||||
@name = name.to_s
|
||||
@rname = "queue:#{name}"
|
||||
end
|
||||
|
||||
# The current size of the queue within Redis.
|
||||
# This value is real-time and can change between calls.
|
||||
#
|
||||
# @return [Integer] the size
|
||||
def size
|
||||
Sidekiq.redis { |con| con.llen(@rname) }
|
||||
end
|
||||
|
||||
# Sidekiq Pro overrides this
|
||||
# @return [Boolean] if the queue is currently paused
|
||||
def paused?
|
||||
false
|
||||
end
|
||||
|
@ -243,7 +249,7 @@ module Sidekiq
|
|||
# Calculates this queue's latency, the difference in seconds since the oldest
|
||||
# job in the queue was enqueued.
|
||||
#
|
||||
# @return Float
|
||||
# @return [Float] in seconds
|
||||
def latency
|
||||
entry = Sidekiq.redis { |conn|
|
||||
conn.lrange(@rname, -1, -1)
|
||||
|
@ -279,12 +285,17 @@ module Sidekiq
|
|||
##
|
||||
# Find the job with the given JID within this queue.
|
||||
#
|
||||
# This is a slow, inefficient operation. Do not use under
|
||||
# This is a *slow, inefficient* operation. Do not use under
|
||||
# normal conditions.
|
||||
#
|
||||
# @param jid [String] the job_id to look for
|
||||
# @return [Sidekiq::JobRecord]
|
||||
# @return [nil] if not found
|
||||
def find_job(jid)
|
||||
detect { |j| j.jid == jid }
|
||||
end
|
||||
|
||||
# delete all jobs within this queue
|
||||
def clear
|
||||
Sidekiq.redis do |conn|
|
||||
conn.multi do |transaction|
|
||||
|
@ -294,6 +305,10 @@ module Sidekiq
|
|||
end
|
||||
end
|
||||
alias_method :💣, :clear
|
||||
|
||||
def as_json(options = nil) # :nodoc:
|
||||
{name: name} # 5336
|
||||
end
|
||||
end
|
||||
|
||||
##
|
||||
|
@ -306,15 +321,16 @@ module Sidekiq
|
|||
class JobRecord
|
||||
attr_reader :item
|
||||
attr_reader :value
|
||||
attr_reader :queue
|
||||
|
||||
def initialize(item, queue_name = nil)
|
||||
def initialize(item, queue_name = nil) # :nodoc:
|
||||
@args = nil
|
||||
@value = item
|
||||
@item = item.is_a?(Hash) ? item : parse(item)
|
||||
@queue = queue_name || @item["queue"]
|
||||
end
|
||||
|
||||
def parse(item)
|
||||
def parse(item) # :nodoc:
|
||||
Sidekiq.load_json(item)
|
||||
rescue JSON::ParserError
|
||||
# If the job payload in Redis is invalid JSON, we'll load
|
||||
|
@ -398,15 +414,12 @@ module Sidekiq
|
|||
end
|
||||
end
|
||||
|
||||
attr_reader :queue
|
||||
|
||||
def latency
|
||||
now = Time.now.to_f
|
||||
now - (@item["enqueued_at"] || @item["created_at"] || now)
|
||||
end
|
||||
|
||||
##
|
||||
# Remove this job from the queue.
|
||||
# Remove this job from the queue
|
||||
def delete
|
||||
count = Sidekiq.redis { |conn|
|
||||
conn.lrem("queue:#{@queue}", 1, @value)
|
||||
|
@ -414,6 +427,7 @@ module Sidekiq
|
|||
count != 0
|
||||
end
|
||||
|
||||
# Access arbitrary attributes within the job hash
|
||||
def [](name)
|
||||
# nil will happen if the JSON fails to parse.
|
||||
# We don't guarantee Sidekiq will work with bad job JSON but we should
|
||||
|
@ -430,11 +444,13 @@ module Sidekiq
|
|||
end
|
||||
end
|
||||
|
||||
# Represents a job within a Redis sorted set where the score
|
||||
# represents a timestamp for the job.
|
||||
class SortedEntry < JobRecord
|
||||
attr_reader :score
|
||||
attr_reader :parent
|
||||
|
||||
def initialize(parent, score, item)
|
||||
def initialize(parent, score, item) # :nodoc:
|
||||
super(item)
|
||||
@score = Float(score)
|
||||
@parent = parent
|
||||
|
@ -452,12 +468,17 @@ module Sidekiq
|
|||
end
|
||||
end
|
||||
|
||||
# Change the scheduled time for this job.
|
||||
#
|
||||
# @param [Time] the new timestamp when this job will be enqueued.
|
||||
def reschedule(at)
|
||||
Sidekiq.redis do |conn|
|
||||
conn.zincrby(@parent.name, at.to_f - @score, Sidekiq.dump_json(@item))
|
||||
end
|
||||
end
|
||||
|
||||
# Enqueue this job from the scheduled or dead set so it will
|
||||
# be executed at some point in the near future.
|
||||
def add_to_queue
|
||||
remove_job do |message|
|
||||
msg = Sidekiq.load_json(message)
|
||||
|
@ -465,6 +486,8 @@ module Sidekiq
|
|||
end
|
||||
end
|
||||
|
||||
# enqueue this job from the retry set so it will be executed
|
||||
# at some point in the near future.
|
||||
def retry
|
||||
remove_job do |message|
|
||||
msg = Sidekiq.load_json(message)
|
||||
|
@ -473,8 +496,7 @@ module Sidekiq
|
|||
end
|
||||
end
|
||||
|
||||
##
|
||||
# Place job in the dead set
|
||||
# Move this job from its current set into the Dead set.
|
||||
def kill
|
||||
remove_job do |message|
|
||||
DeadSet.new.kill(message)
|
||||
|
@ -553,6 +575,10 @@ module Sidekiq
|
|||
end
|
||||
end
|
||||
alias_method :💣, :clear
|
||||
|
||||
def as_json(options = nil) # :nodoc:
|
||||
{name: name} # 5336
|
||||
end
|
||||
end
|
||||
|
||||
class JobSet < SortedSet
|
||||
|
@ -716,11 +742,11 @@ module Sidekiq
|
|||
end
|
||||
|
||||
def self.max_jobs
|
||||
Sidekiq.options[:dead_max_jobs]
|
||||
Sidekiq[:dead_max_jobs]
|
||||
end
|
||||
|
||||
def self.timeout
|
||||
Sidekiq.options[:dead_timeout_in_seconds]
|
||||
Sidekiq[:dead_timeout_in_seconds]
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -9,18 +9,23 @@ require "erb"
|
|||
require "fileutils"
|
||||
|
||||
require "sidekiq"
|
||||
require "sidekiq/component"
|
||||
require "sidekiq/launcher"
|
||||
require "sidekiq/util"
|
||||
|
||||
module Sidekiq
|
||||
module Sidekiq # :nodoc:
|
||||
class CLI
|
||||
include Util
|
||||
include Sidekiq::Component
|
||||
include Singleton unless $TESTING
|
||||
|
||||
attr_accessor :launcher
|
||||
attr_accessor :environment
|
||||
attr_accessor :config
|
||||
|
||||
def parse(args = ARGV.dup)
|
||||
@config = Sidekiq
|
||||
@config[:error_handlers].clear
|
||||
@config[:error_handlers] << @config.method(:default_error_handler)
|
||||
|
||||
setup_options(args)
|
||||
initialize_logger
|
||||
validate!
|
||||
|
@ -36,7 +41,7 @@ module Sidekiq
|
|||
def run(boot_app: true)
|
||||
boot_application if boot_app
|
||||
|
||||
if environment == "development" && $stdout.tty? && Sidekiq.log_formatter.is_a?(Sidekiq::Logger::Formatters::Pretty)
|
||||
if environment == "development" && $stdout.tty? && @config.log_formatter.is_a?(Sidekiq::Logger::Formatters::Pretty)
|
||||
print_banner
|
||||
end
|
||||
logger.info "Booted Rails #{::Rails.version} application in #{environment} environment" if rails_app?
|
||||
|
@ -67,7 +72,7 @@ module Sidekiq
|
|||
|
||||
# touch the connection pool so it is created before we
|
||||
# fire startup and start multithreading.
|
||||
info = Sidekiq.redis_info
|
||||
info = @config.redis_info
|
||||
ver = Gem::Version.new(info["redis_version"])
|
||||
raise "You are connecting to Redis #{ver}, Sidekiq requires Redis 6.2.0 or greater" if ver < Gem::Version.new("6.2.0")
|
||||
|
||||
|
@ -85,22 +90,22 @@ module Sidekiq
|
|||
|
||||
# Since the user can pass us a connection pool explicitly in the initializer, we
|
||||
# need to verify the size is large enough or else Sidekiq's performance is dramatically slowed.
|
||||
cursize = Sidekiq.redis_pool.size
|
||||
needed = Sidekiq.options[:concurrency] + 2
|
||||
cursize = @config.redis_pool.size
|
||||
needed = @config[:concurrency] + 2
|
||||
raise "Sidekiq's pool of #{cursize} Redis connections is too small, please increase the size to at least #{needed}" if cursize < needed
|
||||
|
||||
# cache process identity
|
||||
Sidekiq.options[:identity] = identity
|
||||
@config[:identity] = identity
|
||||
|
||||
# Touch middleware so it isn't lazy loaded by multiple threads, #3043
|
||||
Sidekiq.server_middleware
|
||||
@config.server_middleware
|
||||
|
||||
# Before this point, the process is initializing with just the main thread.
|
||||
# Starting here the process will now have multiple threads running.
|
||||
fire_event(:startup, reverse: false, reraise: true)
|
||||
|
||||
logger.debug { "Client Middleware: #{Sidekiq.client_middleware.map(&:klass).join(", ")}" }
|
||||
logger.debug { "Server Middleware: #{Sidekiq.server_middleware.map(&:klass).join(", ")}" }
|
||||
logger.debug { "Client Middleware: #{@config.client_middleware.map(&:klass).join(", ")}" }
|
||||
logger.debug { "Server Middleware: #{@config.server_middleware.map(&:klass).join(", ")}" }
|
||||
|
||||
launch(self_read)
|
||||
end
|
||||
|
@ -110,7 +115,7 @@ module Sidekiq
|
|||
logger.info "Starting processing, hit Ctrl-C to stop"
|
||||
end
|
||||
|
||||
@launcher = Sidekiq::Launcher.new(options)
|
||||
@launcher = Sidekiq::Launcher.new(@config)
|
||||
|
||||
begin
|
||||
launcher.run
|
||||
|
@ -173,25 +178,25 @@ module Sidekiq
|
|||
# Heroku sends TERM and then waits 30 seconds for process to exit.
|
||||
"TERM" => ->(cli) { raise Interrupt },
|
||||
"TSTP" => ->(cli) {
|
||||
Sidekiq.logger.info "Received TSTP, no longer accepting new work"
|
||||
cli.logger.info "Received TSTP, no longer accepting new work"
|
||||
cli.launcher.quiet
|
||||
},
|
||||
"TTIN" => ->(cli) {
|
||||
Thread.list.each do |thread|
|
||||
Sidekiq.logger.warn "Thread TID-#{(thread.object_id ^ ::Process.pid).to_s(36)} #{thread.name}"
|
||||
cli.logger.warn "Thread TID-#{(thread.object_id ^ ::Process.pid).to_s(36)} #{thread.name}"
|
||||
if thread.backtrace
|
||||
Sidekiq.logger.warn thread.backtrace.join("\n")
|
||||
cli.logger.warn thread.backtrace.join("\n")
|
||||
else
|
||||
Sidekiq.logger.warn "<no backtrace available>"
|
||||
cli.logger.warn "<no backtrace available>"
|
||||
end
|
||||
end
|
||||
}
|
||||
}
|
||||
UNHANDLED_SIGNAL_HANDLER = ->(cli) { Sidekiq.logger.info "No signal handler registered, ignoring" }
|
||||
UNHANDLED_SIGNAL_HANDLER = ->(cli) { cli.logger.info "No signal handler registered, ignoring" }
|
||||
SIGNAL_HANDLERS.default = UNHANDLED_SIGNAL_HANDLER
|
||||
|
||||
def handle_signal(sig)
|
||||
Sidekiq.logger.debug "Got #{sig} signal"
|
||||
logger.debug "Got #{sig} signal"
|
||||
SIGNAL_HANDLERS[sig].call(self)
|
||||
end
|
||||
|
||||
|
@ -237,7 +242,7 @@ module Sidekiq
|
|||
config_dir = if File.directory?(opts[:require].to_s)
|
||||
File.join(opts[:require], "config")
|
||||
else
|
||||
File.join(options[:require], "config")
|
||||
File.join(@config[:require], "config")
|
||||
end
|
||||
|
||||
%w[sidekiq.yml sidekiq.yml.erb].each do |config_file|
|
||||
|
@ -254,26 +259,22 @@ module Sidekiq
|
|||
opts[:concurrency] = Integer(ENV["RAILS_MAX_THREADS"]) if opts[:concurrency].nil? && ENV["RAILS_MAX_THREADS"]
|
||||
|
||||
# merge with defaults
|
||||
options.merge!(opts)
|
||||
end
|
||||
|
||||
def options
|
||||
Sidekiq.options
|
||||
@config.merge!(opts)
|
||||
end
|
||||
|
||||
def boot_application
|
||||
ENV["RACK_ENV"] = ENV["RAILS_ENV"] = environment
|
||||
|
||||
if File.directory?(options[:require])
|
||||
if File.directory?(@config[:require])
|
||||
require "rails"
|
||||
if ::Rails::VERSION::MAJOR < 6
|
||||
warn "Sidekiq #{Sidekiq::VERSION} only supports Rails 6+"
|
||||
end
|
||||
require "sidekiq/rails"
|
||||
require File.expand_path("#{options[:require]}/config/environment.rb")
|
||||
options[:tag] ||= default_tag
|
||||
require File.expand_path("#{@config[:require]}/config/environment.rb")
|
||||
@config[:tag] ||= default_tag
|
||||
else
|
||||
require options[:require]
|
||||
require @config[:require]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -290,8 +291,8 @@ module Sidekiq
|
|||
end
|
||||
|
||||
def validate!
|
||||
if !File.exist?(options[:require]) ||
|
||||
(File.directory?(options[:require]) && !File.exist?("#{options[:require]}/config/application.rb"))
|
||||
if !File.exist?(@config[:require]) ||
|
||||
(File.directory?(@config[:require]) && !File.exist?("#{@config[:require]}/config/application.rb"))
|
||||
logger.info "=================================================================="
|
||||
logger.info " Please point Sidekiq to a Rails application or a Ruby file "
|
||||
logger.info " to load your job classes with -r [DIR|FILE]."
|
||||
|
@ -301,7 +302,7 @@ module Sidekiq
|
|||
end
|
||||
|
||||
[:concurrency, :timeout].each do |opt|
|
||||
raise ArgumentError, "#{opt}: #{options[opt]} is not a valid value" if options.key?(opt) && options[opt].to_i <= 0
|
||||
raise ArgumentError, "#{opt}: #{@config[opt]} is not a valid value" if @config[opt].to_i <= 0
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -375,7 +376,7 @@ module Sidekiq
|
|||
end
|
||||
|
||||
def initialize_logger
|
||||
Sidekiq.logger.level = ::Logger::DEBUG if options[:verbose]
|
||||
@config.logger.level = ::Logger::DEBUG if @config[:verbose]
|
||||
end
|
||||
|
||||
def parse_config(path)
|
||||
|
|
|
@ -0,0 +1,64 @@
|
|||
module Sidekiq
|
||||
##
|
||||
# Sidekiq::Component assumes a config instance is available at @config
|
||||
module Component # :nodoc:
|
||||
attr_reader :config
|
||||
|
||||
def watchdog(last_words)
|
||||
yield
|
||||
rescue Exception => ex
|
||||
handle_exception(ex, {context: last_words})
|
||||
raise ex
|
||||
end
|
||||
|
||||
def safe_thread(name, &block)
|
||||
Thread.new do
|
||||
Thread.current.name = name
|
||||
watchdog(name, &block)
|
||||
end
|
||||
end
|
||||
|
||||
def logger
|
||||
config.logger
|
||||
end
|
||||
|
||||
def redis(&block)
|
||||
config.redis(&block)
|
||||
end
|
||||
|
||||
def tid
|
||||
Thread.current["sidekiq_tid"] ||= (Thread.current.object_id ^ ::Process.pid).to_s(36)
|
||||
end
|
||||
|
||||
def hostname
|
||||
ENV["DYNO"] || Socket.gethostname
|
||||
end
|
||||
|
||||
def process_nonce
|
||||
@@process_nonce ||= SecureRandom.hex(6)
|
||||
end
|
||||
|
||||
def identity
|
||||
@@identity ||= "#{hostname}:#{::Process.pid}:#{process_nonce}"
|
||||
end
|
||||
|
||||
def handle_exception(ex, ctx = {})
|
||||
config.handle_exception(ex, ctx)
|
||||
end
|
||||
|
||||
def fire_event(event, options = {})
|
||||
reverse = options[:reverse]
|
||||
reraise = options[:reraise]
|
||||
|
||||
arr = config[:lifecycle_events][event]
|
||||
arr.reverse! if reverse
|
||||
arr.each do |block|
|
||||
block.call
|
||||
rescue => ex
|
||||
handle_exception(ex, {context: "Exception during Sidekiq lifecycle event.", event: event})
|
||||
raise ex if reraise
|
||||
end
|
||||
arr.clear # once we've fired an event, we never fire it again
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,27 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "sidekiq"
|
||||
|
||||
module Sidekiq
|
||||
module ExceptionHandler
|
||||
class Logger
|
||||
def call(ex, ctx)
|
||||
Sidekiq.logger.warn(Sidekiq.dump_json(ctx)) unless ctx.empty?
|
||||
Sidekiq.logger.warn("#{ex.class.name}: #{ex.message}")
|
||||
Sidekiq.logger.warn(ex.backtrace.join("\n")) unless ex.backtrace.nil?
|
||||
end
|
||||
|
||||
Sidekiq.error_handlers << Sidekiq::ExceptionHandler::Logger.new
|
||||
end
|
||||
|
||||
def handle_exception(ex, ctx = {})
|
||||
Sidekiq.error_handlers.each do |handler|
|
||||
handler.call(ex, ctx)
|
||||
rescue => ex
|
||||
Sidekiq.logger.error "!!! ERROR HANDLER THREW AN ERROR !!!"
|
||||
Sidekiq.logger.error ex
|
||||
Sidekiq.logger.error ex.backtrace.join("\n") unless ex.backtrace.nil?
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,14 +1,16 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "sidekiq"
|
||||
require "sidekiq/component"
|
||||
|
||||
module Sidekiq
|
||||
module Sidekiq # :nodoc:
|
||||
class BasicFetch
|
||||
include Sidekiq::Component
|
||||
# We want the fetch operation to timeout every few seconds so the thread
|
||||
# can check if the process is shutting down.
|
||||
TIMEOUT = 2
|
||||
|
||||
UnitOfWork = Struct.new(:queue, :job) {
|
||||
UnitOfWork = Struct.new(:queue, :job, :config) {
|
||||
def acknowledge
|
||||
# nothing to do
|
||||
end
|
||||
|
@ -18,17 +20,17 @@ module Sidekiq
|
|||
end
|
||||
|
||||
def requeue
|
||||
Sidekiq.redis do |conn|
|
||||
config.redis do |conn|
|
||||
conn.rpush(queue, job)
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
def initialize(options)
|
||||
raise ArgumentError, "missing queue list" unless options[:queues]
|
||||
@options = options
|
||||
@strictly_ordered_queues = !!@options[:strict]
|
||||
@queues = @options[:queues].map { |q| "queue:#{q}" }
|
||||
def initialize(config)
|
||||
raise ArgumentError, "missing queue list" unless config[:queues]
|
||||
@config = config
|
||||
@strictly_ordered_queues = !!@config[:strict]
|
||||
@queues = @config[:queues].map { |q| "queue:#{q}" }
|
||||
if @strictly_ordered_queues
|
||||
@queues.uniq!
|
||||
@queues << TIMEOUT
|
||||
|
@ -44,30 +46,30 @@ module Sidekiq
|
|||
return nil
|
||||
end
|
||||
|
||||
work = Sidekiq.redis { |conn| conn.brpop(*qs) }
|
||||
UnitOfWork.new(*work) if work
|
||||
queue, job = redis { |conn| conn.brpop(*qs) }
|
||||
UnitOfWork.new(queue, job, config) if queue
|
||||
end
|
||||
|
||||
def bulk_requeue(inprogress, options)
|
||||
return if inprogress.empty?
|
||||
|
||||
Sidekiq.logger.debug { "Re-queueing terminated jobs" }
|
||||
logger.debug { "Re-queueing terminated jobs" }
|
||||
jobs_to_requeue = {}
|
||||
inprogress.each do |unit_of_work|
|
||||
jobs_to_requeue[unit_of_work.queue] ||= []
|
||||
jobs_to_requeue[unit_of_work.queue] << unit_of_work.job
|
||||
end
|
||||
|
||||
Sidekiq.redis do |conn|
|
||||
redis do |conn|
|
||||
conn.pipelined do |pipeline|
|
||||
jobs_to_requeue.each do |queue, jobs|
|
||||
pipeline.rpush(queue, jobs)
|
||||
end
|
||||
end
|
||||
end
|
||||
Sidekiq.logger.info("Pushed #{inprogress.size} jobs back to Redis")
|
||||
logger.info("Pushed #{inprogress.size} jobs back to Redis")
|
||||
rescue => ex
|
||||
Sidekiq.logger.warn("Failed to requeue #{inprogress.size} jobs: #{ex.message}")
|
||||
logger.warn("Failed to requeue #{inprogress.size} jobs: #{ex.message}")
|
||||
end
|
||||
|
||||
# Creating the Redis#brpop command takes into account any
|
||||
|
|
|
@ -66,12 +66,13 @@ module Sidekiq
|
|||
|
||||
class Skip < Handled; end
|
||||
|
||||
include Sidekiq::Util
|
||||
include Sidekiq::Component
|
||||
|
||||
DEFAULT_MAX_RETRY_ATTEMPTS = 25
|
||||
|
||||
def initialize(options = {})
|
||||
@max_retries = Sidekiq.options.merge(options).fetch(:max_retries, DEFAULT_MAX_RETRY_ATTEMPTS)
|
||||
def initialize(options)
|
||||
@config = options
|
||||
@max_retries = @config[:max_retries] || DEFAULT_MAX_RETRY_ATTEMPTS
|
||||
end
|
||||
|
||||
# The global retry handler requires only the barest of data.
|
||||
|
|
|
@ -17,13 +17,13 @@ module Sidekiq
|
|||
|
||||
def verify_json(item)
|
||||
job_class = item["wrapped"] || item["class"]
|
||||
if Sidekiq.options[:on_complex_arguments] == :raise
|
||||
if Sidekiq[:on_complex_arguments] == :raise
|
||||
msg = <<~EOM
|
||||
Job arguments to #{job_class} must be native JSON types, see https://github.com/mperham/sidekiq/wiki/Best-Practices.
|
||||
To disable this error, add `Sidekiq.strict_args!(false)` to your initializer.
|
||||
EOM
|
||||
raise(ArgumentError, msg) unless json_safe?(item)
|
||||
elsif Sidekiq.options[:on_complex_arguments] == :warn
|
||||
elsif Sidekiq[:on_complex_arguments] == :warn
|
||||
Sidekiq.logger.warn <<~EOM unless json_safe?(item)
|
||||
Job arguments to #{job_class} do not serialize to JSON safely. This will raise an error in
|
||||
Sidekiq 7.0. See https://github.com/mperham/sidekiq/wiki/Best-Practices or raise an error today
|
||||
|
|
|
@ -3,11 +3,12 @@
|
|||
require "sidekiq/manager"
|
||||
require "sidekiq/fetch"
|
||||
require "sidekiq/scheduled"
|
||||
require "sidekiq/ring_buffer"
|
||||
|
||||
module Sidekiq
|
||||
# The Launcher starts the Manager and Poller threads and provides the process heartbeat.
|
||||
class Launcher
|
||||
include Util
|
||||
include Sidekiq::Component
|
||||
|
||||
STATS_TTL = 5 * 365 * 24 * 60 * 60 # 5 years
|
||||
|
||||
|
@ -22,11 +23,11 @@ module Sidekiq
|
|||
attr_accessor :manager, :poller, :fetcher
|
||||
|
||||
def initialize(options)
|
||||
@config = options
|
||||
options[:fetch] ||= BasicFetch.new(options)
|
||||
@manager = Sidekiq::Manager.new(options)
|
||||
@poller = Sidekiq::Scheduled::Poller.new
|
||||
@poller = Sidekiq::Scheduled::Poller.new(options)
|
||||
@done = false
|
||||
@options = options
|
||||
end
|
||||
|
||||
def run
|
||||
|
@ -45,7 +46,7 @@ module Sidekiq
|
|||
|
||||
# Shuts down this Sidekiq instance. Waits up to the deadline for all jobs to complete.
|
||||
def stop
|
||||
deadline = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) + @options[:timeout]
|
||||
deadline = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) + @config[:timeout]
|
||||
|
||||
@done = true
|
||||
@manager.quiet
|
||||
|
@ -55,8 +56,8 @@ module Sidekiq
|
|||
|
||||
# Requeue everything in case there was a thread which fetched a job while the process was stopped.
|
||||
# This call is a no-op in Sidekiq but necessary for Sidekiq Pro.
|
||||
strategy = @options[:fetch]
|
||||
strategy.bulk_requeue([], @options)
|
||||
strategy = @config[:fetch]
|
||||
strategy.bulk_requeue([], @config)
|
||||
|
||||
clear_heartbeat
|
||||
end
|
||||
|
@ -74,14 +75,14 @@ module Sidekiq
|
|||
heartbeat
|
||||
sleep BEAT_PAUSE
|
||||
end
|
||||
Sidekiq.logger.info("Heartbeat stopping...")
|
||||
logger.info("Heartbeat stopping...")
|
||||
end
|
||||
|
||||
def clear_heartbeat
|
||||
# Remove record from Redis since we are shutting down.
|
||||
# Note we don't stop the heartbeat thread; if the process
|
||||
# doesn't actually exit, it'll reappear in the Web UI.
|
||||
Sidekiq.redis do |conn|
|
||||
redis do |conn|
|
||||
conn.pipelined do |pipeline|
|
||||
pipeline.srem("processes", identity)
|
||||
pipeline.unlink("#{identity}:work")
|
||||
|
@ -134,7 +135,7 @@ module Sidekiq
|
|||
|
||||
nowdate = Time.now.utc.strftime("%Y-%m-%d")
|
||||
|
||||
Sidekiq.redis do |conn|
|
||||
redis do |conn|
|
||||
conn.multi do |transaction|
|
||||
transaction.incrby("stat:processed", procd)
|
||||
transaction.incrby("stat:processed:#{nowdate}", procd)
|
||||
|
@ -161,7 +162,7 @@ module Sidekiq
|
|||
fails = procd = 0
|
||||
kb = memory_usage(::Process.pid)
|
||||
|
||||
_, exists, _, _, msg = Sidekiq.redis { |conn|
|
||||
_, exists, _, _, msg = redis { |conn|
|
||||
conn.multi { |transaction|
|
||||
transaction.sadd("processes", key)
|
||||
transaction.exists?(key)
|
||||
|
@ -199,7 +200,7 @@ module Sidekiq
|
|||
|
||||
def check_rtt
|
||||
a = b = 0
|
||||
Sidekiq.redis do |x|
|
||||
redis do |x|
|
||||
a = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :microsecond)
|
||||
x.ping
|
||||
b = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :microsecond)
|
||||
|
@ -210,7 +211,7 @@ module Sidekiq
|
|||
# Workable is < 10,000µs
|
||||
# Log a warning if it's a disaster.
|
||||
if RTT_READINGS.all? { |x| x > RTT_WARNING_LEVEL }
|
||||
Sidekiq.logger.warn <<~EOM
|
||||
logger.warn <<~EOM
|
||||
Your Redis network connection is performing extremely poorly.
|
||||
Last RTT readings were #{RTT_READINGS.buffer.inspect}, ideally these should be < 1000.
|
||||
Ensure Redis is running in the same AZ or datacenter as Sidekiq.
|
||||
|
@ -247,10 +248,10 @@ module Sidekiq
|
|||
"hostname" => hostname,
|
||||
"started_at" => Time.now.to_f,
|
||||
"pid" => ::Process.pid,
|
||||
"tag" => @options[:tag] || "",
|
||||
"concurrency" => @options[:concurrency],
|
||||
"queues" => @options[:queues].uniq,
|
||||
"labels" => @options[:labels],
|
||||
"tag" => @config[:tag] || "",
|
||||
"concurrency" => @config[:concurrency],
|
||||
"queues" => @config[:queues].uniq,
|
||||
"labels" => @config[:labels],
|
||||
"identity" => identity
|
||||
}
|
||||
end
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "sidekiq/util"
|
||||
require "sidekiq/processor"
|
||||
require "sidekiq/fetch"
|
||||
require "set"
|
||||
|
@ -21,29 +20,26 @@ module Sidekiq
|
|||
# the shutdown process. The other tasks are performed by other threads.
|
||||
#
|
||||
class Manager
|
||||
include Util
|
||||
include Sidekiq::Component
|
||||
|
||||
attr_reader :workers
|
||||
attr_reader :options
|
||||
|
||||
def initialize(options = {})
|
||||
@config = options
|
||||
logger.debug { options.inspect }
|
||||
@options = options
|
||||
@count = options[:concurrency] || 10
|
||||
raise ArgumentError, "Concurrency of #{@count} is not supported" if @count < 1
|
||||
|
||||
@done = false
|
||||
@workers = Set.new
|
||||
@count.times do
|
||||
@workers << Processor.new(self, options)
|
||||
@workers << Processor.new(@config, &method(:processor_result))
|
||||
end
|
||||
@plock = Mutex.new
|
||||
end
|
||||
|
||||
def start
|
||||
@workers.each do |x|
|
||||
x.start
|
||||
end
|
||||
@workers.each(&:start)
|
||||
end
|
||||
|
||||
def quiet
|
||||
|
@ -51,7 +47,7 @@ module Sidekiq
|
|||
@done = true
|
||||
|
||||
logger.info { "Terminating quiet threads" }
|
||||
@workers.each { |x| x.terminate }
|
||||
@workers.each(&:terminate)
|
||||
fire_event(:quiet, reverse: true)
|
||||
end
|
||||
|
||||
|
@ -72,17 +68,11 @@ module Sidekiq
|
|||
hard_shutdown
|
||||
end
|
||||
|
||||
def processor_stopped(processor)
|
||||
@plock.synchronize do
|
||||
@workers.delete(processor)
|
||||
end
|
||||
end
|
||||
|
||||
def processor_died(processor, reason)
|
||||
def processor_result(processor, reason = nil)
|
||||
@plock.synchronize do
|
||||
@workers.delete(processor)
|
||||
unless @done
|
||||
p = Processor.new(self, options)
|
||||
p = Processor.new(@config, &method(:processor_result))
|
||||
@workers << p
|
||||
p.start
|
||||
end
|
||||
|
@ -115,8 +105,8 @@ module Sidekiq
|
|||
# contract says that jobs are run AT LEAST once. Process termination
|
||||
# is delayed until we're certain the jobs are back in Redis because
|
||||
# it is worse to lose a job than to run it twice.
|
||||
strategy = @options[:fetch]
|
||||
strategy.bulk_requeue(jobs, @options)
|
||||
strategy = @config[:fetch]
|
||||
strategy.bulk_requeue(jobs, @config)
|
||||
end
|
||||
|
||||
cleanup.each do |processor|
|
||||
|
@ -129,5 +119,18 @@ module Sidekiq
|
|||
deadline = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) + 3
|
||||
wait_for(deadline) { @workers.empty? }
|
||||
end
|
||||
|
||||
# hack for quicker development / testing environment #2774
|
||||
PAUSE_TIME = $stdout.tty? ? 0.1 : 0.5
|
||||
|
||||
# Wait for the orblock to be true or the deadline passed.
|
||||
def wait_for(deadline, &condblock)
|
||||
remaining = deadline - ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
||||
while remaining > PAUSE_TIME
|
||||
return if condblock.call
|
||||
sleep PAUSE_TIME
|
||||
remaining = deadline - ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "sidekiq/middleware/modules"
|
||||
|
||||
module Sidekiq
|
||||
# Middleware is code configured to run before/after
|
||||
# a message is processed. It is patterned after Rack
|
||||
|
@ -44,10 +46,12 @@ module Sidekiq
|
|||
# This is an example of a minimal server middleware:
|
||||
#
|
||||
# class MyServerHook
|
||||
# include Sidekiq::ServerMiddleware
|
||||
# def call(job_instance, msg, queue)
|
||||
# puts "Before job"
|
||||
# logger.info "Before job"
|
||||
# redis {|conn| conn.get("foo") } # do something in Redis
|
||||
# yield
|
||||
# puts "After job"
|
||||
# logger.info "After job"
|
||||
# end
|
||||
# end
|
||||
#
|
||||
|
@ -56,10 +60,11 @@ module Sidekiq
|
|||
# to Redis:
|
||||
#
|
||||
# class MyClientHook
|
||||
# include Sidekiq::ClientMiddleware
|
||||
# def call(job_class, msg, queue, redis_pool)
|
||||
# puts "Before push"
|
||||
# logger.info "Before push"
|
||||
# result = yield
|
||||
# puts "After push"
|
||||
# logger.info "After push"
|
||||
# result
|
||||
# end
|
||||
# end
|
||||
|
@ -76,7 +81,8 @@ module Sidekiq
|
|||
entries.each(&block)
|
||||
end
|
||||
|
||||
def initialize
|
||||
def initialize(config = nil)
|
||||
@config = config
|
||||
@entries = nil
|
||||
yield self if block_given?
|
||||
end
|
||||
|
@ -91,24 +97,24 @@ module Sidekiq
|
|||
|
||||
def add(klass, *args)
|
||||
remove(klass)
|
||||
entries << Entry.new(klass, *args)
|
||||
entries << Entry.new(@config, klass, *args)
|
||||
end
|
||||
|
||||
def prepend(klass, *args)
|
||||
remove(klass)
|
||||
entries.insert(0, Entry.new(klass, *args))
|
||||
entries.insert(0, Entry.new(@config, klass, *args))
|
||||
end
|
||||
|
||||
def insert_before(oldklass, newklass, *args)
|
||||
i = entries.index { |entry| entry.klass == newklass }
|
||||
new_entry = i.nil? ? Entry.new(newklass, *args) : entries.delete_at(i)
|
||||
new_entry = i.nil? ? Entry.new(@config, newklass, *args) : entries.delete_at(i)
|
||||
i = entries.index { |entry| entry.klass == oldklass } || 0
|
||||
entries.insert(i, new_entry)
|
||||
end
|
||||
|
||||
def insert_after(oldklass, newklass, *args)
|
||||
i = entries.index { |entry| entry.klass == newklass }
|
||||
new_entry = i.nil? ? Entry.new(newklass, *args) : entries.delete_at(i)
|
||||
new_entry = i.nil? ? Entry.new(@config, newklass, *args) : entries.delete_at(i)
|
||||
i = entries.index { |entry| entry.klass == oldklass } || entries.count - 1
|
||||
entries.insert(i + 1, new_entry)
|
||||
end
|
||||
|
@ -149,13 +155,16 @@ module Sidekiq
|
|||
class Entry
|
||||
attr_reader :klass
|
||||
|
||||
def initialize(klass, *args)
|
||||
def initialize(config, klass, *args)
|
||||
@config = config
|
||||
@klass = klass
|
||||
@args = args
|
||||
end
|
||||
|
||||
def make_new
|
||||
@klass.new(*@args)
|
||||
x = @klass.new(*@args)
|
||||
x.config = @config if @config && x.respond_to?(:config=)
|
||||
x
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -15,6 +15,8 @@ module Sidekiq
|
|||
#
|
||||
module CurrentAttributes
|
||||
class Save
|
||||
include Sidekiq::ClientMiddleware
|
||||
|
||||
def initialize(cattr)
|
||||
@klass = cattr
|
||||
end
|
||||
|
@ -31,6 +33,8 @@ module Sidekiq
|
|||
end
|
||||
|
||||
class Load
|
||||
include Sidekiq::ServerMiddleware
|
||||
|
||||
def initialize(cattr)
|
||||
@klass = cattr
|
||||
end
|
||||
|
|
|
@ -10,6 +10,7 @@ module Sidekiq::Middleware::I18n
|
|||
# Get the current locale and store it in the message
|
||||
# to be sent to Sidekiq.
|
||||
class Client
|
||||
include Sidekiq::ClientMiddleware
|
||||
def call(_jobclass, job, _queue, _redis)
|
||||
job["locale"] ||= I18n.locale
|
||||
yield
|
||||
|
@ -18,6 +19,7 @@ module Sidekiq::Middleware::I18n
|
|||
|
||||
# Pull the msg locale out and set the current thread to use it.
|
||||
class Server
|
||||
include Sidekiq::ServerMiddleware
|
||||
def call(_jobclass, job, _queue, &block)
|
||||
I18n.with_locale(job.fetch("locale", I18n.default_locale), &block)
|
||||
end
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
module Sidekiq
|
||||
module ServerMiddleware
|
||||
attr_accessor :config
|
||||
def redis_pool
|
||||
config.redis_pool
|
||||
end
|
||||
|
||||
def logger
|
||||
config.logger
|
||||
end
|
||||
|
||||
def redis(&block)
|
||||
config.redis(&block)
|
||||
end
|
||||
end
|
||||
|
||||
# no difference for now
|
||||
ClientMiddleware = ServerMiddleware
|
||||
end
|
|
@ -1,6 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "sidekiq/util"
|
||||
require "sidekiq/fetch"
|
||||
require "sidekiq/job_logger"
|
||||
require "sidekiq/job_retry"
|
||||
|
@ -15,29 +14,30 @@ module Sidekiq
|
|||
# b. run the middleware chain
|
||||
# c. call #perform
|
||||
#
|
||||
# A Processor can exit due to shutdown (processor_stopped)
|
||||
# or due to an error during job execution (processor_died)
|
||||
# A Processor can exit due to shutdown or due to
|
||||
# an error during job execution.
|
||||
#
|
||||
# If an error occurs in the job execution, the
|
||||
# Processor calls the Manager to create a new one
|
||||
# to replace itself and exits.
|
||||
#
|
||||
class Processor
|
||||
include Util
|
||||
include Sidekiq::Component
|
||||
|
||||
attr_reader :thread
|
||||
attr_reader :job
|
||||
|
||||
def initialize(mgr, options)
|
||||
@mgr = mgr
|
||||
def initialize(options, &block)
|
||||
@callback = block
|
||||
@down = false
|
||||
@done = false
|
||||
@job = nil
|
||||
@thread = nil
|
||||
@config = options
|
||||
@strategy = options[:fetch]
|
||||
@reloader = options[:reloader] || proc { |&block| block.call }
|
||||
@job_logger = (options[:job_logger] || Sidekiq::JobLogger).new
|
||||
@retrier = Sidekiq::JobRetry.new
|
||||
@retrier = Sidekiq::JobRetry.new(options)
|
||||
end
|
||||
|
||||
def terminate(wait = false)
|
||||
|
@ -66,14 +66,14 @@ module Sidekiq
|
|||
|
||||
def run
|
||||
process_one until @done
|
||||
@mgr.processor_stopped(self)
|
||||
@callback.call(self)
|
||||
rescue Sidekiq::Shutdown
|
||||
@mgr.processor_stopped(self)
|
||||
@callback.call(self)
|
||||
rescue Exception => ex
|
||||
@mgr.processor_died(self, ex)
|
||||
@callback.call(self, ex)
|
||||
end
|
||||
|
||||
def process_one
|
||||
def process_one(&block)
|
||||
@job = fetch
|
||||
process(@job) if @job
|
||||
@job = nil
|
||||
|
@ -160,7 +160,7 @@ module Sidekiq
|
|||
ack = false
|
||||
begin
|
||||
dispatch(job_hash, queue, jobstr) do |inst|
|
||||
Sidekiq.server_middleware.invoke(inst, job_hash, queue) do
|
||||
@config.server_middleware.invoke(inst, job_hash, queue) do
|
||||
execute_job(inst, job_hash["args"])
|
||||
end
|
||||
end
|
||||
|
|
|
@ -38,12 +38,12 @@ module Sidekiq
|
|||
end
|
||||
|
||||
initializer "sidekiq.rails_logger" do
|
||||
Sidekiq.configure_server do |_|
|
||||
Sidekiq.configure_server do |config|
|
||||
# This is the integration code necessary so that if a job uses `Rails.logger.info "Hello"`,
|
||||
# it will appear in the Sidekiq console with all of the job context. See #5021 and
|
||||
# https://github.com/rails/rails/blob/b5f2b550f69a99336482739000c58e4e04e033aa/railties/lib/rails/commands/server/server_command.rb#L82-L84
|
||||
unless ::Rails.logger == ::Sidekiq.logger || ::ActiveSupport::Logger.logger_outputs_to?(::Rails.logger, $stdout)
|
||||
::Rails.logger.extend(::ActiveSupport::Logger.broadcast(::Sidekiq.logger))
|
||||
unless ::Rails.logger == config.logger || ::ActiveSupport::Logger.logger_outputs_to?(::Rails.logger, $stdout)
|
||||
::Rails.logger.extend(::ActiveSupport::Logger.broadcast(config.logger))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -60,8 +60,8 @@ module Sidekiq
|
|||
#
|
||||
# None of this matters on the client-side, only within the Sidekiq process itself.
|
||||
config.after_initialize do
|
||||
Sidekiq.configure_server do |_|
|
||||
Sidekiq.options[:reloader] = Sidekiq::Rails::Reloader.new
|
||||
Sidekiq.configure_server do |config|
|
||||
config[:reloader] = Sidekiq::Rails::Reloader.new
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -32,14 +32,14 @@ module Sidekiq
|
|||
elsif Sidekiq.server?
|
||||
# Give ourselves plenty of connections. pool is lazy
|
||||
# so we won't create them until we need them.
|
||||
Sidekiq.options[:concurrency] + 5
|
||||
Sidekiq[:concurrency] + 5
|
||||
elsif ENV["RAILS_MAX_THREADS"]
|
||||
Integer(ENV["RAILS_MAX_THREADS"])
|
||||
else
|
||||
5
|
||||
end
|
||||
|
||||
verify_sizing(size, Sidekiq.options[:concurrency]) if Sidekiq.server?
|
||||
verify_sizing(size, Sidekiq[:concurrency]) if Sidekiq.server?
|
||||
|
||||
pool_timeout = symbolized_options[:pool_timeout] || 1
|
||||
log_info(symbolized_options)
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
require "forwardable"
|
||||
|
||||
module Sidekiq
|
||||
class RingBuffer
|
||||
include Enumerable
|
||||
extend Forwardable
|
||||
def_delegators :@buf, :[], :each, :size
|
||||
|
||||
def initialize(size, default = 0)
|
||||
@size = size
|
||||
@buf = Array.new(size, default)
|
||||
@index = 0
|
||||
end
|
||||
|
||||
def <<(element)
|
||||
@buf[@index % @size] = element
|
||||
@index += 1
|
||||
element
|
||||
end
|
||||
|
||||
def buffer
|
||||
@buf
|
||||
end
|
||||
|
||||
def reset(default = 0)
|
||||
@buf.fill(default)
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,8 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "sidekiq"
|
||||
require "sidekiq/util"
|
||||
require "sidekiq/api"
|
||||
require "sidekiq/component"
|
||||
|
||||
module Sidekiq
|
||||
module Scheduled
|
||||
|
@ -67,12 +67,13 @@ module Sidekiq
|
|||
# just pops the job back onto its original queue so the
|
||||
# workers can pick it up like any other job.
|
||||
class Poller
|
||||
include Util
|
||||
include Sidekiq::Component
|
||||
|
||||
INITIAL_WAIT = 10
|
||||
|
||||
def initialize
|
||||
@enq = (Sidekiq.options[:scheduled_enq] || Sidekiq::Scheduled::Enq).new
|
||||
def initialize(options)
|
||||
@config = options
|
||||
@enq = (options[:scheduled_enq] || Sidekiq::Scheduled::Enq).new
|
||||
@sleeper = ConnectionPool::TimedStack.new
|
||||
@done = false
|
||||
@thread = nil
|
||||
|
@ -100,7 +101,7 @@ module Sidekiq
|
|||
enqueue
|
||||
wait
|
||||
end
|
||||
Sidekiq.logger.info("Scheduler exiting...")
|
||||
logger.info("Scheduler exiting...")
|
||||
}
|
||||
end
|
||||
|
||||
|
@ -171,14 +172,14 @@ module Sidekiq
|
|||
#
|
||||
# We only do this if poll_interval_average is unset (the default).
|
||||
def poll_interval_average
|
||||
Sidekiq.options[:poll_interval_average] ||= scaled_poll_interval
|
||||
@config[:poll_interval_average] ||= scaled_poll_interval
|
||||
end
|
||||
|
||||
# Calculates an average poll interval based on the number of known Sidekiq processes.
|
||||
# This minimizes a single point of failure by dispersing check-ins but without taxing
|
||||
# Redis if you run many Sidekiq processes.
|
||||
def scaled_poll_interval
|
||||
process_count * Sidekiq.options[:average_scheduled_poll_interval]
|
||||
process_count * @config[:average_scheduled_poll_interval]
|
||||
end
|
||||
|
||||
def process_count
|
||||
|
@ -197,7 +198,7 @@ module Sidekiq
|
|||
# to give time for the heartbeat to register (if the poll interval is going to be calculated by the number
|
||||
# of workers), and 5 random seconds to ensure they don't all hit Redis at the same time.
|
||||
total = 0
|
||||
total += INITIAL_WAIT unless Sidekiq.options[:poll_interval_average]
|
||||
total += INITIAL_WAIT unless @config[:poll_interval_average]
|
||||
total += (5 * rand)
|
||||
|
||||
@sleeper.pop(total)
|
||||
|
|
|
@ -179,7 +179,7 @@ module Sidekiq
|
|||
end
|
||||
|
||||
def clear_for(queue, klass)
|
||||
jobs_by_queue[queue].clear
|
||||
jobs_by_queue[queue.to_s].clear
|
||||
jobs_by_class[klass].clear
|
||||
end
|
||||
|
||||
|
|
|
@ -1,108 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require "forwardable"
|
||||
require "socket"
|
||||
require "securerandom"
|
||||
require "sidekiq/exception_handler"
|
||||
|
||||
module Sidekiq
|
||||
##
|
||||
# This module is part of Sidekiq core and not intended for extensions.
|
||||
#
|
||||
|
||||
class RingBuffer
|
||||
include Enumerable
|
||||
extend Forwardable
|
||||
def_delegators :@buf, :[], :each, :size
|
||||
|
||||
def initialize(size, default = 0)
|
||||
@size = size
|
||||
@buf = Array.new(size, default)
|
||||
@index = 0
|
||||
end
|
||||
|
||||
def <<(element)
|
||||
@buf[@index % @size] = element
|
||||
@index += 1
|
||||
element
|
||||
end
|
||||
|
||||
def buffer
|
||||
@buf
|
||||
end
|
||||
|
||||
def reset(default = 0)
|
||||
@buf.fill(default)
|
||||
end
|
||||
end
|
||||
|
||||
module Util
|
||||
include ExceptionHandler
|
||||
|
||||
# hack for quicker development / testing environment #2774
|
||||
PAUSE_TIME = $stdout.tty? ? 0.1 : 0.5
|
||||
|
||||
# Wait for the orblock to be true or the deadline passed.
|
||||
def wait_for(deadline, &condblock)
|
||||
remaining = deadline - ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
||||
while remaining > PAUSE_TIME
|
||||
return if condblock.call
|
||||
sleep PAUSE_TIME
|
||||
remaining = deadline - ::Process.clock_gettime(::Process::CLOCK_MONOTONIC)
|
||||
end
|
||||
end
|
||||
|
||||
def watchdog(last_words)
|
||||
yield
|
||||
rescue Exception => ex
|
||||
handle_exception(ex, {context: last_words})
|
||||
raise ex
|
||||
end
|
||||
|
||||
def safe_thread(name, &block)
|
||||
Thread.new do
|
||||
Thread.current.name = name
|
||||
watchdog(name, &block)
|
||||
end
|
||||
end
|
||||
|
||||
def logger
|
||||
Sidekiq.logger
|
||||
end
|
||||
|
||||
def redis(&block)
|
||||
Sidekiq.redis(&block)
|
||||
end
|
||||
|
||||
def tid
|
||||
Thread.current["sidekiq_tid"] ||= (Thread.current.object_id ^ ::Process.pid).to_s(36)
|
||||
end
|
||||
|
||||
def hostname
|
||||
ENV["DYNO"] || Socket.gethostname
|
||||
end
|
||||
|
||||
def process_nonce
|
||||
@@process_nonce ||= SecureRandom.hex(6)
|
||||
end
|
||||
|
||||
def identity
|
||||
@@identity ||= "#{hostname}:#{::Process.pid}:#{process_nonce}"
|
||||
end
|
||||
|
||||
def fire_event(event, options = {})
|
||||
reverse = options[:reverse]
|
||||
reraise = options[:reraise]
|
||||
|
||||
arr = Sidekiq.options[:lifecycle_events][event]
|
||||
arr.reverse! if reverse
|
||||
arr.each do |block|
|
||||
block.call
|
||||
rescue => ex
|
||||
handle_exception(ex, {context: "Exception during Sidekiq lifecycle event.", event: event})
|
||||
raise ex if reraise
|
||||
end
|
||||
arr.clear
|
||||
end
|
||||
end
|
||||
end
|
|
@ -297,7 +297,7 @@ module Sidekiq
|
|||
end
|
||||
|
||||
def environment_title_prefix
|
||||
environment = Sidekiq.options[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
||||
environment = Sidekiq[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development"
|
||||
|
||||
"[#{environment.upcase}] " unless environment == "production"
|
||||
end
|
||||
|
|
|
@ -1,15 +1,15 @@
|
|||
source 'https://rubygems.org'
|
||||
source "https://rubygems.org"
|
||||
|
||||
gem 'sidekiq', :path => '..'
|
||||
gem 'rails', "~> 6.1"
|
||||
gem 'puma'
|
||||
gem "sidekiq", path: ".."
|
||||
gem "rails"
|
||||
gem "puma"
|
||||
|
||||
gem "redis-client"
|
||||
|
||||
# Ubuntu required packages to install rails
|
||||
# apt-get install build-essential patch ruby-dev zlib1g-dev liblzma-dev libsqlite3-dev
|
||||
platforms :ruby do
|
||||
gem 'sqlite3'
|
||||
gem "sqlite3"
|
||||
end
|
||||
|
||||
gem 'after_commit_everywhere'
|
||||
gem "after_commit_everywhere"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# Add your own tasks in files placed in lib/tasks ending in .rake,
|
||||
# for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
|
||||
|
||||
require_relative 'config/application'
|
||||
require_relative "config/application"
|
||||
|
||||
Rails.application.load_tasks
|
||||
|
|
|
@ -3,42 +3,42 @@ class WorkController < ApplicationController
|
|||
@count = rand(100)
|
||||
puts "Adding #{@count} jobs"
|
||||
@count.times do |x|
|
||||
HardWorker.perform_async('bubba', 0.01, x)
|
||||
HardWorker.perform_async("bubba", 0.01, x)
|
||||
end
|
||||
end
|
||||
|
||||
def email
|
||||
UserMailer.delay_for(30.seconds).greetings(Time.now)
|
||||
render :plain => 'enqueued'
|
||||
render plain: "enqueued"
|
||||
end
|
||||
|
||||
def bulk
|
||||
Sidekiq::Client.push_bulk('class' => HardWorker,
|
||||
'args' => [['bob', 1, 1], ['mike', 1, 2]])
|
||||
render :plain => 'enbulked'
|
||||
Sidekiq::Client.push_bulk("class" => HardWorker,
|
||||
"args" => [["bob", 1, 1], ["mike", 1, 2]])
|
||||
render plain: "enbulked"
|
||||
end
|
||||
|
||||
def long
|
||||
50.times do |x|
|
||||
HardWorker.perform_async('bob', 15, x)
|
||||
HardWorker.perform_async("bob", 15, x)
|
||||
end
|
||||
render :plain => 'enqueued'
|
||||
render plain: "enqueued"
|
||||
end
|
||||
|
||||
def crash
|
||||
HardWorker.perform_async('crash', 1, Time.now.to_f)
|
||||
render :plain => 'enqueued'
|
||||
HardWorker.perform_async("crash", 1, Time.now.to_f)
|
||||
render plain: "enqueued"
|
||||
end
|
||||
|
||||
def delayed_post
|
||||
p = Post.first
|
||||
unless p
|
||||
p = Post.create!(:title => "Title!", :body => 'Body!')
|
||||
p2 = Post.create!(:title => "Other!", :body => 'Second Body!')
|
||||
else
|
||||
if p
|
||||
p2 = Post.second
|
||||
else
|
||||
p = Post.create!(title: "Title!", body: "Body!")
|
||||
p2 = Post.create!(title: "Other!", body: "Second Body!")
|
||||
end
|
||||
p.delay.long_method(p2)
|
||||
render :plain => 'enqueued'
|
||||
render plain: "enqueued"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,6 +4,6 @@ class UserMailer < ActionMailer::Base
|
|||
def greetings(now)
|
||||
@now = now
|
||||
@hostname = `hostname`.strip
|
||||
mail(:to => 'mperham@gmail.com', :subject => 'Ahoy Matey!')
|
||||
mail(to: "mperham@gmail.com", subject: "Ahoy Matey!")
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
class Post < ActiveRecord::Base
|
||||
def long_method(other_post)
|
||||
puts "Running long method with #{self.id} and #{other_post.id}"
|
||||
puts "Running long method with #{id} and #{other_post.id}"
|
||||
end
|
||||
|
||||
def self.testing
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
class HardWorker
|
||||
include Sidekiq::Worker
|
||||
sidekiq_options :backtrace => 5
|
||||
sidekiq_options backtrace: 5
|
||||
|
||||
def perform(name, count, salt)
|
||||
raise name if name == 'crash'
|
||||
raise name if name == "crash"
|
||||
logger.info Time.now
|
||||
sleep count
|
||||
end
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#!/usr/bin/env ruby
|
||||
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
|
||||
load Gem.bin_path('bundler', 'bundle')
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
||||
load Gem.bin_path("bundler", "bundle")
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#!/usr/bin/env ruby
|
||||
begin
|
||||
load File.expand_path('../spring', __FILE__)
|
||||
load File.expand_path("../spring", __FILE__)
|
||||
rescue LoadError => e
|
||||
raise unless e.message.include?('spring')
|
||||
raise unless e.message.include?("spring")
|
||||
end
|
||||
APP_PATH = File.expand_path('../config/application', __dir__)
|
||||
require_relative '../config/boot'
|
||||
require 'rails/commands'
|
||||
APP_PATH = File.expand_path("../config/application", __dir__)
|
||||
require_relative "../config/boot"
|
||||
require "rails/commands"
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
#!/usr/bin/env ruby
|
||||
begin
|
||||
load File.expand_path('../spring', __FILE__)
|
||||
load File.expand_path("../spring", __FILE__)
|
||||
rescue LoadError => e
|
||||
raise unless e.message.include?('spring')
|
||||
raise unless e.message.include?("spring")
|
||||
end
|
||||
require_relative '../config/boot'
|
||||
require 'rake'
|
||||
require_relative "../config/boot"
|
||||
require "rake"
|
||||
Rake.application.run
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
#!/usr/bin/env ruby
|
||||
require 'fileutils'
|
||||
include FileUtils
|
||||
|
||||
# path to your application root.
|
||||
APP_ROOT = File.expand_path('..', __dir__)
|
||||
|
||||
def system!(*args)
|
||||
system(*args) || abort("\n== Command #{args} failed ==")
|
||||
end
|
||||
|
||||
chdir APP_ROOT do
|
||||
# This script is a starting point to setup your application.
|
||||
# Add necessary setup steps to this file.
|
||||
|
||||
puts '== Installing dependencies =='
|
||||
system! 'gem install bundler --conservative'
|
||||
system('bundle check') || system!('bundle install')
|
||||
|
||||
# Install JavaScript dependencies if using Yarn
|
||||
# system('bin/yarn')
|
||||
|
||||
# puts "\n== Copying sample files =="
|
||||
# unless File.exist?('config/database.yml')
|
||||
# cp 'config/database.yml.sample', 'config/database.yml'
|
||||
# end
|
||||
|
||||
puts "\n== Preparing database =="
|
||||
system! 'bin/rails db:setup'
|
||||
|
||||
puts "\n== Removing old logs and tempfiles =="
|
||||
system! 'bin/rails log:clear tmp:clear'
|
||||
|
||||
puts "\n== Restarting application server =="
|
||||
system! 'bin/rails restart'
|
||||
end
|
|
@ -1,5 +1,5 @@
|
|||
# This file is used by Rack-based servers to start the application.
|
||||
|
||||
require_relative 'config/environment'
|
||||
require_relative "config/environment"
|
||||
|
||||
run Rails.application
|
||||
|
|
|
@ -1,18 +1,16 @@
|
|||
require_relative 'boot'
|
||||
require_relative "boot"
|
||||
|
||||
require 'rails'
|
||||
%w(
|
||||
require "rails"
|
||||
%w[
|
||||
active_record/railtie
|
||||
action_controller/railtie
|
||||
action_view/railtie
|
||||
action_mailer/railtie
|
||||
active_job/railtie
|
||||
sprockets/railtie
|
||||
).each do |railtie|
|
||||
begin
|
||||
require railtie
|
||||
rescue LoadError
|
||||
end
|
||||
].each do |railtie|
|
||||
require railtie
|
||||
rescue LoadError
|
||||
end
|
||||
|
||||
# Require the gems listed in Gemfile, including any gems
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../Gemfile', __dir__)
|
||||
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
||||
|
||||
require 'bundler/setup' # Set up gems listed in the Gemfile.
|
||||
require "bundler/setup" # Set up gems listed in the Gemfile.
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
# Load the Rails application.
|
||||
require_relative 'application'
|
||||
require_relative "application"
|
||||
|
||||
# Initialize the Rails application.
|
||||
Rails.application.initialize!
|
||||
|
|
|
@ -14,12 +14,12 @@ Rails.application.configure do
|
|||
|
||||
# Enable/disable caching. By default caching is disabled.
|
||||
# Run rails dev:cache to toggle caching.
|
||||
if Rails.root.join('tmp', 'caching-dev.txt').exist?
|
||||
if Rails.root.join("tmp", "caching-dev.txt").exist?
|
||||
config.action_controller.perform_caching = true
|
||||
|
||||
config.cache_store = :memory_store
|
||||
config.public_file_server.headers = {
|
||||
'Cache-Control' => "public, max-age=#{2.days.to_i}"
|
||||
"Cache-Control" => "public, max-age=#{2.days.to_i}"
|
||||
}
|
||||
else
|
||||
config.action_controller.perform_caching = false
|
||||
|
@ -28,7 +28,7 @@ Rails.application.configure do
|
|||
end
|
||||
|
||||
# Store uploaded files on the local file system (see config/storage.yml for options)
|
||||
#config.active_storage.service = :local
|
||||
# config.active_storage.service = :local
|
||||
|
||||
# Don't care if the mailer can't send.
|
||||
config.action_mailer.raise_delivery_errors = false
|
||||
|
@ -57,5 +57,5 @@ Rails.application.configure do
|
|||
|
||||
# Use an evented file watcher to asynchronously detect changes in source code,
|
||||
# routes, locales, etc. This feature depends on the listen gem.
|
||||
#config.file_watcher = ActiveSupport::EventedFileUpdateChecker
|
||||
# config.file_watcher = ActiveSupport::EventedFileUpdateChecker
|
||||
end
|
||||
|
|
|
@ -11,7 +11,7 @@ Rails.application.configure do
|
|||
config.eager_load = true
|
||||
|
||||
# Full error reports are disabled and caching is turned on.
|
||||
config.consider_all_requests_local = false
|
||||
config.consider_all_requests_local = false
|
||||
config.action_controller.perform_caching = true
|
||||
|
||||
# Ensures that a master key has been made available in either ENV["RAILS_MASTER_KEY"]
|
||||
|
@ -20,7 +20,7 @@ Rails.application.configure do
|
|||
|
||||
# Disable serving static files from the `/public` folder by default since
|
||||
# Apache or NGINX already handles this.
|
||||
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
|
||||
config.public_file_server.enabled = ENV["RAILS_SERVE_STATIC_FILES"].present?
|
||||
|
||||
# Compress JavaScripts and CSS.
|
||||
config.assets.js_compressor = :uglifier
|
||||
|
@ -39,7 +39,7 @@ Rails.application.configure do
|
|||
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX
|
||||
|
||||
# Store uploaded files on the local file system (see config/storage.yml for options)
|
||||
#config.active_storage.service = :local
|
||||
# config.active_storage.service = :local
|
||||
|
||||
# Mount Action Cable outside main process or domain
|
||||
# config.action_cable.mount_path = nil
|
||||
|
@ -54,7 +54,7 @@ Rails.application.configure do
|
|||
config.log_level = :debug
|
||||
|
||||
# Prepend all log lines with the following tags.
|
||||
config.log_tags = [ :request_id ]
|
||||
config.log_tags = [:request_id]
|
||||
|
||||
# Use a different cache store in production.
|
||||
# config.cache_store = :mem_cache_store
|
||||
|
@ -84,9 +84,9 @@ Rails.application.configure do
|
|||
# config.logger = ActiveSupport::TaggedLogging.new(Syslog::Logger.new 'app-name')
|
||||
|
||||
if ENV["RAILS_LOG_TO_STDOUT"].present?
|
||||
logger = ActiveSupport::Logger.new(STDOUT)
|
||||
logger = ActiveSupport::Logger.new($stdout)
|
||||
logger.formatter = config.log_formatter
|
||||
config.logger = ActiveSupport::TaggedLogging.new(logger)
|
||||
config.logger = ActiveSupport::TaggedLogging.new(logger)
|
||||
end
|
||||
|
||||
# Do not dump schema after migrations.
|
||||
|
|
|
@ -15,11 +15,11 @@ Rails.application.configure do
|
|||
# Configure public file server for tests with Cache-Control for performance.
|
||||
config.public_file_server.enabled = true
|
||||
config.public_file_server.headers = {
|
||||
'Cache-Control' => "public, max-age=#{1.hour.to_i}"
|
||||
"Cache-Control" => "public, max-age=#{1.hour.to_i}"
|
||||
}
|
||||
|
||||
# Show full error reports and disable caching.
|
||||
config.consider_all_requests_local = true
|
||||
config.consider_all_requests_local = true
|
||||
config.action_controller.perform_caching = false
|
||||
|
||||
# Raise exceptions instead of rendering exception templates.
|
||||
|
@ -29,7 +29,7 @@ Rails.application.configure do
|
|||
config.action_controller.allow_forgery_protection = false
|
||||
|
||||
# Store uploaded files on the local file system in a temporary directory
|
||||
#config.active_storage.service = :test
|
||||
# config.active_storage.service = :test
|
||||
|
||||
config.action_mailer.perform_caching = false
|
||||
|
||||
|
|
|
@ -4,4 +4,4 @@
|
|||
# If you change this key, all old signed cookies will become invalid!
|
||||
# Make sure the secret is at least 30 characters and all random,
|
||||
# no regular words or you'll be exposed to dictionary attacks.
|
||||
Myapp::Application.config.secret_token = 'bdd335500c81ba1f279f9dd8198d1f334445d0193168ed73c1282502180dca27e3e102ec345e99b2acac6a63f7fe29da69c60cc9e76e8da34fb5d4989db24cd8'
|
||||
Myapp::Application.config.secret_token = "bdd335500c81ba1f279f9dd8198d1f334445d0193168ed73c1282502180dca27e3e102ec345e99b2acac6a63f7fe29da69c60cc9e76e8da34fb5d4989db24cd8"
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
# Be sure to restart your server when you modify this file.
|
||||
|
||||
Rails.application.config.session_store :cookie_store, key: '_myapp_session'
|
||||
Rails.application.config.session_store :cookie_store, key: "_myapp_session"
|
||||
|
|
|
@ -1,19 +1,19 @@
|
|||
Sidekiq.default_job_options = { queue: "something" }
|
||||
Sidekiq.default_job_options = {queue: "something"}
|
||||
Sidekiq.configure_client do |config|
|
||||
config.redis = { :size => 2 }
|
||||
config.redis = {size: 2}
|
||||
end
|
||||
Sidekiq.configure_server do |config|
|
||||
config.on(:startup) { }
|
||||
config.on(:quiet) { }
|
||||
config.on(:startup) {}
|
||||
config.on(:quiet) {}
|
||||
config.on(:shutdown) do
|
||||
#result = RubyProf.stop
|
||||
# result = RubyProf.stop
|
||||
|
||||
## Write the results to a file
|
||||
## Requires railsexpress patched MRI build
|
||||
# brew install qcachegrind
|
||||
#File.open("callgrind.profile", "w") do |f|
|
||||
#RubyProf::CallTreePrinter.new(result).print(f, :min_percent => 1)
|
||||
#end
|
||||
# File.open("callgrind.profile", "w") do |f|
|
||||
# RubyProf::CallTreePrinter.new(result).print(f, :min_percent => 1)
|
||||
# end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
# turns off browser asset caching so we can test CSS changes quickly
|
||||
ENV['SIDEKIQ_WEB_TESTING'] = '1'
|
||||
ENV["SIDEKIQ_WEB_TESTING"] = "1"
|
||||
|
||||
require 'sidekiq/web'
|
||||
Sidekiq::Web.app_url = '/'
|
||||
require "sidekiq/web"
|
||||
Sidekiq::Web.app_url = "/"
|
||||
|
||||
Rails.application.routes.draw do
|
||||
mount Sidekiq::Web => '/sidekiq'
|
||||
mount Sidekiq::Web => "/sidekiq"
|
||||
get "work" => "work#index"
|
||||
get "work/email" => "work#email"
|
||||
get "work/post" => "work#delayed_post"
|
||||
|
|
|
@ -11,12 +11,10 @@
|
|||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 2012_01_23_214055) do
|
||||
|
||||
create_table "posts", force: :cascade do |t|
|
||||
t.string "title"
|
||||
t.string "body"
|
||||
t.datetime "created_at", precision: 6, null: false
|
||||
t.datetime "updated_at", precision: 6, null: false
|
||||
end
|
||||
|
||||
end
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#!/usr/bin/env ruby
|
||||
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
|
||||
|
||||
APP_PATH = File.expand_path('../../config/application', __FILE__)
|
||||
require File.expand_path('../../config/boot', __FILE__)
|
||||
require 'rails/commands'
|
||||
APP_PATH = File.expand_path("../../config/application", __FILE__)
|
||||
require File.expand_path("../../config/boot", __FILE__)
|
||||
require "rails/commands"
|
||||
|
|
|
@ -1,14 +1,14 @@
|
|||
# Easiest way to run Sidekiq::Web.
|
||||
# Run with "bundle exec rackup simple.ru"
|
||||
|
||||
require 'sidekiq/web'
|
||||
require "sidekiq/web"
|
||||
|
||||
# A Web process always runs as client, no need to configure server
|
||||
Sidekiq.configure_client do |config|
|
||||
config.redis = { url: 'redis://localhost:6379/0', size: 1 }
|
||||
config.redis = {url: "redis://localhost:6379/0", size: 1}
|
||||
end
|
||||
|
||||
Sidekiq::Client.push('class' => "HardWorker", 'args' => [])
|
||||
Sidekiq::Client.push("class" => "HardWorker", "args" => [])
|
||||
|
||||
# In a multi-process deployment, all Web UI instances should share
|
||||
# this secret key so they can all decode the encrypted browser cookies
|
||||
|
|
|
@ -28,7 +28,7 @@ end
|
|||
|
||||
ENV["REDIS_URL"] ||= "redis://localhost/15"
|
||||
|
||||
Sidekiq.logger = ::Logger.new(STDOUT)
|
||||
Sidekiq.logger = ::Logger.new($stdout)
|
||||
Sidekiq.logger.level = Logger::ERROR
|
||||
|
||||
if ENV["SIDEKIQ_REDIS_CLIENT"]
|
||||
|
@ -48,3 +48,20 @@ def capture_logging(lvl = Logger::INFO)
|
|||
Sidekiq.logger = old
|
||||
end
|
||||
end
|
||||
|
||||
module Sidekiq
|
||||
def self.reset!
|
||||
@config = DEFAULTS.dup
|
||||
end
|
||||
end
|
||||
|
||||
Signal.trap("TTIN") do
|
||||
Thread.list.each do |thread|
|
||||
puts "Thread TID-#{(thread.object_id ^ ::Process.pid).to_s(36)} #{thread.name}"
|
||||
if thread.backtrace
|
||||
puts thread.backtrace.join("\n")
|
||||
else
|
||||
puts "<no backtrace available>"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,23 +6,29 @@ require "sidekiq/fetch"
|
|||
require "sidekiq/scheduled"
|
||||
require "sidekiq/processor"
|
||||
|
||||
describe "Actors" do
|
||||
class JoeWorker
|
||||
include Sidekiq::Worker
|
||||
def perform(slp)
|
||||
raise "boom" if slp == "boom"
|
||||
sleep(slp) if slp > 0
|
||||
$count += 1
|
||||
end
|
||||
class JoeWorker
|
||||
include Sidekiq::Job
|
||||
def perform(slp)
|
||||
raise "boom" if slp == "boom"
|
||||
sleep(slp) if slp > 0
|
||||
$count += 1
|
||||
end
|
||||
end
|
||||
|
||||
describe "Actors" do
|
||||
before do
|
||||
Sidekiq.reset!
|
||||
Sidekiq.redis { |c| c.flushdb }
|
||||
@config = Sidekiq
|
||||
@config[:queues] = %w[default]
|
||||
@config[:fetch] = Sidekiq::BasicFetch.new(@config)
|
||||
@config[:error_handlers] << Sidekiq.method(:default_error_handler)
|
||||
# @config.logger.level = Logger::DEBUG
|
||||
end
|
||||
|
||||
describe "scheduler" do
|
||||
it "can start and stop" do
|
||||
f = Sidekiq::Scheduled::Poller.new
|
||||
f = Sidekiq::Scheduled::Poller.new(@config)
|
||||
f.start
|
||||
f.terminate
|
||||
end
|
||||
|
@ -37,7 +43,7 @@ describe "Actors" do
|
|||
assert_equal 1, ss.size
|
||||
|
||||
sleep 0.015
|
||||
s = Sidekiq::Scheduled::Poller.new
|
||||
s = Sidekiq::Scheduled::Poller.new(@config)
|
||||
s.enqueue
|
||||
assert_equal 1, q.size
|
||||
assert_equal 0, ss.size
|
||||
|
@ -48,84 +54,82 @@ describe "Actors" do
|
|||
describe "processor" do
|
||||
before do
|
||||
$count = 0
|
||||
@mutex = ::Mutex.new
|
||||
@cond = ::ConditionVariable.new
|
||||
@latest_error = nil
|
||||
end
|
||||
|
||||
def result(pr, ex)
|
||||
@latest_error = ex
|
||||
@mutex.synchronize do
|
||||
@cond.signal
|
||||
end
|
||||
end
|
||||
|
||||
def await(timeout = 0.5)
|
||||
@mutex.synchronize do
|
||||
yield
|
||||
@cond.wait(@mutex, timeout)
|
||||
end
|
||||
end
|
||||
|
||||
it "can start and stop" do
|
||||
m = Mgr.new
|
||||
f = Sidekiq::Processor.new(m, m.options)
|
||||
f = Sidekiq::Processor.new(@config) { |p, ex| raise "should not raise!" }
|
||||
f.terminate
|
||||
end
|
||||
|
||||
class Mgr
|
||||
attr_reader :latest_error
|
||||
attr_reader :mutex
|
||||
attr_reader :cond
|
||||
def initialize
|
||||
@mutex = ::Mutex.new
|
||||
@cond = ::ConditionVariable.new
|
||||
end
|
||||
|
||||
def processor_died(inst, err)
|
||||
@latest_error = err
|
||||
@mutex.synchronize do
|
||||
@cond.signal
|
||||
end
|
||||
end
|
||||
|
||||
def processor_stopped(inst)
|
||||
@mutex.synchronize do
|
||||
@cond.signal
|
||||
end
|
||||
end
|
||||
|
||||
def options
|
||||
opts = {concurrency: 3, queues: ["default"]}
|
||||
opts[:fetch] = Sidekiq::BasicFetch.new(opts)
|
||||
opts
|
||||
end
|
||||
end
|
||||
|
||||
it "can process" do
|
||||
mgr = Mgr.new
|
||||
|
||||
p = Sidekiq::Processor.new(mgr, mgr.options)
|
||||
JoeWorker.perform_async(0)
|
||||
|
||||
a = $count
|
||||
p.process_one
|
||||
b = $count
|
||||
assert_equal a + 1, b
|
||||
end
|
||||
|
||||
it "deals with errors" do
|
||||
mgr = Mgr.new
|
||||
|
||||
p = Sidekiq::Processor.new(mgr, mgr.options)
|
||||
JoeWorker.perform_async("boom")
|
||||
q = Sidekiq::Queue.new
|
||||
assert_equal 0, q.size
|
||||
p = Sidekiq::Processor.new(@config) do |pr, ex|
|
||||
result(pr, ex)
|
||||
end
|
||||
JoeWorker.perform_async(0)
|
||||
assert_equal 1, q.size
|
||||
|
||||
a = $count
|
||||
mgr.mutex.synchronize do
|
||||
await do
|
||||
p.start
|
||||
end
|
||||
|
||||
p.kill(true)
|
||||
b = $count
|
||||
assert_nil @latest_error
|
||||
assert_equal a + 1, b
|
||||
assert_equal 0, q.size
|
||||
end
|
||||
|
||||
it "deals with errors" do
|
||||
q = Sidekiq::Queue.new
|
||||
assert_equal 0, q.size
|
||||
p = Sidekiq::Processor.new(@config) do |pr, ex|
|
||||
result(pr, ex)
|
||||
end
|
||||
jid = JoeWorker.perform_async("boom")
|
||||
assert jid, jid
|
||||
assert_equal 1, q.size
|
||||
|
||||
a = $count
|
||||
await do
|
||||
p.start
|
||||
mgr.cond.wait(mgr.mutex)
|
||||
end
|
||||
b = $count
|
||||
assert_equal a, b
|
||||
|
||||
sleep 0.001
|
||||
assert_equal false, p.thread.status
|
||||
p.terminate(true)
|
||||
refute_nil mgr.latest_error
|
||||
assert_equal RuntimeError, mgr.latest_error.class
|
||||
p.kill(true)
|
||||
assert @latest_error
|
||||
assert_equal "boom", @latest_error.message
|
||||
assert_equal RuntimeError, @latest_error.class
|
||||
end
|
||||
|
||||
it "gracefully kills" do
|
||||
mgr = Mgr.new
|
||||
|
||||
p = Sidekiq::Processor.new(mgr, mgr.options)
|
||||
JoeWorker.perform_async(1)
|
||||
q = Sidekiq::Queue.new
|
||||
assert_equal 0, q.size
|
||||
p = Sidekiq::Processor.new(@config) do |pr, ex|
|
||||
result(pr, ex)
|
||||
end
|
||||
jid = JoeWorker.perform_async(1)
|
||||
assert jid, jid
|
||||
assert_equal 1, q.size
|
||||
|
||||
a = $count
|
||||
|
@ -137,7 +141,7 @@ describe "Actors" do
|
|||
b = $count
|
||||
assert_equal a, b
|
||||
assert_equal false, p.thread.status
|
||||
refute mgr.latest_error, mgr.latest_error.to_s
|
||||
refute @latest_error, @latest_error.to_s
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
179
test/test_cli.rb
179
test/test_cli.rb
|
@ -6,17 +6,22 @@ require "sidekiq/cli"
|
|||
describe Sidekiq::CLI do
|
||||
describe "#parse" do
|
||||
before do
|
||||
Sidekiq.options = Sidekiq::DEFAULTS.dup
|
||||
Sidekiq.reset!
|
||||
@logger = Sidekiq.logger
|
||||
@logdev = StringIO.new
|
||||
Sidekiq.logger = Logger.new(@logdev)
|
||||
@config = Sidekiq
|
||||
end
|
||||
|
||||
attr_reader :config
|
||||
|
||||
after do
|
||||
Sidekiq.logger = @logger
|
||||
end
|
||||
|
||||
subject { Sidekiq::CLI.new }
|
||||
subject do
|
||||
Sidekiq::CLI.new.tap { |c| c.config = config }
|
||||
end
|
||||
|
||||
def logdev
|
||||
@logdev ||= StringIO.new
|
||||
|
@ -28,7 +33,7 @@ describe Sidekiq::CLI do
|
|||
it "accepts with -r" do
|
||||
subject.parse(%w[sidekiq -r ./test/fake_env.rb])
|
||||
|
||||
assert_equal "./test/fake_env.rb", Sidekiq.options[:require]
|
||||
assert_equal "./test/fake_env.rb", config[:require]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -36,7 +41,7 @@ describe Sidekiq::CLI do
|
|||
it "accepts with -c" do
|
||||
subject.parse(%w[sidekiq -c 60 -r ./test/fake_env.rb])
|
||||
|
||||
assert_equal 60, Sidekiq.options[:concurrency]
|
||||
assert_equal 60, config[:concurrency]
|
||||
end
|
||||
|
||||
describe "when concurrency is empty and RAILS_MAX_THREADS env var is set" do
|
||||
|
@ -51,13 +56,13 @@ describe Sidekiq::CLI do
|
|||
it "sets concurrency from RAILS_MAX_THREADS env var" do
|
||||
subject.parse(%w[sidekiq -r ./test/fake_env.rb])
|
||||
|
||||
assert_equal 9, Sidekiq.options[:concurrency]
|
||||
assert_equal 9, config[:concurrency]
|
||||
end
|
||||
|
||||
it "option overrides RAILS_MAX_THREADS env var" do
|
||||
subject.parse(%w[sidekiq -c 60 -r ./test/fake_env.rb])
|
||||
|
||||
assert_equal 60, Sidekiq.options[:concurrency]
|
||||
assert_equal 60, config[:concurrency]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -67,7 +72,7 @@ describe Sidekiq::CLI do
|
|||
it "discards the `strict` option specified via the config file" do
|
||||
subject.parse(%w[sidekiq -C ./test/config_with_internal_options.yml])
|
||||
|
||||
assert_equal true, !!Sidekiq.options[:strict]
|
||||
assert_equal true, !!config[:strict]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -76,20 +81,20 @@ describe Sidekiq::CLI do
|
|||
it "accepts with -q" do
|
||||
subject.parse(%w[sidekiq -q foo -r ./test/fake_env.rb])
|
||||
|
||||
assert_equal ["foo"], Sidekiq.options[:queues]
|
||||
assert_equal ["foo"], config[:queues]
|
||||
end
|
||||
|
||||
describe "when weights are not present" do
|
||||
it "accepts queues without weights" do
|
||||
subject.parse(%w[sidekiq -q foo -q bar -r ./test/fake_env.rb])
|
||||
|
||||
assert_equal ["foo", "bar"], Sidekiq.options[:queues]
|
||||
assert_equal ["foo", "bar"], config[:queues]
|
||||
end
|
||||
|
||||
it "sets strictly ordered queues" do
|
||||
subject.parse(%w[sidekiq -q foo -q bar -r ./test/fake_env.rb])
|
||||
|
||||
assert_equal true, !!Sidekiq.options[:strict]
|
||||
assert_equal true, !!config[:strict]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -97,26 +102,26 @@ describe Sidekiq::CLI do
|
|||
it "accepts queues with weights" do
|
||||
subject.parse(%w[sidekiq -q foo,3 -q bar -r ./test/fake_env.rb])
|
||||
|
||||
assert_equal ["foo", "foo", "foo", "bar"], Sidekiq.options[:queues]
|
||||
assert_equal ["foo", "foo", "foo", "bar"], config[:queues]
|
||||
end
|
||||
|
||||
it "does not set strictly ordered queues" do
|
||||
subject.parse(%w[sidekiq -q foo,3 -q bar -r ./test/fake_env.rb])
|
||||
|
||||
assert_equal false, !!Sidekiq.options[:strict]
|
||||
assert_equal false, !!config[:strict]
|
||||
end
|
||||
end
|
||||
|
||||
it "accepts queues with multi-word names" do
|
||||
subject.parse(%w[sidekiq -q queue_one -q queue-two -r ./test/fake_env.rb])
|
||||
|
||||
assert_equal ["queue_one", "queue-two"], Sidekiq.options[:queues]
|
||||
assert_equal ["queue_one", "queue-two"], config[:queues]
|
||||
end
|
||||
|
||||
it "accepts queues with dots in the name" do
|
||||
subject.parse(%w[sidekiq -q foo.bar -r ./test/fake_env.rb])
|
||||
|
||||
assert_equal ["foo.bar"], Sidekiq.options[:queues]
|
||||
assert_equal ["foo.bar"], config[:queues]
|
||||
end
|
||||
|
||||
describe "when duplicate queue names" do
|
||||
|
@ -131,7 +136,7 @@ describe Sidekiq::CLI do
|
|||
it "sets 'default' queue" do
|
||||
subject.parse(%w[sidekiq -r ./test/fake_env.rb])
|
||||
|
||||
assert_equal ["default"], Sidekiq.options[:queues]
|
||||
assert_equal ["default"], config[:queues]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -139,7 +144,7 @@ describe Sidekiq::CLI do
|
|||
it "sets 'default' queue" do
|
||||
subject.parse(%w[sidekiq -C ./test/config_empty.yml -r ./test/fake_env.rb])
|
||||
|
||||
assert_equal ["default"], Sidekiq.options[:queues]
|
||||
assert_equal ["default"], config[:queues]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -149,7 +154,7 @@ describe Sidekiq::CLI do
|
|||
it "accepts with -t" do
|
||||
subject.parse(%w[sidekiq -t 30 -r ./test/fake_env.rb])
|
||||
|
||||
assert_equal 30, Sidekiq.options[:timeout]
|
||||
assert_equal 30, config[:timeout]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -165,57 +170,57 @@ describe Sidekiq::CLI do
|
|||
it "accepts with -C" do
|
||||
subject.parse(%w[sidekiq -C ./test/config.yml])
|
||||
|
||||
assert_equal "./test/config.yml", Sidekiq.options[:config_file]
|
||||
refute Sidekiq.options[:verbose]
|
||||
assert_equal "./test/fake_env.rb", Sidekiq.options[:require]
|
||||
assert_nil Sidekiq.options[:environment]
|
||||
assert_equal 50, Sidekiq.options[:concurrency]
|
||||
assert_equal 2, Sidekiq.options[:queues].count { |q| q == "very_often" }
|
||||
assert_equal 1, Sidekiq.options[:queues].count { |q| q == "seldom" }
|
||||
assert_equal "./test/config.yml", config[:config_file]
|
||||
refute config[:verbose]
|
||||
assert_equal "./test/fake_env.rb", config[:require]
|
||||
assert_nil config[:environment]
|
||||
assert_equal 50, config[:concurrency]
|
||||
assert_equal 2, config[:queues].count { |q| q == "very_often" }
|
||||
assert_equal 1, config[:queues].count { |q| q == "seldom" }
|
||||
end
|
||||
|
||||
it "accepts stringy keys" do
|
||||
subject.parse(%w[sidekiq -C ./test/config_string.yml])
|
||||
|
||||
assert_equal "./test/config_string.yml", Sidekiq.options[:config_file]
|
||||
refute Sidekiq.options[:verbose]
|
||||
assert_equal "./test/fake_env.rb", Sidekiq.options[:require]
|
||||
assert_nil Sidekiq.options[:environment]
|
||||
assert_equal 50, Sidekiq.options[:concurrency]
|
||||
assert_equal 2, Sidekiq.options[:queues].count { |q| q == "very_often" }
|
||||
assert_equal 1, Sidekiq.options[:queues].count { |q| q == "seldom" }
|
||||
assert_equal "./test/config_string.yml", config[:config_file]
|
||||
refute config[:verbose]
|
||||
assert_equal "./test/fake_env.rb", config[:require]
|
||||
assert_nil config[:environment]
|
||||
assert_equal 50, config[:concurrency]
|
||||
assert_equal 2, config[:queues].count { |q| q == "very_often" }
|
||||
assert_equal 1, config[:queues].count { |q| q == "seldom" }
|
||||
end
|
||||
|
||||
it "accepts environment specific config" do
|
||||
subject.parse(%w[sidekiq -e staging -C ./test/config_environment.yml])
|
||||
|
||||
assert_equal "./test/config_environment.yml", Sidekiq.options[:config_file]
|
||||
refute Sidekiq.options[:verbose]
|
||||
assert_equal "./test/fake_env.rb", Sidekiq.options[:require]
|
||||
assert_equal "staging", Sidekiq.options[:environment]
|
||||
assert_equal 50, Sidekiq.options[:concurrency]
|
||||
assert_equal 2, Sidekiq.options[:queues].count { |q| q == "very_often" }
|
||||
assert_equal 1, Sidekiq.options[:queues].count { |q| q == "seldom" }
|
||||
assert_equal "./test/config_environment.yml", config[:config_file]
|
||||
refute config[:verbose]
|
||||
assert_equal "./test/fake_env.rb", config[:require]
|
||||
assert_equal "staging", config[:environment]
|
||||
assert_equal 50, config[:concurrency]
|
||||
assert_equal 2, config[:queues].count { |q| q == "very_often" }
|
||||
assert_equal 1, config[:queues].count { |q| q == "seldom" }
|
||||
end
|
||||
|
||||
it "accepts environment specific config with alias" do
|
||||
subject.parse(%w[sidekiq -e staging -C ./test/config_with_alias.yml])
|
||||
assert_equal "./test/config_with_alias.yml", Sidekiq.options[:config_file]
|
||||
refute Sidekiq.options[:verbose]
|
||||
assert_equal "./test/fake_env.rb", Sidekiq.options[:require]
|
||||
assert_equal "staging", Sidekiq.options[:environment]
|
||||
assert_equal 50, Sidekiq.options[:concurrency]
|
||||
assert_equal 2, Sidekiq.options[:queues].count { |q| q == "very_often" }
|
||||
assert_equal 1, Sidekiq.options[:queues].count { |q| q == "seldom" }
|
||||
assert_equal "./test/config_with_alias.yml", config[:config_file]
|
||||
refute config[:verbose]
|
||||
assert_equal "./test/fake_env.rb", config[:require]
|
||||
assert_equal "staging", config[:environment]
|
||||
assert_equal 50, config[:concurrency]
|
||||
assert_equal 2, config[:queues].count { |q| q == "very_often" }
|
||||
assert_equal 1, config[:queues].count { |q| q == "seldom" }
|
||||
|
||||
subject.parse(%w[sidekiq -e production -C ./test/config_with_alias.yml])
|
||||
assert_equal "./test/config_with_alias.yml", Sidekiq.options[:config_file]
|
||||
assert Sidekiq.options[:verbose]
|
||||
assert_equal "./test/fake_env.rb", Sidekiq.options[:require]
|
||||
assert_equal "production", Sidekiq.options[:environment]
|
||||
assert_equal 50, Sidekiq.options[:concurrency]
|
||||
assert_equal 2, Sidekiq.options[:queues].count { |q| q == "very_often" }
|
||||
assert_equal 1, Sidekiq.options[:queues].count { |q| q == "seldom" }
|
||||
assert_equal "./test/config_with_alias.yml", config[:config_file]
|
||||
assert config[:verbose]
|
||||
assert_equal "./test/fake_env.rb", config[:require]
|
||||
assert_equal "production", config[:environment]
|
||||
assert_equal 50, config[:concurrency]
|
||||
assert_equal 2, config[:queues].count { |q| q == "very_often" }
|
||||
assert_equal 1, config[:queues].count { |q| q == "seldom" }
|
||||
end
|
||||
|
||||
it "exposes ERB expected __FILE__ and __dir__" do
|
||||
|
@ -226,8 +231,8 @@ describe Sidekiq::CLI do
|
|||
|
||||
subject.parse(%W[sidekiq -C #{given_path}])
|
||||
|
||||
assert_equal(expected_file, Sidekiq.options.fetch(:__FILE__))
|
||||
assert_equal(expected_dir, Sidekiq.options.fetch(:__dir__))
|
||||
assert_equal(expected_file, config.fetch(:__FILE__))
|
||||
assert_equal(expected_dir, config.fetch(:__dir__))
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -236,30 +241,30 @@ describe Sidekiq::CLI do
|
|||
it "tries config/sidekiq.yml from required diretory" do
|
||||
subject.parse(%w[sidekiq -r ./test/dummy])
|
||||
|
||||
assert_equal "./test/dummy/config/sidekiq.yml", Sidekiq.options[:config_file]
|
||||
assert_equal 25, Sidekiq.options[:concurrency]
|
||||
assert_equal "./test/dummy/config/sidekiq.yml", config[:config_file]
|
||||
assert_equal 25, config[:concurrency]
|
||||
end
|
||||
end
|
||||
|
||||
describe "when required path is a file" do
|
||||
it "tries config/sidekiq.yml from current diretory" do
|
||||
Sidekiq.options[:require] = "./test/dummy" # stub current dir – ./
|
||||
config[:require] = "./test/dummy" # stub current dir – ./
|
||||
|
||||
subject.parse(%w[sidekiq -r ./test/fake_env.rb])
|
||||
|
||||
assert_equal "./test/dummy/config/sidekiq.yml", Sidekiq.options[:config_file]
|
||||
assert_equal 25, Sidekiq.options[:concurrency]
|
||||
assert_equal "./test/dummy/config/sidekiq.yml", config[:config_file]
|
||||
assert_equal 25, config[:concurrency]
|
||||
end
|
||||
end
|
||||
|
||||
describe "without any required path" do
|
||||
it "tries config/sidekiq.yml from current diretory" do
|
||||
Sidekiq.options[:require] = "./test/dummy" # stub current dir – ./
|
||||
config[:require] = "./test/dummy" # stub current dir – ./
|
||||
|
||||
subject.parse(%w[sidekiq])
|
||||
|
||||
assert_equal "./test/dummy/config/sidekiq.yml", Sidekiq.options[:config_file]
|
||||
assert_equal 25, Sidekiq.options[:concurrency]
|
||||
assert_equal "./test/dummy/config/sidekiq.yml", config[:config_file]
|
||||
assert_equal 25, config[:concurrency]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -272,13 +277,13 @@ describe Sidekiq::CLI do
|
|||
-q often,7
|
||||
-q seldom,3])
|
||||
|
||||
assert_equal "./test/config.yml", Sidekiq.options[:config_file]
|
||||
refute Sidekiq.options[:verbose]
|
||||
assert_equal "./test/fake_env.rb", Sidekiq.options[:require]
|
||||
assert_equal "snoop", Sidekiq.options[:environment]
|
||||
assert_equal 100, Sidekiq.options[:concurrency]
|
||||
assert_equal 7, Sidekiq.options[:queues].count { |q| q == "often" }
|
||||
assert_equal 3, Sidekiq.options[:queues].count { |q| q == "seldom" }
|
||||
assert_equal "./test/config.yml", config[:config_file]
|
||||
refute config[:verbose]
|
||||
assert_equal "./test/fake_env.rb", config[:require]
|
||||
assert_equal "snoop", config[:environment]
|
||||
assert_equal 100, config[:concurrency]
|
||||
assert_equal 7, config[:queues].count { |q| q == "often" }
|
||||
assert_equal 3, config[:queues].count { |q| q == "seldom" }
|
||||
end
|
||||
|
||||
describe "when the config file specifies queues with weights" do
|
||||
|
@ -288,7 +293,7 @@ describe Sidekiq::CLI do
|
|||
-r ./test/fake_env.rb
|
||||
-q foo -q bar])
|
||||
|
||||
assert_equal true, !!Sidekiq.options[:strict]
|
||||
assert_equal true, !!config[:strict]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -297,7 +302,7 @@ describe Sidekiq::CLI do
|
|||
subject.parse(%w[sidekiq -C ./test/config.yml
|
||||
-r ./test/fake_env.rb])
|
||||
|
||||
assert_equal false, !!Sidekiq.options[:strict]
|
||||
assert_equal false, !!config[:strict]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -307,7 +312,7 @@ describe Sidekiq::CLI do
|
|||
-r ./test/fake_env.rb
|
||||
-q foo,2 -q bar,3])
|
||||
|
||||
assert_equal false, !!Sidekiq.options[:strict]
|
||||
assert_equal false, !!config[:strict]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -319,7 +324,7 @@ describe Sidekiq::CLI do
|
|||
-r ./test/fake_env.rb
|
||||
-q foo -q bar])
|
||||
|
||||
assert_equal true, !!Sidekiq.options[:strict]
|
||||
assert_equal true, !!config[:strict]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -328,7 +333,7 @@ describe Sidekiq::CLI do
|
|||
subject.parse(%w[sidekiq -C ./test/config_queues_without_weights.yml
|
||||
-r ./test/fake_env.rb])
|
||||
|
||||
assert_equal true, !!Sidekiq.options[:strict]
|
||||
assert_equal true, !!config[:strict]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -338,7 +343,7 @@ describe Sidekiq::CLI do
|
|||
-r ./test/fake_env.rb
|
||||
-q foo,2 -q bar,3])
|
||||
|
||||
assert_equal false, !!Sidekiq.options[:strict]
|
||||
assert_equal false, !!config[:strict]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -350,7 +355,7 @@ describe Sidekiq::CLI do
|
|||
-r ./test/fake_env.rb
|
||||
-q foo -q bar])
|
||||
|
||||
assert_equal true, !!Sidekiq.options[:strict]
|
||||
assert_equal true, !!config[:strict]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -359,7 +364,7 @@ describe Sidekiq::CLI do
|
|||
subject.parse(%w[sidekiq -C ./test/config_empty.yml
|
||||
-r ./test/fake_env.rb])
|
||||
|
||||
assert_equal true, !!Sidekiq.options[:strict]
|
||||
assert_equal true, !!config[:strict]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -369,7 +374,7 @@ describe Sidekiq::CLI do
|
|||
-r ./test/fake_env.rb
|
||||
-q foo,2 -q bar,3])
|
||||
|
||||
assert_equal false, !!Sidekiq.options[:strict]
|
||||
assert_equal false, !!config[:strict]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -380,8 +385,8 @@ describe Sidekiq::CLI do
|
|||
it "tries config/sidekiq.yml" do
|
||||
subject.parse(%w[sidekiq -r ./test/dummy])
|
||||
|
||||
assert_equal "sidekiq.yml", File.basename(Sidekiq.options[:config_file])
|
||||
assert_equal 25, Sidekiq.options[:concurrency]
|
||||
assert_equal "sidekiq.yml", File.basename(config[:config_file])
|
||||
assert_equal 25, config[:concurrency]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -451,14 +456,15 @@ describe Sidekiq::CLI do
|
|||
|
||||
describe "#run" do
|
||||
before do
|
||||
Sidekiq.options[:concurrency] = 2
|
||||
Sidekiq.options[:require] = "./test/fake_env.rb"
|
||||
subject.config = Sidekiq
|
||||
subject.config[:concurrency] = 2
|
||||
subject.config[:require] = "./test/fake_env.rb"
|
||||
end
|
||||
|
||||
describe "require workers" do
|
||||
describe "when path is a rails directory" do
|
||||
before do
|
||||
Sidekiq.options[:require] = "./test/dummy"
|
||||
subject.config[:require] = "./test/dummy"
|
||||
subject.environment = "test"
|
||||
end
|
||||
|
||||
|
@ -476,7 +482,7 @@ describe Sidekiq::CLI do
|
|||
subject.run
|
||||
end
|
||||
|
||||
assert_equal "dummy", Sidekiq.options[:tag]
|
||||
assert_equal "dummy", subject.config[:tag]
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -556,11 +562,12 @@ describe Sidekiq::CLI do
|
|||
it "quiets with a corresponding event" do
|
||||
quiet = false
|
||||
|
||||
Sidekiq.on(:quiet) do
|
||||
subject.config = Sidekiq
|
||||
subject.config.on(:quiet) do
|
||||
quiet = true
|
||||
end
|
||||
|
||||
subject.launcher = Sidekiq::Launcher.new(Sidekiq.options)
|
||||
subject.launcher = Sidekiq::Launcher.new(subject.config)
|
||||
subject.handle_signal("TSTP")
|
||||
|
||||
assert_match(/Got TSTP signal/, logdev.string)
|
||||
|
|
|
@ -132,13 +132,13 @@ describe Sidekiq::Client do
|
|||
end
|
||||
|
||||
describe "argument checking" do
|
||||
before do
|
||||
Sidekiq.strict_args!(false)
|
||||
end
|
||||
before do
|
||||
Sidekiq.strict_args!(false)
|
||||
end
|
||||
|
||||
after do
|
||||
Sidekiq.strict_args!(:raise)
|
||||
end
|
||||
after do
|
||||
Sidekiq.strict_args!(:raise)
|
||||
end
|
||||
|
||||
class InterestingWorker
|
||||
include Sidekiq::Worker
|
||||
|
|
|
@ -1,17 +1,19 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative "./helper"
|
||||
require "sidekiq/web/csrf_protection"
|
||||
|
||||
class TestCsrf < Minitest::Test
|
||||
describe "Csrf" do
|
||||
def session
|
||||
@session ||= {}
|
||||
end
|
||||
|
||||
def env(method = :get, form_hash = {}, rack_session = session)
|
||||
imp = StringIO.new("")
|
||||
imp = StringIO.new
|
||||
{
|
||||
"REQUEST_METHOD" => method.to_s.upcase,
|
||||
"rack.session" => rack_session,
|
||||
"rack.logger" => ::Logger.new(@logio ||= StringIO.new("")),
|
||||
"rack.logger" => ::Logger.new(@logio ||= StringIO.new),
|
||||
"rack.input" => imp,
|
||||
"rack.request.form_input" => imp,
|
||||
"rack.request.form_hash" => form_hash
|
||||
|
@ -22,7 +24,7 @@ class TestCsrf < Minitest::Test
|
|||
Sidekiq::Web::CsrfProtection.new(block).call(env)
|
||||
end
|
||||
|
||||
def test_get
|
||||
it "get" do
|
||||
ok = [200, {}, ["OK"]]
|
||||
first = 1
|
||||
second = 1
|
||||
|
@ -46,7 +48,7 @@ class TestCsrf < Minitest::Test
|
|||
refute_equal first, second
|
||||
end
|
||||
|
||||
def test_bad_post
|
||||
it "bad post" do
|
||||
result = call(env(:post)) do
|
||||
raise "Shouldnt be called"
|
||||
end
|
||||
|
@ -58,7 +60,7 @@ class TestCsrf < Minitest::Test
|
|||
assert_match(/attack prevented/, @logio.string)
|
||||
end
|
||||
|
||||
def test_good_and_bad_posts
|
||||
it "succeeds with good token" do
|
||||
# Make a GET to set up the session with a good token
|
||||
goodtoken = call(env) do |envy|
|
||||
envy[:csrf_token]
|
||||
|
@ -72,7 +74,9 @@ class TestCsrf < Minitest::Test
|
|||
refute_nil result
|
||||
assert_equal 200, result[0]
|
||||
assert_equal ["OK"], result[2]
|
||||
end
|
||||
|
||||
it "fails with bad token" do
|
||||
# Make a POST with a known bad token
|
||||
result = call(env(:post, "authenticity_token" => "N0QRBD34tU61d7fi+0ZaF/35JLW/9K+8kk8dc1TZoK/0pTl7GIHap5gy7BWGsoKlzbMLRp1yaDpCDFwTJtxWAg==")) do
|
||||
raise "shouldnt be called"
|
||||
|
@ -82,7 +86,7 @@ class TestCsrf < Minitest::Test
|
|||
assert_equal ["Forbidden"], result[2]
|
||||
end
|
||||
|
||||
def test_empty_session_post
|
||||
it "empty session post" do
|
||||
# Make a GET to set up the session with a good token
|
||||
goodtoken = call(env) do |envy|
|
||||
envy[:csrf_token]
|
||||
|
@ -98,7 +102,8 @@ class TestCsrf < Minitest::Test
|
|||
assert_equal ["Forbidden"], result[2]
|
||||
end
|
||||
|
||||
def test_empty_csrf_session_post
|
||||
it "empty csrf session post" do
|
||||
# Make a GET to set up the session with a good token
|
||||
goodtoken = call(env) do |envy|
|
||||
envy[:csrf_token]
|
||||
end
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative "./helper"
|
||||
require "sidekiq/middleware/current_attributes"
|
||||
require "sidekiq/fetch"
|
||||
|
||||
module Myapp
|
||||
class Current < ActiveSupport::CurrentAttributes
|
||||
|
@ -7,8 +10,8 @@ module Myapp
|
|||
end
|
||||
end
|
||||
|
||||
class TestCurrentAttributes < Minitest::Test
|
||||
def test_save
|
||||
describe "Current attributes" do
|
||||
it "saves" do
|
||||
cm = Sidekiq::CurrentAttributes::Save.new(Myapp::Current)
|
||||
job = {}
|
||||
with_context(:user_id, 123) do
|
||||
|
@ -18,7 +21,7 @@ class TestCurrentAttributes < Minitest::Test
|
|||
end
|
||||
end
|
||||
|
||||
def test_load
|
||||
it "loads" do
|
||||
cm = Sidekiq::CurrentAttributes::Load.new(Myapp::Current)
|
||||
|
||||
job = {"cattr" => {"user_id" => 123}}
|
||||
|
@ -29,7 +32,7 @@ class TestCurrentAttributes < Minitest::Test
|
|||
# the Rails reloader is responsible for reseting Current after every unit of work
|
||||
end
|
||||
|
||||
def test_persist
|
||||
it "persists" do
|
||||
Sidekiq::CurrentAttributes.persist(Myapp::Current)
|
||||
job_hash = {}
|
||||
with_context(:user_id, 16) do
|
||||
|
@ -38,15 +41,15 @@ class TestCurrentAttributes < Minitest::Test
|
|||
end
|
||||
end
|
||||
|
||||
assert_nil Myapp::Current.user_id
|
||||
Sidekiq.server_middleware.invoke(nil, job_hash, nil) do
|
||||
assert_equal 16, job_hash["cattr"][:user_id]
|
||||
assert_equal 16, Myapp::Current.user_id
|
||||
end
|
||||
assert_nil Myapp::Current.user_id
|
||||
ensure
|
||||
Sidekiq.client_middleware.clear
|
||||
Sidekiq.server_middleware.clear
|
||||
# assert_nil Myapp::Current.user_id
|
||||
# Sidekiq.server_middleware.invoke(nil, job_hash, nil) do
|
||||
# assert_equal 16, job_hash["cattr"][:user_id]
|
||||
# assert_equal 16, Myapp::Current.user_id
|
||||
# end
|
||||
# assert_nil Myapp::Current.user_id
|
||||
# ensure
|
||||
# Sidekiq.client_middleware.clear
|
||||
# Sidekiq.server_middleware.clear
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
@ -1,15 +1,20 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative "helper"
|
||||
require "sidekiq/exception_handler"
|
||||
require "sidekiq/component"
|
||||
require "stringio"
|
||||
require "logger"
|
||||
|
||||
ExceptionHandlerTestException = Class.new(StandardError)
|
||||
TEST_EXCEPTION = ExceptionHandlerTestException.new("Something didn't work!")
|
||||
|
||||
class Component
|
||||
include Sidekiq::ExceptionHandler
|
||||
class Thing
|
||||
include Sidekiq::Component
|
||||
attr_reader :config
|
||||
|
||||
def initialize(config)
|
||||
@config = config
|
||||
end
|
||||
|
||||
def invoke_exception(args)
|
||||
raise TEST_EXCEPTION
|
||||
|
@ -18,25 +23,23 @@ class Component
|
|||
end
|
||||
end
|
||||
|
||||
describe Sidekiq::ExceptionHandler do
|
||||
describe Sidekiq::Component do
|
||||
describe "with mock logger" do
|
||||
before do
|
||||
@old_logger = Sidekiq.logger
|
||||
@str_logger = StringIO.new
|
||||
Sidekiq.logger = Logger.new(@str_logger)
|
||||
@config = Sidekiq
|
||||
@config[:error_handlers] << Sidekiq.method(:default_error_handler)
|
||||
end
|
||||
|
||||
after do
|
||||
Sidekiq.logger = @old_logger
|
||||
@config[:error_handlers].clear
|
||||
end
|
||||
|
||||
it "logs the exception to Sidekiq.logger" do
|
||||
Component.new.invoke_exception(a: 1)
|
||||
@str_logger.rewind
|
||||
log = @str_logger.readlines
|
||||
assert_match(/"a":1/, log[0], "didn't include the context")
|
||||
assert_match(/Something didn't work!/, log[1], "didn't include the exception message")
|
||||
assert_match(/test\/test_exception_handler.rb/, log[2], "didn't include the backtrace")
|
||||
output = capture_logging do
|
||||
Thing.new(@config).invoke_exception(a: 1)
|
||||
end
|
||||
assert_match(/"a":1/, output, "didn't include the context")
|
||||
assert_match(/Something didn't work!/, output, "didn't include the exception message")
|
||||
assert_match(/test\/test_exception_handler.rb/, output, "didn't include the backtrace")
|
||||
end
|
||||
|
||||
describe "when the exception does not have a backtrace" do
|
||||
|
@ -44,12 +47,7 @@ describe Sidekiq::ExceptionHandler do
|
|||
exception = ExceptionHandlerTestException.new
|
||||
assert_nil exception.backtrace
|
||||
|
||||
begin
|
||||
Component.new.handle_exception exception
|
||||
pass
|
||||
rescue
|
||||
flunk "failed handling a nil backtrace"
|
||||
end
|
||||
Thing.new(@config).handle_exception exception
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -6,19 +6,21 @@ require "sidekiq/api"
|
|||
|
||||
describe Sidekiq::BasicFetch do
|
||||
before do
|
||||
@prev_redis = Sidekiq.instance_variable_get(:@redis) || {}
|
||||
Sidekiq.redis do |conn|
|
||||
conn.flushdb
|
||||
conn.rpush("queue:basic", "msg")
|
||||
end
|
||||
Sidekiq.reset!
|
||||
@config = Sidekiq
|
||||
end
|
||||
|
||||
after do
|
||||
Sidekiq.redis = @prev_redis
|
||||
def fetcher(options)
|
||||
@config.merge!(options)
|
||||
Sidekiq::BasicFetch.new(@config)
|
||||
end
|
||||
|
||||
it "retrieves" do
|
||||
fetch = Sidekiq::BasicFetch.new(queues: ["basic", "bar"])
|
||||
fetch = fetcher(queues: ["basic", "bar"])
|
||||
uow = fetch.retrieve_work
|
||||
refute_nil uow
|
||||
assert_equal "basic", uow.queue_name
|
||||
|
@ -31,7 +33,7 @@ describe Sidekiq::BasicFetch do
|
|||
end
|
||||
|
||||
it "retrieves with strict setting" do
|
||||
fetch = Sidekiq::BasicFetch.new(queues: ["basic", "bar", "bar"], strict: true)
|
||||
fetch = fetcher(queues: ["basic", "bar", "bar"], strict: true)
|
||||
cmd = fetch.queues_cmd
|
||||
assert_equal cmd, ["queue:basic", "queue:bar", Sidekiq::BasicFetch::TIMEOUT]
|
||||
end
|
||||
|
@ -47,7 +49,7 @@ describe Sidekiq::BasicFetch do
|
|||
assert_equal 2, q1.size
|
||||
assert_equal 1, q2.size
|
||||
|
||||
fetch = Sidekiq::BasicFetch.new(queues: ["foo", "bar"])
|
||||
fetch = fetcher(queues: ["foo", "bar"])
|
||||
works = 3.times.map { fetch.retrieve_work }
|
||||
assert_equal 0, q1.size
|
||||
assert_equal 0, q2.size
|
||||
|
@ -58,7 +60,7 @@ describe Sidekiq::BasicFetch do
|
|||
end
|
||||
|
||||
it "sleeps when no queues are active" do
|
||||
fetch = Sidekiq::BasicFetch.new(queues: [])
|
||||
fetch = fetcher(queues: [])
|
||||
mock = Minitest::Mock.new
|
||||
mock.expect(:call, nil, [Sidekiq::BasicFetch::TIMEOUT])
|
||||
fetch.stub(:sleep, mock) { assert_nil fetch.retrieve_work }
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative "helper"
|
||||
|
||||
describe Sidekiq::Job do
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
require_relative "helper"
|
||||
require "sidekiq/job_logger"
|
||||
|
||||
class TestJobLogger < Minitest::Test
|
||||
def setup
|
||||
describe "Job logger" do
|
||||
before do
|
||||
@old = Sidekiq.logger
|
||||
@output = StringIO.new
|
||||
@logger = Sidekiq::Logger.new(@output, level: :info)
|
||||
|
@ -14,13 +14,13 @@ class TestJobLogger < Minitest::Test
|
|||
Thread.current[:sidekiq_tid] = nil
|
||||
end
|
||||
|
||||
def teardown
|
||||
after do
|
||||
Thread.current[:sidekiq_context] = nil
|
||||
Thread.current[:sidekiq_tid] = nil
|
||||
Sidekiq.logger = @old
|
||||
end
|
||||
|
||||
def test_pretty_output
|
||||
it "tests pretty output" do
|
||||
jl = Sidekiq::JobLogger.new(@logger)
|
||||
|
||||
# pretty
|
||||
|
@ -41,7 +41,7 @@ class TestJobLogger < Minitest::Test
|
|||
assert_match(/#{Time.now.utc.to_date}.+Z pid=#{$$} tid=#{p.tid} .+INFO: done/, b)
|
||||
end
|
||||
|
||||
def test_json_output
|
||||
it "tests json output" do
|
||||
# json
|
||||
@logger.formatter = Sidekiq::Logger::Formatters::JSON.new
|
||||
jl = Sidekiq::JobLogger.new(@logger)
|
||||
|
@ -60,7 +60,7 @@ class TestJobLogger < Minitest::Test
|
|||
assert_equal(["bid", "class", "jid", "tags"], keys)
|
||||
end
|
||||
|
||||
def test_custom_log_level
|
||||
it "tests custom log level" do
|
||||
jl = Sidekiq::JobLogger.new(@logger)
|
||||
job = {"class" => "FooWorker", "log_level" => "debug"}
|
||||
|
||||
|
@ -79,7 +79,7 @@ class TestJobLogger < Minitest::Test
|
|||
assert_match(/INFO: done/, c)
|
||||
end
|
||||
|
||||
def test_custom_log_level_uses_default_log_level_for_invalid_value
|
||||
it "tests custom log level uses default log level for invalid value" do
|
||||
jl = Sidekiq::JobLogger.new(@logger)
|
||||
job = {"class" => "FooWorker", "log_level" => "non_existent"}
|
||||
|
||||
|
@ -94,7 +94,7 @@ class TestJobLogger < Minitest::Test
|
|||
assert_match(/WARN: Invalid log level/, log_level_warning)
|
||||
end
|
||||
|
||||
def test_custom_logger_with_non_numeric_levels
|
||||
it "tests custom logger with non numeric levels" do
|
||||
logger_class = Class.new(Logger) do
|
||||
def level
|
||||
:nonsense
|
||||
|
|
|
@ -4,9 +4,16 @@ require_relative "helper"
|
|||
require "sidekiq/launcher"
|
||||
|
||||
describe Sidekiq::Launcher do
|
||||
subject { Sidekiq::Launcher.new(options) }
|
||||
subject do
|
||||
Sidekiq::Launcher.new(@config)
|
||||
end
|
||||
|
||||
before do
|
||||
Sidekiq.redis { |c| c.flushdb }
|
||||
Sidekiq.reset!
|
||||
@config = Sidekiq
|
||||
@config[:tag] = "myapp"
|
||||
@config[:concurrency] = 3
|
||||
end
|
||||
|
||||
def new_manager(opts)
|
||||
|
@ -23,8 +30,8 @@ describe Sidekiq::Launcher do
|
|||
|
||||
describe "heartbeat" do
|
||||
before do
|
||||
@mgr = new_manager(options)
|
||||
@launcher = Sidekiq::Launcher.new(options)
|
||||
@mgr = new_manager(@config)
|
||||
@launcher = Sidekiq::Launcher.new(@config)
|
||||
@launcher.manager = @mgr
|
||||
@id = @launcher.identity
|
||||
|
||||
|
@ -157,8 +164,4 @@ describe Sidekiq::Launcher do
|
|||
end
|
||||
end
|
||||
end
|
||||
|
||||
def options
|
||||
{concurrency: 3, queues: ["default"], tag: "myapp"}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,8 +3,8 @@
|
|||
require_relative "helper"
|
||||
require "sidekiq/logger"
|
||||
|
||||
class TestLogger < Minitest::Test
|
||||
def setup
|
||||
describe "logger" do
|
||||
before do
|
||||
@output = StringIO.new
|
||||
@logger = Sidekiq::Logger.new(@output)
|
||||
|
||||
|
@ -13,30 +13,30 @@ class TestLogger < Minitest::Test
|
|||
Thread.current[:sidekiq_tid] = nil
|
||||
end
|
||||
|
||||
def teardown
|
||||
after do
|
||||
Sidekiq.log_formatter = nil
|
||||
Thread.current[:sidekiq_context] = nil
|
||||
Thread.current[:sidekiq_tid] = nil
|
||||
end
|
||||
|
||||
def test_default_log_formatter
|
||||
it "tests default logger format" do
|
||||
assert_kind_of Sidekiq::Logger::Formatters::Pretty, Sidekiq::Logger.new(@output).formatter
|
||||
end
|
||||
|
||||
def test_heroku_log_formatter
|
||||
it "tests heroku logger formatter" do
|
||||
ENV["DYNO"] = "dyno identifier"
|
||||
assert_kind_of Sidekiq::Logger::Formatters::WithoutTimestamp, Sidekiq::Logger.new(@output).formatter
|
||||
ensure
|
||||
ENV["DYNO"] = nil
|
||||
end
|
||||
|
||||
def test_json_log_formatter
|
||||
it "tests json logger formatter" do
|
||||
Sidekiq.log_formatter = Sidekiq::Logger::Formatters::JSON.new
|
||||
|
||||
assert_kind_of Sidekiq::Logger::Formatters::JSON, Sidekiq::Logger.new(@output).formatter
|
||||
end
|
||||
|
||||
def test_with_context
|
||||
it "tests with context" do
|
||||
subject = Sidekiq::Context
|
||||
assert_equal({}, subject.current)
|
||||
|
||||
|
@ -47,9 +47,9 @@ class TestLogger < Minitest::Test
|
|||
assert_equal({}, subject.current)
|
||||
end
|
||||
|
||||
def test_with_overlapping_context
|
||||
it "tests with overlapping context" do
|
||||
subject = Sidekiq::Context
|
||||
subject.current.merge!({foo: "bar"})
|
||||
subject.current[:foo] = "bar"
|
||||
assert_equal({foo: "bar"}, subject.current)
|
||||
|
||||
subject.with(foo: "bingo") do
|
||||
|
@ -59,7 +59,7 @@ class TestLogger < Minitest::Test
|
|||
assert_equal({foo: "bar"}, subject.current)
|
||||
end
|
||||
|
||||
def test_nested_contexts
|
||||
it "tests nested contexts" do
|
||||
subject = Sidekiq::Context
|
||||
assert_equal({}, subject.current)
|
||||
|
||||
|
@ -76,7 +76,7 @@ class TestLogger < Minitest::Test
|
|||
assert_equal({}, subject.current)
|
||||
end
|
||||
|
||||
def test_formatted_output
|
||||
it "tests formatted output" do
|
||||
@logger.info("hello world")
|
||||
assert_match(/INFO: hello world/, @output.string)
|
||||
reset(@output)
|
||||
|
@ -96,7 +96,7 @@ class TestLogger < Minitest::Test
|
|||
end
|
||||
end
|
||||
|
||||
def test_json_output_is_parsable
|
||||
it "makes sure json output is parseable" do
|
||||
@logger.formatter = Sidekiq::Logger::Formatters::JSON.new
|
||||
|
||||
@logger.debug("boom")
|
||||
|
@ -118,7 +118,7 @@ class TestLogger < Minitest::Test
|
|||
assert_equal "INFO", hash["lvl"]
|
||||
end
|
||||
|
||||
def test_forwards_logger_kwargs
|
||||
it "tests forwards logger kwards" do
|
||||
assert_silent do
|
||||
logger = Sidekiq::Logger.new("/dev/null", level: Logger::INFO)
|
||||
|
||||
|
@ -126,7 +126,7 @@ class TestLogger < Minitest::Test
|
|||
end
|
||||
end
|
||||
|
||||
def test_log_level_query_methods
|
||||
it "tests log level query methods" do
|
||||
logger = Sidekiq::Logger.new("/dev/null", level: Logger::INFO)
|
||||
|
||||
refute_predicate logger, :debug?
|
||||
|
|
|
@ -6,42 +6,36 @@ require "sidekiq/manager"
|
|||
describe Sidekiq::Manager do
|
||||
before do
|
||||
Sidekiq.redis { |c| c.flushdb }
|
||||
Sidekiq.reset!
|
||||
@config = Sidekiq
|
||||
@config[:fetch] = Sidekiq::BasicFetch.new(@config)
|
||||
end
|
||||
|
||||
def new_manager(opts)
|
||||
Sidekiq::Manager.new(opts.merge(fetch: Sidekiq::BasicFetch.new(opts)))
|
||||
def new_manager
|
||||
Sidekiq::Manager.new(@config)
|
||||
end
|
||||
|
||||
it "creates N processor instances" do
|
||||
mgr = new_manager(options)
|
||||
assert_equal options[:concurrency], mgr.workers.size
|
||||
mgr = new_manager
|
||||
assert_equal @config[:concurrency], mgr.workers.size
|
||||
end
|
||||
|
||||
it "shuts down the system" do
|
||||
mgr = new_manager(options)
|
||||
mgr = new_manager
|
||||
mgr.stop(::Process.clock_gettime(::Process::CLOCK_MONOTONIC))
|
||||
end
|
||||
|
||||
it "throws away dead processors" do
|
||||
mgr = new_manager(options)
|
||||
mgr = new_manager
|
||||
init_size = mgr.workers.size
|
||||
processor = mgr.workers.first
|
||||
begin
|
||||
mgr.processor_died(processor, "ignored")
|
||||
mgr.processor_result(processor, "ignored")
|
||||
|
||||
assert_equal init_size, mgr.workers.size
|
||||
refute mgr.workers.include?(processor)
|
||||
ensure
|
||||
mgr.workers.each { |p| p.terminate(true) }
|
||||
mgr.quiet
|
||||
end
|
||||
end
|
||||
|
||||
it "does not support invalid concurrency" do
|
||||
assert_raises(ArgumentError) { new_manager(concurrency: 0) }
|
||||
assert_raises(ArgumentError) { new_manager(concurrency: -1) }
|
||||
end
|
||||
|
||||
def options
|
||||
{concurrency: 3, queues: ["default"]}
|
||||
end
|
||||
end
|
||||
|
|
|
@ -77,17 +77,15 @@ describe Sidekiq::Middleware do
|
|||
it "executes middleware in the proper order" do
|
||||
msg = Sidekiq.dump_json({"class" => CustomWorker.to_s, "args" => [$recorder]})
|
||||
|
||||
Sidekiq.server_middleware do |chain|
|
||||
@config = Sidekiq
|
||||
@config.server_middleware do |chain|
|
||||
# should only add once, second should replace the first
|
||||
2.times { |i| chain.add CustomMiddleware, i.to_s, $recorder }
|
||||
chain.insert_before CustomMiddleware, AnotherCustomMiddleware, "2", $recorder
|
||||
chain.insert_after AnotherCustomMiddleware, YetAnotherCustomMiddleware, "3", $recorder
|
||||
end
|
||||
|
||||
boss = Minitest::Mock.new
|
||||
opts = {queues: ["default"]}
|
||||
processor = Sidekiq::Processor.new(boss, opts)
|
||||
boss.expect(:processor_done, nil, [processor])
|
||||
processor = Sidekiq::Processor.new(@config) { |pr, ex| }
|
||||
processor.process(Sidekiq::BasicFetch::UnitOfWork.new("queue:default", msg))
|
||||
assert_equal %w[2 before 3 before 1 before work_performed 1 after 3 after 2 after], $recorder.flatten
|
||||
end
|
||||
|
@ -167,4 +165,28 @@ describe Sidekiq::Middleware do
|
|||
I18n.available_locales = nil
|
||||
end
|
||||
end
|
||||
|
||||
class FooC
|
||||
include Sidekiq::ClientMiddleware
|
||||
def initialize(*args)
|
||||
@args = args
|
||||
end
|
||||
|
||||
def call(w, j, q, rp)
|
||||
redis { |c| c.incr(self.class.name) }
|
||||
logger.info { |c| [self.class.name, @args].inspect }
|
||||
yield
|
||||
end
|
||||
end
|
||||
|
||||
describe "configuration" do
|
||||
it "gets an object which provides redis and logging" do
|
||||
cfg = Sidekiq
|
||||
chain = Sidekiq::Middleware::Chain.new(cfg)
|
||||
chain.add FooC, foo: "bar"
|
||||
final_action = nil
|
||||
chain.invoke(nil, nil, nil, nil) { final_action = true }
|
||||
assert final_action
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -11,10 +11,9 @@ describe Sidekiq::Processor do
|
|||
|
||||
before do
|
||||
$invokes = 0
|
||||
@mgr = Minitest::Mock.new
|
||||
opts = {queues: ["default"]}
|
||||
opts[:fetch] = Sidekiq::BasicFetch.new(opts)
|
||||
@processor = ::Sidekiq::Processor.new(@mgr, opts)
|
||||
@config = Sidekiq
|
||||
@config[:fetch] = Sidekiq::BasicFetch.new(@config)
|
||||
@processor = ::Sidekiq::Processor.new(@config) { |*args| }
|
||||
end
|
||||
|
||||
class MockWorker
|
||||
|
@ -60,7 +59,6 @@ describe Sidekiq::Processor do
|
|||
it "does not modify original arguments" do
|
||||
msg = {"class" => MockWorker.to_s, "args" => [["myarg"]]}
|
||||
msgstr = Sidekiq.dump_json(msg)
|
||||
@mgr.expect(:processor_done, nil, [@processor])
|
||||
@processor.process(work(msgstr))
|
||||
assert_equal [["myarg"]], msg["args"]
|
||||
end
|
||||
|
@ -208,7 +206,6 @@ describe Sidekiq::Processor do
|
|||
|
||||
it "acks the job" do
|
||||
work.expect(:acknowledge, nil)
|
||||
@mgr.expect(:processor_done, nil, [@processor])
|
||||
@processor.process(work)
|
||||
end
|
||||
end
|
||||
|
@ -229,7 +226,6 @@ describe Sidekiq::Processor do
|
|||
describe "everything goes well" do
|
||||
it "acks the job" do
|
||||
work.expect(:acknowledge, nil)
|
||||
@mgr.expect(:processor_done, nil, [@processor])
|
||||
@processor.process(work)
|
||||
end
|
||||
end
|
||||
|
@ -306,7 +302,6 @@ describe Sidekiq::Processor do
|
|||
|
||||
def successful_job
|
||||
msg = Sidekiq.dump_json({"class" => MockWorker.to_s, "args" => ["myarg"]})
|
||||
@mgr.expect(:processor_done, nil, [@processor])
|
||||
@processor.process(work(msg))
|
||||
end
|
||||
|
||||
|
@ -328,8 +323,7 @@ describe Sidekiq::Processor do
|
|||
|
||||
before do
|
||||
opts = {queues: ["default"], job_logger: CustomJobLogger}
|
||||
@mgr = Minitest::Mock.new
|
||||
@processor = ::Sidekiq::Processor.new(@mgr, opts)
|
||||
@processor = ::Sidekiq::Processor.new(opts) { |pr, ex| }
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -341,7 +335,6 @@ describe Sidekiq::Processor do
|
|||
|
||||
def successful_job
|
||||
msg = Sidekiq.dump_json({"class" => MockWorker.to_s, "args" => ["myarg"]})
|
||||
@mgr.expect(:processor_done, nil, [@processor])
|
||||
@processor.process(work(msg))
|
||||
end
|
||||
|
||||
|
@ -354,9 +347,10 @@ describe Sidekiq::Processor do
|
|||
|
||||
describe "custom job logger class" do
|
||||
before do
|
||||
opts = {queues: ["default"], job_logger: CustomJobLogger}
|
||||
opts = Sidekiq
|
||||
opts[:job_logger] = CustomJobLogger
|
||||
opts[:fetch] = Sidekiq::BasicFetch.new(opts)
|
||||
@processor = ::Sidekiq::Processor.new(nil, opts)
|
||||
@processor = ::Sidekiq::Processor.new(opts) { |pr, ex| }
|
||||
end
|
||||
|
||||
it "is called instead default Sidekiq::JobLogger" do
|
||||
|
|
|
@ -6,7 +6,7 @@ require "sidekiq/cli"
|
|||
describe Sidekiq::RedisConnection do
|
||||
describe "create" do
|
||||
before do
|
||||
Sidekiq.options = Sidekiq::DEFAULTS.dup
|
||||
Sidekiq.reset!
|
||||
@old = ENV["REDIS_URL"]
|
||||
ENV["REDIS_URL"] = "redis://localhost/15"
|
||||
end
|
||||
|
@ -60,14 +60,15 @@ describe Sidekiq::RedisConnection do
|
|||
|
||||
it "defaults server pool sizes based on concurrency with padding" do
|
||||
_expected_padding = 5
|
||||
prev_concurrency = Sidekiq.options[:concurrency]
|
||||
Sidekiq.options[:concurrency] = 6
|
||||
config = Sidekiq
|
||||
prev_concurrency = config[:concurrency]
|
||||
config[:concurrency] = 6
|
||||
pool = server_connection
|
||||
|
||||
assert_equal 11, pool.instance_eval { @size }
|
||||
assert_equal 11, pool.instance_eval { @available.length }
|
||||
ensure
|
||||
Sidekiq.options[:concurrency] = prev_concurrency
|
||||
config[:concurrency] = prev_concurrency
|
||||
end
|
||||
|
||||
it "defaults client pool sizes to 5" do
|
||||
|
|
|
@ -5,28 +5,31 @@ require "sidekiq/scheduled"
|
|||
require "sidekiq/job_retry"
|
||||
require "sidekiq/api"
|
||||
|
||||
class SomeWorker
|
||||
include Sidekiq::Worker
|
||||
end
|
||||
|
||||
class BadErrorMessage < StandardError
|
||||
def message
|
||||
raise "Ahhh, this isn't supposed to happen"
|
||||
end
|
||||
end
|
||||
|
||||
describe Sidekiq::JobRetry do
|
||||
before do
|
||||
Sidekiq.redis { |c| c.flushdb }
|
||||
@config = Sidekiq
|
||||
@config[:max_retries] = 25
|
||||
@config[:error_handlers] << Sidekiq.method(:default_error_handler)
|
||||
end
|
||||
|
||||
describe "middleware" do
|
||||
class SomeWorker
|
||||
include Sidekiq::Worker
|
||||
end
|
||||
|
||||
class BadErrorMessage < StandardError
|
||||
def message
|
||||
raise "Ahhh, this isn't supposed to happen"
|
||||
end
|
||||
end
|
||||
|
||||
before do
|
||||
Sidekiq.redis { |c| c.flushdb }
|
||||
end
|
||||
|
||||
def worker
|
||||
@worker ||= SomeWorker.new
|
||||
end
|
||||
|
||||
def handler(options = {})
|
||||
@handler ||= Sidekiq::JobRetry.new(options)
|
||||
def handler
|
||||
@handler ||= Sidekiq::JobRetry.new(@config)
|
||||
end
|
||||
|
||||
def jobstr(options = {})
|
||||
|
@ -105,7 +108,8 @@ describe Sidekiq::JobRetry do
|
|||
1.upto(max_retries + 1) do |i|
|
||||
assert_raises RuntimeError do
|
||||
job = i > 1 ? jobstr("retry_count" => i - 2) : jobstr
|
||||
handler(max_retries: max_retries).local(worker, job, "default") do
|
||||
@config[:max_retries] = max_retries
|
||||
handler.local(worker, job, "default") do
|
||||
raise "kerblammo!"
|
||||
end
|
||||
end
|
||||
|
@ -119,7 +123,7 @@ describe Sidekiq::JobRetry do
|
|||
c = nil
|
||||
assert_raises RuntimeError do
|
||||
handler.local(worker, jobstr("backtrace" => true), "default") do
|
||||
c = caller(0); raise "kerblammo!"
|
||||
(c = caller(0)) && raise("kerblammo!")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -132,13 +136,13 @@ describe Sidekiq::JobRetry do
|
|||
c = nil
|
||||
assert_raises RuntimeError do
|
||||
handler.local(worker, jobstr("backtrace" => 3), "default") do
|
||||
c = caller(0)[0...3]; raise "kerblammo!"
|
||||
c = caller(0)[0...3]
|
||||
raise "kerblammo!"
|
||||
end
|
||||
end
|
||||
|
||||
job = Sidekiq::RetrySet.new.first
|
||||
assert job.error_backtrace
|
||||
assert_equal c, job.error_backtrace
|
||||
assert_equal 3, c.size
|
||||
end
|
||||
|
||||
|
@ -221,6 +225,7 @@ describe Sidekiq::JobRetry do
|
|||
raise "kerblammo!"
|
||||
end
|
||||
end
|
||||
assert job, "No job found in retry set"
|
||||
assert_equal "default", job["queue"]
|
||||
assert_equal "kerblammo!", job["error_message"]
|
||||
assert_equal "RuntimeError", job["error_class"]
|
||||
|
@ -248,17 +253,6 @@ describe Sidekiq::JobRetry do
|
|||
end
|
||||
|
||||
describe "custom retry delay" do
|
||||
before do
|
||||
@old_logger = Sidekiq.logger
|
||||
@tmp_log_path = "/tmp/sidekiq-retries.log"
|
||||
Sidekiq.logger = Logger.new(@tmp_log_path)
|
||||
end
|
||||
|
||||
after do
|
||||
Sidekiq.logger = @old_logger
|
||||
File.unlink @tmp_log_path if File.exist?(@tmp_log_path)
|
||||
end
|
||||
|
||||
class CustomWorkerWithoutException
|
||||
include Sidekiq::Worker
|
||||
|
||||
|
@ -315,9 +309,11 @@ describe Sidekiq::JobRetry do
|
|||
end
|
||||
|
||||
it "falls back to the default retry on exception" do
|
||||
refute_equal 4, handler.__send__(:delay_for, ErrorWorker, 2, StandardError.new)
|
||||
output = capture_logging do
|
||||
refute_equal 4, handler.__send__(:delay_for, ErrorWorker, 2, StandardError.new)
|
||||
end
|
||||
assert_match(/Failure scheduling retry using the defined `sidekiq_retry_in`/,
|
||||
File.read(@tmp_log_path), "Log entry missing for sidekiq_retry_in")
|
||||
output, "Log entry missing for sidekiq_retry_in")
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -332,7 +328,7 @@ describe Sidekiq::JobRetry do
|
|||
end
|
||||
|
||||
it "does not recurse infinitely checking if it's a shutdown" do
|
||||
assert(!Sidekiq::JobRetry.new.send(
|
||||
assert(!Sidekiq::JobRetry.new(@config).send(
|
||||
:exception_caused_by_shutdown?, @error
|
||||
))
|
||||
end
|
||||
|
@ -357,7 +353,7 @@ describe Sidekiq::JobRetry do
|
|||
end
|
||||
|
||||
it "does not recurse infinitely checking if it's a shutdown" do
|
||||
assert(!Sidekiq::JobRetry.new.send(
|
||||
assert(!Sidekiq::JobRetry.new(@config).send(
|
||||
:exception_caused_by_shutdown?, @error
|
||||
))
|
||||
end
|
||||
|
|
|
@ -1,30 +1,30 @@
|
|||
require_relative "helper"
|
||||
require "sidekiq/job_retry"
|
||||
|
||||
class NewWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_class_attribute :exhausted_called, :exhausted_job, :exhausted_exception
|
||||
|
||||
sidekiq_retries_exhausted do |job, e|
|
||||
self.exhausted_called = true
|
||||
self.exhausted_job = job
|
||||
self.exhausted_exception = e
|
||||
end
|
||||
end
|
||||
|
||||
class OldWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_class_attribute :exhausted_called, :exhausted_job, :exhausted_exception
|
||||
|
||||
sidekiq_retries_exhausted do |job|
|
||||
self.exhausted_called = true
|
||||
self.exhausted_job = job
|
||||
end
|
||||
end
|
||||
|
||||
describe "sidekiq_retries_exhausted" do
|
||||
class NewWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_class_attribute :exhausted_called, :exhausted_job, :exhausted_exception
|
||||
|
||||
sidekiq_retries_exhausted do |job, e|
|
||||
self.exhausted_called = true
|
||||
self.exhausted_job = job
|
||||
self.exhausted_exception = e
|
||||
end
|
||||
end
|
||||
|
||||
class OldWorker
|
||||
include Sidekiq::Worker
|
||||
|
||||
sidekiq_class_attribute :exhausted_called, :exhausted_job, :exhausted_exception
|
||||
|
||||
sidekiq_retries_exhausted do |job|
|
||||
self.exhausted_called = true
|
||||
self.exhausted_job = job
|
||||
end
|
||||
end
|
||||
|
||||
def cleanup
|
||||
[NewWorker, OldWorker].each do |worker_class|
|
||||
worker_class.exhausted_called = nil
|
||||
|
@ -34,6 +34,7 @@ describe "sidekiq_retries_exhausted" do
|
|||
end
|
||||
|
||||
before do
|
||||
@config = Sidekiq
|
||||
cleanup
|
||||
end
|
||||
|
||||
|
@ -49,8 +50,8 @@ describe "sidekiq_retries_exhausted" do
|
|||
@old_worker ||= OldWorker.new
|
||||
end
|
||||
|
||||
def handler(options = {})
|
||||
@handler ||= Sidekiq::JobRetry.new(options)
|
||||
def handler
|
||||
@handler ||= Sidekiq::JobRetry.new(@config)
|
||||
end
|
||||
|
||||
def job(options = {})
|
||||
|
|
|
@ -20,9 +20,10 @@ describe Sidekiq::Scheduled do
|
|||
@future_2 = {"class" => ScheduledWorker.name, "args" => [4], "queue" => "queue_5"}
|
||||
@future_3 = {"class" => ScheduledWorker.name, "args" => [5], "queue" => "queue_6"}
|
||||
|
||||
@config = Sidekiq
|
||||
@retry = Sidekiq::RetrySet.new
|
||||
@scheduled = Sidekiq::ScheduledSet.new
|
||||
@poller = Sidekiq::Scheduled::Poller.new
|
||||
@poller = Sidekiq::Scheduled::Poller.new(@config)
|
||||
end
|
||||
|
||||
class MyStopper
|
||||
|
@ -105,11 +106,11 @@ describe Sidekiq::Scheduled do
|
|||
end
|
||||
|
||||
def with_sidekiq_option(name, value)
|
||||
_original, Sidekiq.options[name] = Sidekiq.options[name], value
|
||||
original, Sidekiq[name] = Sidekiq[name], value
|
||||
begin
|
||||
yield
|
||||
ensure
|
||||
Sidekiq.options[name] = _original
|
||||
Sidekiq[name] = original
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -1,9 +1,12 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative "helper"
|
||||
require "sidekiq/cli"
|
||||
|
||||
describe Sidekiq do
|
||||
before do
|
||||
@config = Sidekiq
|
||||
end
|
||||
|
||||
describe "json processing" do
|
||||
it "handles json" do
|
||||
assert_equal({"foo" => "bar"}, Sidekiq.load_json("{\"foo\":\"bar\"}"))
|
||||
|
@ -14,39 +17,40 @@ describe Sidekiq do
|
|||
describe "redis connection" do
|
||||
it "returns error without creating a connection if block is not given" do
|
||||
assert_raises(ArgumentError) do
|
||||
Sidekiq.redis
|
||||
@config.redis
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'lifecycle events' do
|
||||
it 'handles invalid input' do
|
||||
Sidekiq.options[:lifecycle_events][:startup].clear
|
||||
describe "lifecycle events" do
|
||||
it "handles invalid input" do
|
||||
config = @config
|
||||
config[:lifecycle_events][:startup].clear
|
||||
|
||||
e = assert_raises ArgumentError do
|
||||
Sidekiq.on(:startp)
|
||||
config.on(:startp)
|
||||
end
|
||||
assert_match(/Invalid event name/, e.message)
|
||||
e = assert_raises ArgumentError do
|
||||
Sidekiq.on("startup")
|
||||
config.on("startup")
|
||||
end
|
||||
assert_match(/Symbols only/, e.message)
|
||||
Sidekiq.on(:startup) do
|
||||
config.on(:startup) do
|
||||
1 + 1
|
||||
end
|
||||
|
||||
assert_equal 2, Sidekiq.options[:lifecycle_events][:startup].first.call
|
||||
assert_equal 2, config[:lifecycle_events][:startup].first.call
|
||||
end
|
||||
end
|
||||
|
||||
describe "default_job_options" do
|
||||
it "stringifies keys" do
|
||||
@old_options = Sidekiq.default_job_options
|
||||
@old_options = @config.default_job_options
|
||||
begin
|
||||
Sidekiq.default_job_options = {queue: "cat"}
|
||||
assert_equal "cat", Sidekiq.default_job_options["queue"]
|
||||
@config.default_job_options = {queue: "cat"}
|
||||
assert_equal "cat", @config.default_job_options["queue"]
|
||||
ensure
|
||||
Sidekiq.default_job_options = @old_options
|
||||
@config.default_job_options = @old_options
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -54,13 +58,12 @@ describe Sidekiq do
|
|||
describe "error handling" do
|
||||
it "deals with user-specified error handlers which raise errors" do
|
||||
output = capture_logging do
|
||||
Sidekiq.error_handlers << proc { |x, hash|
|
||||
@config.error_handlers << proc { |x, hash|
|
||||
raise "boom"
|
||||
}
|
||||
cli = Sidekiq::CLI.new
|
||||
cli.handle_exception(RuntimeError.new("hello"))
|
||||
@config.handle_exception(RuntimeError.new("hello"))
|
||||
ensure
|
||||
Sidekiq.error_handlers.pop
|
||||
@config.error_handlers.pop
|
||||
end
|
||||
assert_includes output, "boom"
|
||||
assert_includes output, "ERROR"
|
||||
|
@ -70,7 +73,7 @@ describe Sidekiq do
|
|||
describe "redis connection" do
|
||||
it "does not continually retry" do
|
||||
assert_raises Sidekiq::RedisConnection.adapter::CommandError do
|
||||
Sidekiq.redis do |c|
|
||||
@config.redis do |c|
|
||||
raise Sidekiq::RedisConnection.adapter::CommandError, "READONLY You can't write against a replica."
|
||||
end
|
||||
end
|
||||
|
@ -78,7 +81,7 @@ describe Sidekiq do
|
|||
|
||||
it "reconnects if connection is flagged as readonly" do
|
||||
counts = []
|
||||
Sidekiq.redis do |c|
|
||||
@config.redis do |c|
|
||||
counts << c.info["total_connections_received"].to_i
|
||||
raise Sidekiq::RedisConnection.adapter::CommandError, "READONLY You can't write against a replica." if counts.size == 1
|
||||
end
|
||||
|
@ -88,7 +91,7 @@ describe Sidekiq do
|
|||
|
||||
it "reconnects if instance state changed" do
|
||||
counts = []
|
||||
Sidekiq.redis do |c|
|
||||
@config.redis do |c|
|
||||
counts << c.info["total_connections_received"].to_i
|
||||
raise Sidekiq::RedisConnection.adapter::CommandError, "UNBLOCKED force unblock from blocking operation, instance state changed (master -> replica?)" if counts.size == 1
|
||||
end
|
||||
|
@ -99,7 +102,7 @@ describe Sidekiq do
|
|||
|
||||
describe "redis info" do
|
||||
it "calls the INFO command which returns at least redis_version" do
|
||||
output = Sidekiq.redis_info
|
||||
output = @config.redis_info
|
||||
assert_includes output.keys, "redis_version"
|
||||
end
|
||||
end
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative "helper"
|
||||
require "sidekiq/sd_notify"
|
||||
require "sidekiq/systemd"
|
||||
|
||||
class TestSystemd < Minitest::Test
|
||||
def setup
|
||||
describe "Systemd" do
|
||||
before do
|
||||
::Dir::Tmpname.create("sidekiq_socket") do |sockaddr|
|
||||
@sockaddr = sockaddr
|
||||
@socket = Socket.new(:UNIX, :DGRAM, 0)
|
||||
|
@ -13,8 +15,8 @@ class TestSystemd < Minitest::Test
|
|||
end
|
||||
end
|
||||
|
||||
def teardown
|
||||
@socket.close if @socket
|
||||
after do
|
||||
@socket&.close
|
||||
File.unlink(@sockaddr) if @sockaddr
|
||||
@socket = nil
|
||||
@sockaddr = nil
|
||||
|
@ -24,7 +26,7 @@ class TestSystemd < Minitest::Test
|
|||
@socket.recvfrom(10)[0]
|
||||
end
|
||||
|
||||
def test_notify
|
||||
it "notifies" do
|
||||
count = Sidekiq::SdNotify.ready
|
||||
assert_equal(socket_message, "READY=1")
|
||||
assert_equal(ENV["NOTIFY_SOCKET"], @sockaddr)
|
||||
|
|
|
@ -51,7 +51,7 @@ describe "Sidekiq::Testing.fake" do
|
|||
assert_in_delta 10.seconds.from_now.to_f, DirectWorker.jobs.last["at"], 0.1
|
||||
end
|
||||
|
||||
it 'stubs the enqueue call' do
|
||||
it "stubs the enqueue call" do
|
||||
assert_equal 0, EnqueuedWorker.jobs.size
|
||||
assert Sidekiq::Client.enqueue(EnqueuedWorker, 1, 2)
|
||||
assert_equal 1, EnqueuedWorker.jobs.size
|
||||
|
@ -212,6 +212,18 @@ describe "Sidekiq::Testing.fake" do
|
|||
assert_equal 1, SecondWorker.count
|
||||
end
|
||||
|
||||
it "clears the jobs of workers having their queue name defined as a symbol" do
|
||||
assert_equal Symbol, AltQueueWorker.sidekiq_options["queue"].class
|
||||
|
||||
AltQueueWorker.perform_async
|
||||
assert_equal 1, AltQueueWorker.jobs.size
|
||||
assert_equal 1, Sidekiq::Queues[AltQueueWorker.sidekiq_options["queue"].to_s].size
|
||||
|
||||
AltQueueWorker.clear
|
||||
assert_equal 0, AltQueueWorker.jobs.size
|
||||
assert_equal 0, Sidekiq::Queues[AltQueueWorker.sidekiq_options["queue"].to_s].size
|
||||
end
|
||||
|
||||
it "drains jobs across all workers even when workers create new jobs" do
|
||||
Sidekiq::Worker.jobs.clear
|
||||
FirstWorker.count = 0
|
||||
|
|
|
@ -39,7 +39,7 @@ describe "Sidekiq::Testing.inline" do
|
|||
end
|
||||
end
|
||||
|
||||
it 'stubs the enqueue call when in testing mode' do
|
||||
it "stubs the enqueue call when in testing mode" do
|
||||
assert Sidekiq::Client.enqueue(InlineWorker, true)
|
||||
|
||||
assert_raises InlineError do
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
require_relative "helper"
|
||||
require "sidekiq/util"
|
||||
|
||||
class TestUtil < Minitest::Test
|
||||
class Helpers
|
||||
include Sidekiq::Util
|
||||
end
|
||||
|
||||
def test_event_firing
|
||||
before_handlers = Sidekiq.options[:lifecycle_events][:startup]
|
||||
begin
|
||||
Sidekiq.options[:lifecycle_events][:startup] = [proc { raise "boom" }]
|
||||
h = Helpers.new
|
||||
h.fire_event(:startup)
|
||||
|
||||
Sidekiq.options[:lifecycle_events][:startup] = [proc { raise "boom" }]
|
||||
assert_raises RuntimeError do
|
||||
h.fire_event(:startup, reraise: true)
|
||||
end
|
||||
ensure
|
||||
Sidekiq.options[:lifecycle_events][:startup] = before_handlers
|
||||
end
|
||||
end
|
||||
end
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
require_relative "helper"
|
||||
require "sidekiq/web"
|
||||
require "sidekiq/util"
|
||||
require "rack/test"
|
||||
|
||||
describe Sidekiq::Web do
|
||||
|
@ -429,7 +428,7 @@ describe Sidekiq::Web do
|
|||
|
||||
it "escape job args and error messages" do
|
||||
# on /retries page
|
||||
params = add_xss_retry
|
||||
add_xss_retry
|
||||
get "/retries"
|
||||
assert_equal 200, last_response.status
|
||||
assert_match(/FailWorker/, last_response.body)
|
||||
|
@ -514,8 +513,6 @@ describe Sidekiq::Web do
|
|||
end
|
||||
|
||||
describe "stats" do
|
||||
include Sidekiq::Util
|
||||
|
||||
before do
|
||||
Sidekiq.redis do |conn|
|
||||
conn.set("stat:processed", 5)
|
||||
|
@ -569,8 +566,6 @@ describe Sidekiq::Web do
|
|||
end
|
||||
|
||||
describe "stats/queues" do
|
||||
include Sidekiq::Util
|
||||
|
||||
before do
|
||||
Sidekiq.redis do |conn|
|
||||
conn.set("stat:processed", 5)
|
||||
|
@ -710,6 +705,10 @@ describe Sidekiq::Web do
|
|||
[msg, score]
|
||||
end
|
||||
|
||||
def hostname
|
||||
ENV["DYNO"] || Socket.gethostname
|
||||
end
|
||||
|
||||
def add_worker
|
||||
key = "#{hostname}:#{$$}"
|
||||
msg = "{\"queue\":\"default\",\"payload\":{\"retry\":true,\"queue\":\"default\",\"timeout\":20,\"backtrace\":5,\"class\":\"HardWorker\",\"args\":[\"bob\",10,5],\"jid\":\"2b5ad2b016f5e063a1c62872\"},\"run_at\":1361208995}"
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
require_relative "helper"
|
||||
require "sidekiq/web"
|
||||
|
||||
class TestWebHelpers < Minitest::Test
|
||||
describe "Web helpers" do
|
||||
class Helpers
|
||||
include Sidekiq::WebHelpers
|
||||
|
||||
|
@ -33,7 +33,7 @@ class TestWebHelpers < Minitest::Test
|
|||
end
|
||||
end
|
||||
|
||||
def test_locale_determination
|
||||
it "tests locale determination" do
|
||||
obj = Helpers.new
|
||||
assert_equal "en", obj.locale
|
||||
|
||||
|
@ -89,7 +89,7 @@ class TestWebHelpers < Minitest::Test
|
|||
assert_equal "en", obj.locale
|
||||
end
|
||||
|
||||
def test_available_locales
|
||||
it "tests available locales" do
|
||||
obj = Helpers.new
|
||||
expected = %w[
|
||||
ar cs da de el en es fa fr he hi it ja
|
||||
|
@ -99,7 +99,7 @@ class TestWebHelpers < Minitest::Test
|
|||
assert_equal expected, obj.available_locales.sort
|
||||
end
|
||||
|
||||
def test_display_illegal_args
|
||||
it "tests displaying of illegal args" do
|
||||
o = Helpers.new
|
||||
s = o.display_args([1, 2, 3])
|
||||
assert_equal "1, 2, 3", s
|
||||
|
@ -111,12 +111,12 @@ class TestWebHelpers < Minitest::Test
|
|||
assert_equal "Invalid job payload, args is nil", s
|
||||
end
|
||||
|
||||
def test_to_query_string_escapes_bad_query_input
|
||||
it "query string escapes bad query input" do
|
||||
obj = Helpers.new
|
||||
assert_equal "page=B%3CH", obj.to_query_string("page" => "B<H")
|
||||
end
|
||||
|
||||
def test_qparams_string_escapes_bad_query_input
|
||||
it "qparams string escapes bad query input" do
|
||||
obj = Helpers.new
|
||||
obj.instance_eval do
|
||||
def params
|
||||
|
|
Loading…
Reference in New Issue