diff -Nru ruby-sidekiq-6.0.4+dfsg/3.0-Upgrade.md ruby-sidekiq-6.3.1+dfsg/3.0-Upgrade.md --- ruby-sidekiq-6.0.4+dfsg/3.0-Upgrade.md 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/3.0-Upgrade.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,70 +0,0 @@ -# Upgrading to Sidekiq 3.0 - -Sidekiq 3.0 brings several new features but also removes old APIs and -changes a few data elements in Redis. To upgrade cleanly: - -* Upgrade to the latest Sidekiq 2.x and run it for a few weeks. - `gem 'sidekiq', '< 3'` - This is only needed if you have retries pending. -* 3rd party gems which use **client-side middleware** will need to update - due to an API change. The Redis connection for a particular job is - passed thru the middleware to handle sharding where jobs can - be pushed to different redis server instances. - - `def call(worker_class, msg, queue, redis_pool)` - - Client-side middleware should use `redis_pool.with { |conn| ... }` to - perform Redis operations and **not** `Sidekiq.redis`. -* If you used the capistrano integration, you'll need to pull in the - new [capistrano-sidekiq](https://github.com/seuros/capistrano-sidekiq) - gem and use it in your deploy.rb. -* API changes: - - `Sidekiq::Client.registered_workers` replaced by `Sidekiq::Workers.new` - - `Sidekiq::Client.registered_queues` replaced by `Sidekiq::Queue.all` - - `Sidekiq::Worker#retries_exhausted` replaced by `Sidekiq::Worker.sidekiq_retries_exhausted` - - `Sidekiq::Workers#each` has changed significantly with a reworking - of Sidekiq's internal process/thread data model. -* `sidekiq/api` is no longer automatically required. If your code uses - the API, you will need to require it. -* Redis-to-Go is no longer transparently activated on Heroku so as to not play - favorites with any particular Redis service. You need to set a config option - for your app: - `heroku config:set REDIS_PROVIDER=REDISTOGO_URL`. You may also use - the generic `REDIS_URL`. See - [Advanced Options: Setting the Location of your Redis server][1] - for details. -* Anyone using Airbrake, Honeybadger, Exceptional or ExceptionNotifier - will need to update their error gem version to the latest to pull in - Sidekiq support. Sidekiq will not provide explicit support for these - services so as to not play favorites with any particular error service. -* MRI 1.9 is no longer officially supported. Sidekiq's official - support policy is to support the current and previous major releases - of MRI and Rails. As of February 2014, that's MRI 2.1, MRI 2.0, JRuby 1.7, Rails 4.0 - and Rails 3.2. I will consider PRs to fix issues found by users for - other platforms/versions. - -## Error Service Providers - -If you previously provided a middleware to capture job errors, you -should instead provide a global error handler with Sidekiq 3.0. This -ensures **any** error within Sidekiq will be logged appropriately, not -just during job execution. - -```ruby -if Sidekiq::VERSION < '3' - # old behavior - Sidekiq.configure_server do |config| - config.server_middleware do |chain| - chain.add MyErrorService::Middleware - end - end -else - Sidekiq.configure_server do |config| - config.error_handlers << proc {|ex,context| MyErrorService.notify(ex, context) } - end -end -``` - -Your error handler must respond to `call(exception, context_hash)`. - -[1]: https://github.com/mperham/sidekiq/wiki/Advanced-Options#via-env-variable diff -Nru ruby-sidekiq-6.0.4+dfsg/4.0-Upgrade.md ruby-sidekiq-6.3.1+dfsg/4.0-Upgrade.md --- ruby-sidekiq-6.0.4+dfsg/4.0-Upgrade.md 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/4.0-Upgrade.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,53 +0,0 @@ -# Welcome to Sidekiq 4.0! - -Sidekiq 4.0 contains a redesigned, more efficient core with less overhead per job. -See my blog for [an overview of Sidekiq 4's higher performance](http://www.mikeperham.com/2015/10/14/optimizing-sidekiq/). - -## What's New - -* Sidekiq no longer uses Celluloid. If your application code uses Celluloid, - you will need to pull it in yourself. - -* `redis-namespace` has been removed from Sidekiq's gem dependencies. If - you want to use namespacing ([and I strongly urge you not to](http://www.mikeperham.com/2015/09/24/storing-data-with-redis/)), you'll need to add the gem to your Gemfile: -```ruby -gem 'redis-namespace' -``` - -* **Redis 2.8.0 or greater is required.** Redis 2.8 was released two years - ago and contains **many** useful features which Sidekiq couldn't - leverage until now. **Redis 3.0.3 or greater is recommended** for large - scale use [#2431](https://github.com/mperham/sidekiq/issues/2431). - -* Jobs are now fetched from Redis in parallel, making Sidekiq more - resilient to high network latency. This means that Sidekiq requires - more Redis connections per process. You must have a minimum of - `concurrency + 2` connections in your pool or Sidekiq will exit. - When in doubt, let Sidekiq size the connection pool for you. - -* Worker data is no longer updated in real-time but rather upon every - heartbeat. Don't expect the `Sidekiq::Workers` API to be millisecond-precise. - -* There's a new testing API based off the `Sidekiq::Queues` namespace. All - assertions made against the Worker class still work as expected. -```ruby -assert_equal 0, Sidekiq::Queues["default"].size -HardWorker.perform_async("log") -assert_equal 1, Sidekiq::Queues["default"].size -assert_equal "log", Sidekiq::Queues["default"].first['args'][0] -Sidekiq::Queues.clear_all -``` - -## Upgrade - -First, make sure you are using Redis 2.8 or greater. Next: - -* Upgrade to the latest Sidekiq 3.x. -```ruby -gem 'sidekiq', '< 4' -``` -* Fix any deprecation warnings you see. -* Upgrade to 4.x. -```ruby -gem 'sidekiq', '< 5' -``` diff -Nru ruby-sidekiq-6.0.4+dfsg/5.0-Upgrade.md ruby-sidekiq-6.3.1+dfsg/5.0-Upgrade.md --- ruby-sidekiq-6.0.4+dfsg/5.0-Upgrade.md 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/5.0-Upgrade.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,56 +0,0 @@ -# Welcome to Sidekiq 5.0! - -Sidekiq 5.0 contains a reworked job dispatch and execution core to integrate -better with the new Rails 5.0 Executor. It also drops support for older -versions of Ruby and Rails and adds support for RTL languages in the Web UI. - -## What's New - -* Integrate job logging and retry logic directly in with the job - execution logic in Sidekiq::Processor. Previously this logic was - defined as middleware. In Rails 5.0, ActiveSupport::Executor handles ActiveRecord - connection management, job callbacks, development mode class loading, - etc. Because of its extensive responsibilities, the Executor can't be - integrated as Sidekiq middleware; the logging/retry logic had to be pulled out - too. Sidekiq 4.2 had a hack to make it work but this redesign provides - a cleaner integration. [#3235] -* The Delayed Extensions `delay`, `delay_in` and `delay_until` APIs are - no longer available by default. The extensions allow you to marshal - job arguments as YAML, leading to cases where job payloads could be many - 100s of KB or larger if not careful, leading to Redis networking - timeouts or other problems. As noted in the Best Practices wiki page, - Sidekiq is designed for jobs with small, simple arguments. - - Add this line to your initializer to re-enable them and get the old behavior: - ```ruby - Sidekiq::Extensions.enable_delay! - ``` - The old `Sidekiq.remove_delay!` API has been removed as it is now the default. [#3299] -* Sidekiq's quiet signal is now `TSTP` (think of it as **T**hread - **ST**o**P**) instead of USR1 as USR1 is not available on JRuby. - USR1 will continue to be supported in Sidekiq 5.x for backwards - compatibility and will be removed in Sidekiq 6.x. [#3302] -* The Web UI is now bi-directional - it can render either LTR - (left-to-right) or RTL languages. With this change, **Farsi, Arabic, - Hebrew and Urdu** are officially supported. [#3381] -* Jobs which can't be parsed due to invalid JSON are now pushed - immediately to the Dead set since they require manual intervention and - will never execute successfully as is. The Web UI has been updated to - more gracefully display these jobs. [#3296] -* **Rails 3.2** is no longer supported. -* **Ruby 2.0 and Ruby 2.1** are no longer supported. Ruby 2.2.2+ is required. - -## Upgrade - -As always, please upgrade Sidekiq **one major version at a time**. -If you are already running Sidekiq 4.x, then: - -* Upgrade to the latest Sidekiq 4.x. -```ruby -gem 'sidekiq', '< 5' -``` -* Fix any deprecation warnings you see. -* Upgrade to 5.x. -```ruby -gem 'sidekiq', '< 6' -``` diff -Nru ruby-sidekiq-6.0.4+dfsg/6.0-Upgrade.md ruby-sidekiq-6.3.1+dfsg/6.0-Upgrade.md --- ruby-sidekiq-6.0.4+dfsg/6.0-Upgrade.md 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/6.0-Upgrade.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,72 +0,0 @@ -# Welcome to Sidekiq 6.0! - -Sidekiq 6.0 contains some breaking changes which streamline proper operation -of Sidekiq. It also drops support for EOL versions of Ruby and Rails. - -## What's New - -This release has major breaking changes. Read and test carefully in production. - -- ActiveJobs can now use `sidekiq_options` directly to configure Sidekiq - features/internals like the retry subsystem. Prefer the native - Sidekiq::Worker APIs as some Sidekiq features (e.g. unique jobs) do not work well with AJ. - (requires Rails 6.0.2) -```ruby -class MyJob < ActiveJob::Base - queue_as :myqueue - sidekiq_options retry: 10, backtrace: 20 - def perform(...) - end -end -``` -- Logging has been redesigned to allow pluggable formatters and several - formats ship with Sidekiq: - * default - your typical output on macOS - * heroku - enabled specifically when running in Heroku - * json - a JSON format for search indexing, one hash per line - -Sidekiq will enable the best formatter for the detected environment but -you can override it by configuring the log formatter explicitly. See -'sidekiq/logger' for implementation details. - -```ruby -Sidekiq.configure_server do |config| - config.log_formatter = AcmeCorp::PlainLogFormatter.new - # config.log_formatter = Sidekiq::Logger::Formatters::JSON.new -end -``` -Please see the [Logging](https://github.com/mperham/sidekiq/wiki/Logging) wiki page for the latest documentation and notes. -- **Remove the daemonization, logfile and pidfile command line arguments and `sidekiqctl` binary**. -I've [noted for years](https://www.mikeperham.com/2014/09/22/dont-daemonize-your-daemons/) -how modern services should be managed with a proper init system. -Managing services manually is more error-prone, let your operating system do it for you. -systemd, upstart, and foreman are three options. See the Deployment wiki page for the latest details. -- **Validate proper usage of the `REDIS_PROVIDER` variable.** -This variable is meant to hold the name of the environment -variable which contains your Redis URL, so that you can switch Redis -providers quickly and easily with a single variable change. It is not -meant to hold the actual Redis URL itself. If you want to manually set -the Redis URL then you may set `REDIS_URL` directly. [#3969] -- **Increase default shutdown timeout from 8 seconds to 25 seconds.** -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. -* **Ruby <2.5** is no longer supported. -* **Redis <4** is no longer supported. - -## Upgrade - -As always, please upgrade Sidekiq **one major version at a time**. -If you are already running Sidekiq 5.x, then: - -* Upgrade to the latest Sidekiq 5.x. -```ruby -gem 'sidekiq', '< 6' -``` -* Fix any deprecation warnings you see. -* Upgrade to 6.x. -```ruby -gem 'sidekiq', '< 7' -``` diff -Nru ruby-sidekiq-6.0.4+dfsg/bin/sidekiq ruby-sidekiq-6.3.1+dfsg/bin/sidekiq --- ruby-sidekiq-6.0.4+dfsg/bin/sidekiq 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/bin/sidekiq 2021-11-18 13:57:25.000000000 +0000 @@ -6,13 +6,37 @@ require_relative '../lib/sidekiq/cli' +def integrate_with_systemd + return unless ENV["NOTIFY_SOCKET"] + + Sidekiq.configure_server do |config| + Sidekiq.logger.info "Enabling systemd notification integration" + require "sidekiq/sd_notify" + config.on(:startup) do + Sidekiq::SdNotify.ready + end + config.on(:shutdown) do + Sidekiq::SdNotify.stopping + end + Sidekiq.start_watchdog if Sidekiq::SdNotify.watchdog? + end +end + begin cli = Sidekiq::CLI.instance cli.parse + + integrate_with_systemd + cli.run rescue => e raise e if $DEBUG - STDERR.puts e.message - STDERR.puts e.backtrace.join("\n") + if Sidekiq.error_handlers.length == 0 + STDERR.puts e.message + STDERR.puts e.backtrace.join("\n") + else + cli.handle_exception e + end + exit 1 end diff -Nru ruby-sidekiq-6.0.4+dfsg/Changes.md ruby-sidekiq-6.3.1+dfsg/Changes.md --- ruby-sidekiq-6.0.4+dfsg/Changes.md 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/Changes.md 2021-11-18 13:57:25.000000000 +0000 @@ -1,6 +1,159 @@ # Sidekiq Changes -[Sidekiq Changes](https://github.com/mperham/sidekiq/blob/master/Changes.md) | [Sidekiq Pro Changes](https://github.com/mperham/sidekiq/blob/master/Pro-Changes.md) | [Sidekiq Enterprise Changes](https://github.com/mperham/sidekiq/blob/master/Ent-Changes.md) +[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) + +6.3.1 +--------- + +- Fix keyword arguments error with CurrentAttributes on Ruby 3.0 [#5048] + +6.3.0 +--------- + +- **BREAK**: The Web UI has been refactored to remove jQuery. Any UI extensions + which use jQuery will break. +- **FEATURE**: Sidekiq.logger has been enhanced so any `Rails.logger` + output in jobs now shows up in the Sidekiq console. Remove any logger + hacks in your initializer and see if it Just Works™ now. [#5021] +- **FEATURE**: Add `Sidekiq::Job` alias for `Sidekiq::Worker`, to better + reflect industry standard terminology. You can now do this: +```ruby +class MyJob + include Sidekiq::Job + sidekiq_options ... + def perform(args) + end +end +``` +- **FEATURE**: Support for serializing ActiveSupport::CurrentAttributes into each job. [#4982] +```ruby +# config/initializers/sidekiq.rb +require "sidekiq/middleware/current_attributes" +Sidekiq::CurrentAttributes.persist(Myapp::Current) # Your AS::CurrentAttributes singleton +``` +- **FEATURE**: Add `Sidekiq::Worker.perform_bulk` for enqueuing jobs in bulk, + similar to `Sidekiq::Client.push_bulk` [#5042] +```ruby +MyJob.perform_bulk([[1], [2], [3]]) +``` +- Implement `queue_as`, `wait` and `wait_until` for ActiveJob compatibility [#5003] +- Scheduler now uses Lua to reduce Redis load and network roundtrips [#5044] +- Retry Redis operation if we get an `UNBLOCKED` Redis error [#4985] +- Run existing signal traps, if any, before running Sidekiq's trap [#4991] +- Fix fetch bug when using weighted queues which caused Sidekiq to stop + processing queues randomly [#5031] + +6.2.2 +--------- + +- Reduce retry jitter, add jitter to `sidekiq_retry_in` values [#4957] +- Minimize scheduler load on Redis at scale [#4882] +- Improve logging of delay jobs [#4904, BuonOno] +- Minor CSS improvements for buttons and tables, design PRs always welcome! +- Tweak Web UI `Cache-Control` header [#4966] +- Rename internal API class `Sidekiq::Job` to `Sidekiq::JobRecord` [#4955] + +6.2.1 +--------- + +- Update RTT warning logic to handle transient RTT spikes [#4851] +- Fix very low priority CVE on unescaped queue name [#4852] +- Add note about sessions and Rails apps in API mode + +6.2.0 +--------- + +- Store Redis RTT and log if poor [#4824] +- Add process/thread stats to Busy page [#4806] +- Improve Web UI on mobile devices [#4840] +- **Refactor Web UI session usage** [#4804] + Numerous people have hit "Forbidden" errors and struggled with Sidekiq's + Web UI session requirement. If you have code in your initializer for + Web sessions, it's quite possible it will need to be removed. Here's + an overview: +``` +Sidekiq::Web needs a valid Rack session for CSRF protection. If this is a Rails app, +make sure you mount Sidekiq::Web *inside* your routes in `config/routes.rb` so +Sidekiq can reuse the Rails session: + + Rails.application.routes.draw do + mount Sidekiq::Web => "/sidekiq" + .... + end + +If this is a bare Rack app, use a session middleware before Sidekiq::Web: + + # first, use IRB to create a shared secret key for sessions and commit it + require 'securerandom'; File.open(".session.key", "w") {|f| f.write(SecureRandom.hex(32)) } + + # now, update your Rack app to include the secret with a session cookie middleware + use Rack::Session::Cookie, secret: File.read(".session.key"), same_site: true, max_age: 86400 + run Sidekiq::Web + +If this is a Rails app in API mode, you need to enable sessions. + + https://guides.rubyonrails.org/api_app.html#using-session-middlewares +``` + +6.1.3 +--------- + +- Warn if Redis is configured to evict data under memory pressure [#4752] +- Add process RSS on the Busy page [#4717] + +6.1.2 +--------- + +- Improve readability in dark mode Web UI [#4674] +- Fix Web UI crash with corrupt session [#4672] +- Allow middleware to yield arguments [#4673, @eugeneius] +- Migrate CI from CircleCI to GitHub Actions [#4677] + +6.1.1 +--------- + +- Jobs are now sorted by age in the Busy Workers table. [#4641] +- Fix "check all" JS logic in Web UI [#4619] + +6.1.0 +--------- + +- Web UI - Dark Mode fixes [#4543, natematykiewicz] +- Ensure `Rack::ContentLength` is loaded as middleware for correct Web UI responses [#4541] +- Avoid exception dumping SSL store in Redis connection logging [#4532] +- Better error messages in Sidekiq::Client [#4549] +- Remove rack-protection, reimplement CSRF protection [#4588] +- Require redis-rb 4.2 [#4591] +- Update to jquery 1.12.4 [#4593] +- Refactor internal fetch logic and API [#4602] + +6.0.7 +--------- + +- Refactor systemd integration to work better with custom binaries [#4511] +- Don't connect to Redis at process exit if not needed [#4502] +- Remove Redis connection naming [#4479] +- Fix Redis Sentinel password redaction [#4499] +- Add Vietnamese locale (vi) [#4528] + +6.0.6 +--------- + +- **Integrate with systemd's watchdog and notification features** [#4488] + Set `Type=notify` in [sidekiq.service](https://github.com/mperham/sidekiq/blob/4b8a8bd3ae42f6e48ae1fdaf95ed7d7af18ed8bb/examples/systemd/sidekiq.service#L30-L39). The integration works automatically. +- Use `setTimeout` rather than `setInterval` to avoid thundering herd [#4480] +- Fix edge case where a job can be pushed without a queue. +- Flush job stats at exit [#4498] +- Check RAILS_ENV before RACK_ENV [#4493] +- Add Lithuanian locale [#4476] + +6.0.5 +--------- + +- Fix broken Web UI response when using NewRelic and Rack 2.1.2+. [#4440] +- Update APIs to use `UNLINK`, not `DEL`. [#4449] +- Fix Ruby 2.7 warnings [#4412] +- Add support for `APP_ENV` [[95fa5d9]](https://github.com/mperham/sidekiq/commit/95fa5d90192148026e52ca2902f1b83c70858ce8) 6.0.4 --------- @@ -96,7 +249,7 @@ This release has major breaking changes. Read and test carefully in production. -- With Rails 6.0.1+, ActiveJobs can now use `sidekiq_options` directly to configure Sidekiq +- With Rails 6.0.2+, ActiveJobs can now use `sidekiq_options` directly to configure Sidekiq features/internals like the retry subsystem. [#4213, pirj] ```ruby class MyJob < ActiveJob::Base @@ -132,6 +285,18 @@ - Integrate the StandardRB code formatter to ensure consistent code styling. [#4114, gearnode] +5.2.9 +--------- + +- Release Rack lock due to a cascade of CVEs. [#4566] + Pro-tip: don't lock Rack. + +5.2.8 +--------- + +- Lock to Rack 2.0.x to prevent future incompatibilities +- Fix invalid reference in `sidekiqctl` + 5.2.7 --------- diff -Nru ruby-sidekiq-6.0.4+dfsg/.circleci/config.yml ruby-sidekiq-6.3.1+dfsg/.circleci/config.yml --- ruby-sidekiq-6.0.4+dfsg/.circleci/config.yml 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/.circleci/config.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,82 +0,0 @@ -version: 2 -references: - unit: &unit - run: - name: Run test suite - command: bundle exec rake - restore: &restore - restore_cache: - keys: - - v1-dependencies-{{ checksum "Gemfile.lock" }} - # fallback to using the latest cache if no exact match is found - - v1-dependencies- - bundle: &bundle - run: - name: install dependencies - command: | - bundle install --jobs=4 --retry=3 --path vendor/bundle - save: &save - save_cache: - paths: - - ./vendor/bundle - key: v1-dependencies-{{ checksum "Gemfile.lock" }} -jobs: - "ruby-2.5": - docker: - - image: circleci/ruby:2.5 - - image: circleci/redis:4.0 - steps: - - checkout - - <<: *restore - - <<: *bundle - - <<: *save - - <<: *unit - "ruby-2.6": - environment: - COVERAGE: true - CC_TEST_REPORTER_ID: 003c3033501d70a2653bd887ff9a8b2884a263e6a4e27f2ba68748e15530918d - docker: - - image: circleci/ruby:2.6 - - image: circleci/redis:4.0 - steps: - - checkout - - <<: *restore - - <<: *bundle - - <<: *save - - - run: - name: Setup Code Climate test-reporter - command: | - # download test reporter as a static binary - curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter - chmod +x ./cc-test-reporter - - - run: - name: Code Climate before-build - command: | - ./cc-test-reporter before-build - - - <<: *unit - - - run: - name: Report code coverage to Code Climate - command: | - ./cc-test-reporter after-build -t simplecov --exit-code $? - "jruby": - docker: - - image: circleci/jruby:latest - - image: circleci/redis:4.0 - steps: - - checkout - - <<: *restore - - <<: *bundle - - <<: *save - - <<: *unit - -workflows: - version: 2 - build: - jobs: - - "ruby-2.5" - - "ruby-2.6" - - "jruby" diff -Nru ruby-sidekiq-6.0.4+dfsg/code_of_conduct.md ruby-sidekiq-6.3.1+dfsg/code_of_conduct.md --- ruby-sidekiq-6.0.4+dfsg/code_of_conduct.md 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/code_of_conduct.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ -# Contributor Code of Conduct - -As contributors and maintainers of this project, and in the interest of -fostering an open and welcoming community, we pledge to respect all people who -contribute through reporting issues, posting feature requests, updating -documentation, submitting pull requests or patches, and other activities. - -We are committed to making participation in this project a harassment-free -experience for everyone, regardless of level of experience, gender, gender -identity and expression, sexual orientation, disability, personal appearance, -body size, race, ethnicity, age, religion, or nationality. - -Examples of unacceptable behavior by participants include: - -* The use of sexualized language or imagery -* Personal attacks -* Trolling or insulting/derogatory comments -* Public or private harassment -* Publishing other's private information, such as physical or electronic - addresses, without explicit permission -* Other unethical or unprofessional conduct - -Project maintainers have the right and responsibility to remove, edit, or -reject comments, commits, code, wiki edits, issues, and other contributions -that are not aligned to this Code of Conduct, or to ban temporarily or -permanently any contributor for other behaviors that they deem inappropriate, -threatening, offensive, or harmful. - -By adopting this Code of Conduct, project maintainers commit themselves to -fairly and consistently applying these principles to every aspect of managing -this project. Project maintainers who do not follow or enforce the Code of -Conduct may be permanently removed from the project team. - -This Code of Conduct applies both within project spaces and in public spaces -when an individual is representing the project or its community. - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project maintainer at mperham AT gmail.com. All -complaints will be reviewed and investigated and will result in a response that -is deemed necessary and appropriate to the circumstances. Maintainers are -obligated to maintain confidentiality with regard to the reporter of an -incident. - - -This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 1.3.0, available at -[http://contributor-covenant.org/version/1/3/0/][version] - -[homepage]: http://contributor-covenant.org -[version]: http://contributor-covenant.org/version/1/3/0/ diff -Nru ruby-sidekiq-6.0.4+dfsg/COMM-LICENSE ruby-sidekiq-6.3.1+dfsg/COMM-LICENSE --- ruby-sidekiq-6.0.4+dfsg/COMM-LICENSE 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/COMM-LICENSE 1970-01-01 00:00:00.000000000 +0000 @@ -1,97 +0,0 @@ -END-USER LICENSE AGREEMENT - ------------------------------------------------------------------------------- - -IMPORTANT: THIS SOFTWARE END-USER LICENSE AGREEMENT ("EULA") IS A LEGAL AGREEMENT (“Agreement”) BETWEEN YOU (THE CUSTOMER, EITHER AS AN INDIVIDUAL OR, IF PURCHASED OR OTHERWISE ACQUIRED BY OR FOR AN ENTITY, AS AN ENTITY) AND CONTRIBUTED SYSTEMS. READ IT CAREFULLY BEFORE COMPLETING THE INSTALLATION PROCESS AND USING SIDEKIQ PRO AND RELATED SOFTWARE COMPONENTS (“SOFTWARE”). IT PROVIDES A LICENSE TO USE THE SOFTWARE AND CONTAINS WARRANTY INFORMATION AND LIABILITY DISCLAIMERS. BY INSTALLING AND USING THE SOFTWARE, YOU ARE CONFIRMING YOUR ACCEPTANCE OF THE SOFTWARE AND AGREEING TO BECOME BOUND BY THE TERMS OF THIS AGREEMENT. - ------------------------------------------------------------------------------- - -In order to use the Software under this Agreement, you must receive a “Source URL” at the time of purchase, in accordance with the scope of use and other terms specified for each type of Software and as set forth in this Section 1 of this Agreement. - -1. License Grant - -1.1 General Use. This Agreement grants you a non-exclusive, non-transferable, limited license to the use rights for the Software, without the right to grant sublicenses, subject to the terms and conditions in this Agreement. The Software is licensed, not sold. - -1.2 Unlimited Organization License. If you purchased an Organization License (included with the Sidekiq Pro Software), you may install the Software on an unlimited number of Hosts. “Host” means any physical or virtual machine which is controlled by you. You may also run an unlimited number of Workers. “Worker” means a thread within a Sidekiq server process which executes jobs. You may concurrently run the software on an unlimited number of Hosts, with each host running an unlimited number of Workers. - -1.3 Limited Enterprise License. If you purchased a Limited License for the Sidekiq Enterprise Software, you may install the Software on an unlimited number of Hosts. “Host” means any physical or virtual machine which is controlled by you. The aggregate number of Workers run by the hosts must not exceed the maximum number of Workers authorized at the time of purchase. “Worker” means a thread within a Sidekiq server process which executes jobs. In order to run additional Workers, you must purchase an additional allowance from Contributed Systems. - -1.4 Enterprise Site License. If you purchased a Site License for the Sidekiq Enterprise Software, you may install the Software on an unlimited number of Hosts. “Host” means any physical or virtual machine which is controlled by you. You may also run an unlimited number of Workers. “Worker” means a thread within a Sidekiq server process which executes jobs. You may concurrently run the software on an unlimited number of Hosts, with each host running an unlimited number of Workers. - -1.5 Appliance License. If you purchased an Appliance License, you may distribute the Software in any applications, frameworks, or elements (collectively referred to as an “Application” or “Applications”) that you develop using the Software in accordance with this EULA, provided that such distribution does not violate the restrictions set forth in section 3 of this EULA. You must not remove, obscure or interfere with any copyright, acknowledgment, attribution, trademark, warning or disclaimer statement affixed to, incorporated in or otherwise applied in connection with the Software. You are required to ensure that the Software is not reused by or with any applications other than those with which you distribute it as permitted herein. For example, if You install the Software on a customer's server, that customer is not permitted to use the Software independently of your Application. You must inform Contributed Systems of your knowledge of any infringing use of the Software by any of your customers. You are liable for compliance by those third parties with the terms and conditions of this EULA. You will not owe Contributed Systems any royalties for your distribution of the Software in accordance with this EULA. - -1.6 Archive Copies. You are entitled to make a reasonable amount of copies of the Software for archival purposes. Each copy must reproduce all copyright and other proprietary rights notices on or in the Software Product. - -1.7 Electronic Delivery. All Software and license documentation shall be delivered by electronic means unless otherwise specified on the applicable invoice or at the time of purchase. Software shall be deemed delivered when it is made available for download by you (“Delivery”). - -2. Modifications. Contributed Systems shall provide you with source code so that you can create Modifications of the original software. “Modification” means: (a) any addition to or deletion from the contents of a file included in the original Software or previous Modifications created by You, or (b) any new file that contains any part of the original Software or previous Modifications. While you retain all rights to any original work authored by you as part of the Modifications, We continue to own all copyright and other intellectual property rights in the Software. - -3. Restricted Uses. - -3.1 You shall not (and shall not allow any third party to): (a) decompile, disassemble, or otherwise reverse engineer the Software or attempt to reconstruct or discover any source code, underlying ideas, algorithms, file formats or programming interfaces of the Software by any means whatsoever (except and only to the extent that applicable law prohibits or restricts reverse engineering restrictions); (b) distribute, sell, sublicense, rent, lease or use the Software for time sharing, hosting, service provider or like purposes, except as expressly permitted under this Agreement; (c) redistribute the Software or Modifications other than by including the Software or a portion thereof within your own product, which must have substantially different functionality than the Software or Modifications and must not allow any third party to use the Software or Modifications, or any portions thereof, for software development or application development purposes; (d) redistribute the Software as part of a product, "appliance" or "virtual server"; (e) redistribute the Software on any server which is not directly under your control; (f) remove any product identification, proprietary, copyright or other notices contained in the Software; (g) modify any part of the Software, create a derivative work of any part of the Software (except as permitted in Section 4), or incorporate the Software, except to the extent expressly authorized in writing by Contributed Systems; (h) publicly disseminate performance information or analysis (including, without limitation, benchmarks) from any source relating to the Software; (i) utilize any equipment, device, software, or other means designed to circumvent or remove any form of Source URL or copy protection used by Contributed Systems in connection with the Software, or use the Software together with any authorization code, Source URL, serial number, or other copy protection device not supplied by Contributed Systems; (j) use the Software to develop a product which is competitive with any Contributed Systems product offerings; or (k) use unauthorized Source URLS or keycode(s) or distribute or publish Source URLs or keycode(s), except as may be expressly permitted by Contributed Systems in writing. If your unique Source URL is ever published, Contributed Systems reserves the right to terminate your access without notice. - -3.2 UNDER NO CIRCUMSTANCES MAY YOU USE THE SOFTWARE AS PART OF A PRODUCT OR SERVICE THAT PROVIDES SIMILAR FUNCTIONALITY TO THE SOFTWARE ITSELF. - -The Open Source version of the Software (“LGPL Version”) is licensed -under the terms of the GNU Lesser General Public License version 3.0 -(“LGPL”) and not under this EULA. - -4. Ownership. Notwithstanding anything to the contrary contained herein, except for the limited license rights expressly provided herein, Contributed Systems and its suppliers have and will retain all rights, title and interest (including, without limitation, all patent, copyright, trademark, trade secret and other intellectual property rights) in and to the Software and all copies, modifications and derivative works thereof (including any changes which incorporate any of your ideas, feedback or suggestions). You acknowledge that you are obtaining only a limited license right to the Software, and that irrespective of any use of the words “purchase”, “sale” or like terms hereunder no ownership rights are being conveyed to you under this Agreement or otherwise. - -5. Fees and Payment. The Software license fees will be due and payable in full as set forth in the applicable invoice or at the time of purchase. If the Software does not function properly within two weeks of purchase, please contact us within those two weeks for a refund. You shall be responsible for all taxes, withholdings, duties and levies arising from the order (excluding taxes based on the net income of Contributed Systems). - -6. Support, Maintenance and Services. Subject to the terms and conditions of this Agreement, as set forth in your invoice, and as set forth on the Sidekiq Pro support page (https://github.com/mperham/sidekiq/wiki/Commercial-Support), support and maintenance services may be included with the purchase of your license subscription. - -7. Term of Agreement. - -7.1 Term. This Agreement is effective as of the Delivery of the Software and expires at such time as all license and service subscriptions hereunder have expired in accordance with their own terms (the “Term”). For clarification, the term of your license under this Agreement may be perpetual, limited for Evaluation Version, or designated as a fixed-term license in the Invoice, and shall be specified at your time of purchase. Either party may terminate this Agreement (including all related Invoices) if the other party: (a) fails to cure any material breach of this Agreement within thirty (30) days after written notice of such breach, provided that Contributed Systems may terminate this Agreement immediately upon any breach of Section 3 or if you exceed any other restrictions contained in Section 1, unless otherwise specified in this agreement; (b) ceases operation without a successor; or (c) seeks protection under any bankruptcy, receivership, trust deed, creditors arrangement, composition or comparable proceeding, or if any such proceeding is instituted against such party (and not dismissed within sixty (60) days)). Termination is not an exclusive remedy and the exercise by either party of any remedy under this Agreement will be without prejudice to any other remedies it may have under this Agreement, by law, or otherwise. - -7.2 Termination. Upon any termination of this Agreement, you shall cease any and all use of any Software and destroy all copies thereof. - -7.3 Expiration of License. Upon the expiration of any term under this Agreement, (a) all Software updates and services pursuant to the license shall cease, (b) you may only continue to run existing installations of the Software, (c) you may not install the Software on any additional Hosts, and (d) any new installation of the Software shall require the purchase of a new license subscription from Contributed Systems. - -8. Disclaimer of Warranties. The Software is provided "as is," with all faults, defects and errors, and without warranty of any kind. Contributed Systems does not warrant that the Software will be free of bugs, errors, viruses or other defects, and Contributed Systems shall have no liability of any kind for the use of or inability to use the Software, the Software content or any associated service, and you acknowledge that it is not technically practicable for Contributed Systems to do so. -To the maximum extent permitted by applicable law, Contributed Systems disclaims all warranties, express, implied, arising by law or otherwise, regarding the Software, the Software content and their respective performance or suitability for your intended use, including without limitation any implied warranty of merchantability, fitness for a particular purpose. - -9. Limitation of Liability. - -In no event will Contributed Systems be liable for any direct, indirect, consequential, incidental, special, exemplary, or punitive damages or liabilities whatsoever arising from or relating to the Software, the Software content or this Agreement, whether based on contract, tort (including negligence), strict liability or other theory, even if Contributed Systems has been advised of the possibility of such damages. - -In no event will Contributed Systems' liability exceed the Software license price as indicated in the invoice. The existence of more than one claim will not enlarge or extend this limit. - -10. Remedies. Your exclusive remedy and Contributed Systems' entire liability for breach of this Agreement shall be limited, at Contributed Systems' sole and exclusive discretion, to (a) replacement of any defective software or documentation; or (b) refund of the license fee paid to Contributed Systems, payable in accordance with Contributed Systems' refund policy. - -11. Acknowledgements. - -11.1 Consent to the Use of Data. You agree that Contributed Systems and its affiliates may collect and use technical information gathered as part of the product support services. Contributed Systems may use this information solely to improve products and services and will not disclose this information in a form that personally identifies you. - -11.2 Verification. We or a certified auditor acting on our behalf, may, upon its reasonable request and at its expense, audit you with respect to the use of the Software. Such audit may be conducted by mail, electronic means or through an in-person visit to your place of business. Any such in-person audit shall be conducted during regular business hours at your facilities and shall not unreasonably interfere with your business activities. We shall not remove, copy, or redistribute any electronic material during the course of an audit. If an audit reveals that you are using the Software in a way that is in material violation of the terms of the EULA, then you shall pay our reasonable costs of conducting the audit. In the case of a material violation, you agree to pay Us any amounts owing that are attributable to the unauthorized use. In the alternative, We reserve the right, at our sole option, to terminate the licenses for the Software. - -11.3 Government End Users. If the Software and related documentation are supplied to or purchased by or on behalf of the United States Government, then the Software is deemed to be "commercial software" as that term is used in the Federal Acquisition Regulation system. Rights of the United States shall not exceed the minimum rights set forth in FAR 52.227-19 for "restricted computer software". All other terms and conditions of this Agreement apply. - -12. Third Party Software. Examples included in Software may provide links to third party libraries or code (collectively “Third Party Software”) to implement various functions. Third Party Software does not comprise part of the Software. In some cases, access to Third Party Software may be included along with the Software delivery as a convenience for demonstration purposes. Such source code and libraries may be included in the “…/examples” source tree delivered with the Software and do not comprise the Software. Licensee acknowledges (1) that some part of Third Party Software may require additional licensing of copyright and patents from the owners of such, and (2) that distribution of any of the Software referencing or including any portion of a Third Party Software may require appropriate licensing from such third parties. - - -13. Miscellaneous - -13.1 Entire Agreement. This Agreement sets forth our entire agreement with respect to the Software and the subject matter hereof and supersedes all prior and contemporaneous understandings and agreements whether written or oral. - -13.2 Amendment. Contributed Systems reserves the right, in its sole discretion, to amend this Agreement from time. Amendments to this Agreement can be located at: https://github.com/mperham/sidekiq/blob/master/COMM-LICENSE. - -13.3 Assignment. You may not assign this Agreement or any of its rights under this Agreement without the prior written consent of Contributed Systems and any attempted assignment without such consent shall be void. - -13.4 Export Compliance. You agree to comply with all applicable laws and regulations, including laws, regulations, orders or other restrictions on export, re-export or redistribution of software. - -13.5 Indemnification. You agree to defend, indemnify, and hold harmless Contributed Systems from and against any lawsuits, claims, losses, damages, fines and expenses (including attorneys' fees and costs) arising out of your use of the Software or breach of this Agreement. - -13.6 Governing Law. This Agreement is governed by the laws of the State of Oregon and the United States without regard to conflicts of laws provisions thereof, and without regard to the United Nations Convention on the International Sale of Goods or the Uniform Computer Information Transactions Act, as currently enacted by any jurisdiction or as may be codified or amended from time to time by any jurisdiction. The jurisdiction and venue for actions related to the subject matter hereof shall be the state of Oregon and United States federal courts located in Portland, Oregon, and both parties hereby submit to the personal jurisdiction of such courts. - -13.7 Attorneys' Fees and Costs. The prevailing party in any action to enforce this Agreement will be entitled to recover its attorneys' fees and costs in connection with such action. - -13.8 Severability. If any provision of this Agreement is held by a court of competent jurisdiction to be invalid, illegal, or unenforceable, the remainder of this Agreement will remain in full force and effect. - -13.9 Waiver. Failure or neglect by either party to enforce at any time any of the provisions of this licence Agreement shall not be construed or deemed to be a waiver of that party's rights under this Agreement. - -13.10 Headings. The headings of sections and paragraphs of this Agreement are for convenience of reference only and are not intended to restrict, affect or be of any weight in the interpretation or construction of the provisions of such sections or paragraphs. - -14. Contact Information. If you have any questions about this EULA, or if you want to contact Contributed Systems for any reason, please direct correspondence to info@contribsys.com. diff -Nru ruby-sidekiq-6.0.4+dfsg/debian/changelog ruby-sidekiq-6.3.1+dfsg/debian/changelog --- ruby-sidekiq-6.0.4+dfsg/debian/changelog 2020-08-02 18:51:33.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/debian/changelog 2021-11-18 13:58:10.000000000 +0000 @@ -1,3 +1,31 @@ +ruby-sidekiq (6.3.1+dfsg-1) unstable; urgency=medium + + [ Debian Janitor ] + * Trim trailing whitespace. + * Use secure copyright file specification URI. + * Remove constraints unnecessary since buster + + [ Pirate Praveen ] + * New upstream version 6.3.1+dfsg + * Bump Standards-Version to 4.6.0 (no changes needed) + * Switch to ${ruby:Depends} instead of ruby | ruby-interpreter + + -- Pirate Praveen Thu, 18 Nov 2021 19:28:10 +0530 + +ruby-sidekiq (6.2.1+dfsg-1) experimental; urgency=medium + + [ Cédric Boutillier ] + * Update team name + * Add .gitattributes to keep unwanted files out of the source package + + [ Pirate Praveen ] + * New upstream version 6.2.1+dfsg + * Bump Standards-Version to 4.5.1 (no changes needed) + * Bump debhelper compatibility level to 13 + * Refresh patches + + -- Pirate Praveen Thu, 17 Jun 2021 19:34:44 +0530 + ruby-sidekiq (6.0.4+dfsg-2) unstable; urgency=medium * Reupload to unstable @@ -31,7 +59,7 @@ ruby-sidekiq (5.2.3+dfsg-1) unstable; urgency=medium * Team upload - * New upstream release 5.2.3+dfsg + * New upstream release 5.2.3+dfsg -- Manas Kashyap Thu, 13 Dec 2018 15:12:19 +0000 @@ -62,7 +90,7 @@ * Team upload * New upstream release - * Bump standards version to 4.1.4 (no changes) + * Bump standards version to 4.1.4 (no changes) -- Manas kashyap Sun, 13 May 2018 15:17:43 +0000 @@ -83,7 +111,7 @@ ruby-sidekiq (4.2.3+dfsg-2) unstable; urgency=medium - * Add ruby-rack-protection as dependency + * Add ruby-rack-protection as dependency -- Pirate Praveen Sun, 29 Jan 2017 02:02:52 +0530 @@ -105,7 +133,7 @@ ruby-sidekiq (4.0.1+dfsg-2) unstable; urgency=medium - * Reupload to unstable + * Reupload to unstable -- Pirate Praveen Wed, 27 Jan 2016 21:36:07 +0530 diff -Nru ruby-sidekiq-6.0.4+dfsg/debian/control ruby-sidekiq-6.3.1+dfsg/debian/control --- ruby-sidekiq-6.0.4+dfsg/debian/control 2020-08-02 18:50:56.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/debian/control 2021-11-18 13:58:10.000000000 +0000 @@ -1,9 +1,9 @@ Source: ruby-sidekiq Section: ruby Priority: optional -Maintainer: Debian Ruby Extras Maintainers +Maintainer: Debian Ruby Team Uploaders: Pirate Praveen -Build-Depends: debhelper-compat (= 12), +Build-Depends: debhelper-compat (= 13), gem2deb, libjs-d3, libjs-jquery, @@ -14,19 +14,19 @@ redis-server, ruby-actionmailer (>= 2:6.0.2), ruby-activerecord (>= 2:6.0.2), - ruby-celluloid (>= 0.16.0), + ruby-celluloid, ruby-concurrent, ruby-connection-pool (<< 3.0), - ruby-connection-pool (>= 2.2.2~), + ruby-connection-pool, ruby-coveralls, ruby-railties (>= 2:6.0.2), - ruby-redis (>= 4.1~), + ruby-redis, ruby-redis-namespace (<< 2.0), - ruby-redis-namespace (>= 1.5.2), + ruby-redis-namespace, ruby-rack-protection (>= 1.5.0), ruby-sinatra, - ruby-tilt (>= 2.0.1) -Standards-Version: 4.5.0 + ruby-tilt +Standards-Version: 4.6.0 Vcs-Git: https://salsa.debian.org/ruby-team/ruby-sidekiq.git Vcs-Browser: https://salsa.debian.org/ruby-team/ruby-sidekiq Homepage: http://sidekiq.org @@ -37,16 +37,7 @@ Architecture: all XB-Ruby-Versions: ${ruby:Versions} Depends: libjs-bootstrap, - ruby | ruby-interpreter, - ruby-celluloid (>= 0.16.0), - ruby-concurrent, - ruby-connection-pool (<< 3.0), - ruby-connection-pool (>= 2.2.2~), - ruby-json, - ruby-redis (>= 3.3.5~), - ruby-redis-namespace (<< 2.0), - ruby-redis-namespace (>= 1.5.2), - ruby-rack-protection (>= 1.5.0), + ${ruby:Depends}, ${misc:Depends}, ${shlibs:Depends} Description: Simple, efficient background processing for Ruby diff -Nru ruby-sidekiq-6.0.4+dfsg/debian/copyright ruby-sidekiq-6.3.1+dfsg/debian/copyright --- ruby-sidekiq-6.0.4+dfsg/debian/copyright 2020-08-02 18:50:56.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/debian/copyright 2021-11-18 13:58:10.000000000 +0000 @@ -1,4 +1,4 @@ -Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ Upstream-Name: sidekiq Source: http://sidekiq.org/ Files-Excluded: diff -Nru ruby-sidekiq-6.0.4+dfsg/debian/patches/remove-git-in-gemspec.patch ruby-sidekiq-6.3.1+dfsg/debian/patches/remove-git-in-gemspec.patch --- ruby-sidekiq-6.0.4+dfsg/debian/patches/remove-git-in-gemspec.patch 2020-08-02 18:50:56.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/debian/patches/remove-git-in-gemspec.patch 2021-11-18 13:58:10.000000000 +0000 @@ -6,8 +6,8 @@ gem.license = "LGPL-3.0" gem.executables = ["sidekiq", "sidekiqmon"] -- gem.files = `git ls-files | grep -Ev '^(test|myapp|examples)'`.split("\n") -+ gem.files = Dir.glob("**/*").select {|v| v !~ /^(test|myapp|examples|debian)/} +- gem.files = ["sidekiq.gemspec", "README.md", "Changes.md", "LICENSE"] + `git ls-files | grep -E '^(bin|lib|web)'`.split("\n") ++ gem.files = ["sidekiq.gemspec", "README.md", "Changes.md", "LICENSE"] + Dir.glob("**/*").select {|v| v !~ /^(debian)/} gem.name = "sidekiq" gem.version = Sidekiq::VERSION gem.required_ruby_version = ">= 2.5.0" diff -Nru ruby-sidekiq-6.0.4+dfsg/debian/patches/require-standard-cli.patch ruby-sidekiq-6.3.1+dfsg/debian/patches/require-standard-cli.patch --- ruby-sidekiq-6.0.4+dfsg/debian/patches/require-standard-cli.patch 2020-08-02 18:50:56.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/debian/patches/require-standard-cli.patch 2021-11-18 13:58:10.000000000 +0000 @@ -12,5 +12,5 @@ -require_relative '../lib/sidekiq/cli' +require 'sidekiq/cli' - begin - cli = Sidekiq::CLI.instance + def integrate_with_systemd + return unless ENV["NOTIFY_SOCKET"] diff -Nru ruby-sidekiq-6.0.4+dfsg/debian/salsa-ci.yml ruby-sidekiq-6.3.1+dfsg/debian/salsa-ci.yml --- ruby-sidekiq-6.0.4+dfsg/debian/salsa-ci.yml 2020-08-02 18:50:56.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/debian/salsa-ci.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,4 +0,0 @@ ---- -include: - - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/salsa-ci.yml - - https://salsa.debian.org/salsa-ci-team/pipeline/raw/master/pipeline-jobs.yml diff -Nru ruby-sidekiq-6.0.4+dfsg/Ent-2.0-Upgrade.md ruby-sidekiq-6.3.1+dfsg/Ent-2.0-Upgrade.md --- ruby-sidekiq-6.0.4+dfsg/Ent-2.0-Upgrade.md 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/Ent-2.0-Upgrade.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,37 +0,0 @@ -# Welcome to Sidekiq Enterprise 2.0! - -Sidekiq Enterprise 2.0 adds a few new features and adds the requirement that license -credentials be available at runtime. Note that Sidekiq 6.0 does have major breaking changes. - -## What's New - -* Sidekiq Enterprise now requires license credentials at runtime. If you - configured Bundler as described in the access email you need do -nothing, everything should just work. If you are vendoring Sidekiq -Enterprise you will need to configure Bundler also or set -`SIDEKIQ_ENT_USERNAME=abcdef12 bundle exec sidekiq...` when starting the -process. [#4232] -* Dead jobs now release any unique locks they were holding when they died [#4162] -* Backoff can now be customized per rate limiter by passing in a Proc [#4219] -```ruby -limiter = Sidekiq::Limiter.bucket(:stripe, 10, :second, backoff: ->(limiter, job) { - return job['overrated'] || 5 # wait for N seconds, where N is the number of - # times we've failed the rate limit -}) -``` -* Removed deprecated APIs and warnings. -* Various changes for Sidekiq 6.0 -* Requires Ruby 2.5+ and Redis 4.0+ -* Requires Sidekiq 6.0+ and Sidekiq Pro 5.0+ - -## Upgrade - -* Upgrade to the latest Sidekiq Enterprise 1.x. -```ruby -gem 'sidekiq-ent', '< 2' -``` -* Fix any deprecation warnings you see. -* Upgrade to 2.x. -```ruby -gem 'sidekiq-ent', '< 3' -``` diff -Nru ruby-sidekiq-6.0.4+dfsg/Ent-Changes.md ruby-sidekiq-6.3.1+dfsg/Ent-Changes.md --- ruby-sidekiq-6.0.4+dfsg/Ent-Changes.md 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/Ent-Changes.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,256 +0,0 @@ -# Sidekiq Enterprise Changelog - -[Sidekiq Changes](https://github.com/mperham/sidekiq/blob/master/Changes.md) | [Sidekiq Pro Changes](https://github.com/mperham/sidekiq/blob/master/Pro-Changes.md) | [Sidekiq Enterprise Changes](https://github.com/mperham/sidekiq/blob/master/Ent-Changes.md) - -Please see [http://sidekiq.org/](http://sidekiq.org/) for more details and how to buy. - -2.0.1 -------------- - -- Periodic job registration API adjusted to avoid loading classes in initializer [#4271] -- Remove support for deprecated ENV variables (COUNT, MAXMEM\_MB, INDEX) in swarm code - -2.0.0 -------------- - -- Except for the [newly required credentials](https://github.com/mperham/sidekiq/issues/4232), Sidekiq Enterprise 2.0 does - not have any significant migration steps. -- Sidekiq Enterprise must now be started with valid license credentials. [#4232] -- Call `GC.compact` if possible in sidekiqswarm before forking [#4181] -- Changes for forward-compatibility with Sidekiq 6.0. -- Add death handler to remove any lingering unique locks [#4162] -- Backoff can now be customized per rate limiter [#4219] -- Code formatting changes for StandardRB - -1.8.1 -------------- - -- Fix excessive lock reclaims with concurrent limiter [#4105] -- Add ES translations, see issues [#3949](https://github.com/mperham/sidekiq/issues/3949) and [#3951](https://github.com/mperham/sidekiq/issues/3951) to add your own language. - -1.8.0 -------------- - -- Require Sidekiq Pro 4.0 and Sidekiq 5.2. -- Refactor historical metrics API to use revamped Statsd support in Sidekiq Pro -- Add a gauge to historical metrics for `default` queue latency [#4079] - -1.7.2 -------------- - -- Add PT and JA translations -- Fix elapsed time calculations to use monotonic clock [#4000, sj26] -- Fix edge case where flapping leadership would cause old periodic - jobs to be fired once [#3974] -- Add support for sidekiqswarm memory monitoring on FreeBSD [#3884] - -1.7.1 -------------- - -- Fix Lua error in concurrent rate limiter under heavy contention -- Remove superfluous `freeze` calls on Strings [#3759] - -1.7.0 -------------- - -- **NEW FEATURE** [Rolling restarts](https://github.com/mperham/sidekiq/wiki/Ent-Rolling-Restarts) - great for long running jobs! -- Adjust middleware so unique jobs that don't push aren't registered in a Batch [#3662] -- Add new unlimited rate limiter, useful for testing [#3743] -```ruby -limiter = Sidekiq::Limiter.unlimited(...any args...) -``` - -1.6.1 -------------- - -- Fix crash in rate limiter middleware when used with custom exceptions [#3604] - -1.6.0 -------------- - -- Show process "leader" tag on Busy page, requires Sidekiq 5.0.2 [#2867] -- Capture custom metrics with the `save_history` API. [#2815] -- Implement new `unique_until: 'start'` policy option. [#3471] - -1.5.4 -------------- - -- Fix broken Cron page in Web UI [#3458] - -1.5.3 -------------- - -- Remove dependency on the algorithms gem [#3446] -- Allow user to specify max memory in megabytes with SIDEKIQ\_MAXMEM\_MB [#3451] -- Implement logic to detect app startup failure, sidekiqswarm will exit - rather than try to restart the app forever [#3450] -- Another fix for doubly-encrypted arguments [#3368] - -1.5.2 -------------- - -- Fix encrypted arguments double-encrypted by retry or rate limiting [#3368] -- Fix leak in concurrent rate limiter, run this in Rails console to clean up existing data [#3323] -```ruby -expiry = 1.month.to_i; Sidekiq::Limiter.redis { |c| c.scan_each(match: "lmtr-cfree-*") { |key| c.expire(key, expiry) } } -``` - -1.5.1 -------------- - -- Fix issue with census startup when not using Bundler configuration for - source credentials. - -1.5.0 -------------- - -- Add new web authorization API [#3251] -- Update all sidekiqswarm env vars to use SIDEKIQ\_ prefix [#3218] -- Add census reporting, the leader will ping contribsys nightly with aggregate usage metrics - -1.4.0 -------------- - -- No functional changes, require latest Sidekiq and Sidekiq Pro versions - -1.3.2 -------------- - -- Upgrade encryption to use OpenSSL's more secure GCM mode. [#3060] - -1.3.1 -------------- - -- Fix multi-process memory monitoring on CentOS 6.x [#3063] -- Polish the new encryption feature a bit. - -1.3.0 -------------- - -- **BETA** [New encryption feature](https://github.com/mperham/sidekiq/wiki/Ent-Encryption) - which automatically encrypts the last argument of a Worker, aka the secret bag. - -1.2.4 -------------- - -- Fix issue causing some minutely jobs to execute every other minute. -- Log a warning if slow periodic processing causes us to miss a clock tick. - -1.2.3 -------------- - -- Periodic jobs could stop executing until process restart if Redis goes down [#3047] - -1.2.2 -------------- - -- Add API to check if a unique lock is present. See [#2932] for details. -- Tune concurrent limiters to minimize thread thrashing under heavy contention. [#2944] -- Add option for tuning which Bundler groups get preloaded with `sidekiqswarm` [#3025] -``` -SIDEKIQ_PRELOAD=default,production bin/sidekiqswarm ... -# Use an empty value for maximum application compatibility -SIDEKIQ_PRELOAD= bin/sidekiqswarm ... -``` - -1.2.1 -------------- - -- Multi-Process mode can now monitor the RSS memory of children and - restart any that grow too large. To limit children to 1GB each: -``` -MAXMEM_KB=1048576 COUNT=2 bundle exec sidekiqswarm ... -``` - -1.2.0 -------------- - -- **NEW FEATURE** Multi-process mode! Sidekiq Enterprise can now fork multiple worker - processes, enabling significant memory savings. See the [wiki -documentation](https://github.com/mperham/sidekiq/wiki/Ent-Multi-Process) for details. - - -0.7.10 -------------- - -- More precise gemspec dependency versioning - -1.1.0 -------------- - -- **NEW FEATURE** Historical queue metrics, [documented in the wiki](https://github.com/mperham/sidekiq/wiki/Ent-Historical-Metrics) [#2719] - -0.7.9, 1.0.2 -------------- - -- Window limiters can now accept arbitrary window sizes [#2686] -- Fix race condition in window limiters leading to non-stop OverLimit [#2704] -- Fix invalid overage counts when nesting concurrent limiters - -1.0.1 ----------- - -- Fix crash in periodic subsystem when a follower shuts down, thanks - to @justinko for reporting. - -1.0.0 ----------- - -- Enterprise 1.x targets Sidekiq 4.x. -- Rewrite several features to remove Celluloid dependency. No - functional changes. - -0.7.8 ----------- - -- Fix `unique_for: false` [#2658] - - -0.7.7 ----------- - -- Enterprise 0.x targets Sidekiq 3.x. -- Fix racy shutdown event which could lead to disappearing periodic - jobs, requires Sidekiq >= 3.5.3. -- Add new :leader event which is fired when a process gains leadership. - -0.7.6 ----------- - -- Redesign how overrated jobs are rescheduled to avoid creating new - jobs. [#2619] - -0.7.5 ----------- - -- Fix dynamic creation of concurrent limiters [#2617] - -0.7.4 ----------- -- Add additional check to prevent duplicate periodic job creation -- Allow user-specified TTLs for rate limiters [#2607] -- Paginate rate limiter index page [#2606] - -0.7.3 ----------- - -- Rework `Sidekiq::Limiter` redis handling to match global redis handling. -- Allow user to customize rate limit backoff logic and handle custom - rate limit errors. -- Fix scalability issue with Limiter index page. - -0.7.2 ----------- - -- Fix typo which prevented limiters with '0' in their names. - -0.7.1 ----------- - -- Fix issue where unique scheduled jobs can't be enqueued upon schedule - due to the existing unique lock. [#2499] - -0.7.0 ----------- - -Initial release. diff -Nru ruby-sidekiq-6.0.4+dfsg/Gemfile ruby-sidekiq-6.3.1+dfsg/Gemfile --- ruby-sidekiq-6.0.4+dfsg/Gemfile 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/Gemfile 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -source "https://rubygems.org" - -gemspec - -gem "rake" -gem "redis-namespace" -gem "rails", ">= 6.0.2" -gem "sqlite3", platforms: :ruby -gem "activerecord-jdbcsqlite3-adapter", platforms: :jruby - -group :test do - gem "minitest" - gem "simplecov" -end - -group :development, :test do - gem "pry-byebug", platforms: :mri - gem "standard" -end - -group :load_test do - gem "hiredis" - gem "toxiproxy" -end diff -Nru ruby-sidekiq-6.0.4+dfsg/Gemfile.lock ruby-sidekiq-6.3.1+dfsg/Gemfile.lock --- ruby-sidekiq-6.0.4+dfsg/Gemfile.lock 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/Gemfile.lock 1970-01-01 00:00:00.000000000 +0000 @@ -1,199 +0,0 @@ -PATH - remote: . - specs: - sidekiq (6.0.4) - connection_pool (>= 2.2.2) - rack (>= 2.0.0) - rack-protection (>= 2.0.0) - redis (>= 4.1.0) - -GEM - remote: https://rubygems.org/ - specs: - actioncable (6.0.2) - actionpack (= 6.0.2) - nio4r (~> 2.0) - websocket-driver (>= 0.6.1) - actionmailbox (6.0.2) - actionpack (= 6.0.2) - activejob (= 6.0.2) - activerecord (= 6.0.2) - activestorage (= 6.0.2) - activesupport (= 6.0.2) - mail (>= 2.7.1) - actionmailer (6.0.2) - actionpack (= 6.0.2) - actionview (= 6.0.2) - activejob (= 6.0.2) - mail (~> 2.5, >= 2.5.4) - rails-dom-testing (~> 2.0) - actionpack (6.0.2) - actionview (= 6.0.2) - activesupport (= 6.0.2) - rack (~> 2.0) - rack-test (>= 0.6.3) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.0, >= 1.2.0) - actiontext (6.0.2) - actionpack (= 6.0.2) - activerecord (= 6.0.2) - activestorage (= 6.0.2) - activesupport (= 6.0.2) - nokogiri (>= 1.8.5) - actionview (6.0.2) - activesupport (= 6.0.2) - builder (~> 3.1) - erubi (~> 1.4) - rails-dom-testing (~> 2.0) - rails-html-sanitizer (~> 1.1, >= 1.2.0) - activejob (6.0.2) - activesupport (= 6.0.2) - globalid (>= 0.3.6) - activemodel (6.0.2) - activesupport (= 6.0.2) - activerecord (6.0.2) - activemodel (= 6.0.2) - activesupport (= 6.0.2) - activestorage (6.0.2) - actionpack (= 6.0.2) - activejob (= 6.0.2) - activerecord (= 6.0.2) - marcel (~> 0.3.1) - activesupport (6.0.2) - concurrent-ruby (~> 1.0, >= 1.0.2) - i18n (>= 0.7, < 2) - minitest (~> 5.1) - tzinfo (~> 1.1) - zeitwerk (~> 2.2) - ast (2.4.0) - builder (3.2.4) - byebug (11.0.1) - coderay (1.1.2) - concurrent-ruby (1.1.5) - connection_pool (2.2.2) - crass (1.0.5) - docile (1.3.2) - erubi (1.9.0) - globalid (0.4.2) - activesupport (>= 4.2.0) - hiredis (0.6.3) - i18n (1.7.0) - concurrent-ruby (~> 1.0) - jaro_winkler (1.5.4) - json (2.2.0) - loofah (2.4.0) - crass (~> 1.0.2) - nokogiri (>= 1.5.9) - mail (2.7.1) - mini_mime (>= 0.1.1) - marcel (0.3.3) - mimemagic (~> 0.3.2) - method_source (0.9.2) - mimemagic (0.3.3) - mini_mime (1.0.2) - mini_portile2 (2.4.0) - minitest (5.11.3) - nio4r (2.5.2) - nokogiri (1.10.7) - mini_portile2 (~> 2.4.0) - parallel (1.19.0) - parser (2.6.5.0) - ast (~> 2.4.0) - pry (0.12.2) - coderay (~> 1.1.0) - method_source (~> 0.9.0) - pry-byebug (3.7.0) - byebug (~> 11.0) - pry (~> 0.10) - rack (2.0.7) - rack-protection (2.0.7) - rack - rack-test (1.1.0) - rack (>= 1.0, < 3) - rails (6.0.2) - actioncable (= 6.0.2) - actionmailbox (= 6.0.2) - actionmailer (= 6.0.2) - actionpack (= 6.0.2) - actiontext (= 6.0.2) - actionview (= 6.0.2) - activejob (= 6.0.2) - activemodel (= 6.0.2) - activerecord (= 6.0.2) - activestorage (= 6.0.2) - activesupport (= 6.0.2) - bundler (>= 1.3.0) - railties (= 6.0.2) - sprockets-rails (>= 2.0.0) - rails-dom-testing (2.0.3) - activesupport (>= 4.2.0) - nokogiri (>= 1.6) - rails-html-sanitizer (1.3.0) - loofah (~> 2.3) - railties (6.0.2) - actionpack (= 6.0.2) - activesupport (= 6.0.2) - method_source - rake (>= 0.8.7) - thor (>= 0.20.3, < 2.0) - rainbow (3.0.0) - rake (12.3.3) - redis (4.1.2) - redis-namespace (1.6.0) - redis (>= 3.0.4) - rubocop (0.75.1) - jaro_winkler (~> 1.5.1) - parallel (~> 1.10) - parser (>= 2.6) - rainbow (>= 2.2.2, < 4.0) - ruby-progressbar (~> 1.7) - unicode-display_width (>= 1.4.0, < 1.7) - rubocop-performance (1.5.1) - rubocop (>= 0.71.0) - ruby-progressbar (1.10.1) - simplecov (0.17.0) - docile (~> 1.1) - json (>= 1.8, < 3) - simplecov-html (~> 0.10.0) - simplecov-html (0.10.2) - sprockets (4.0.0) - concurrent-ruby (~> 1.0) - rack (> 1, < 3) - sprockets-rails (3.2.1) - actionpack (>= 4.0) - activesupport (>= 4.0) - sprockets (>= 3.0.0) - sqlite3 (1.4.1) - standard (0.1.6) - rubocop (~> 0.75.0) - rubocop-performance (~> 1.5.0) - thor (1.0.1) - thread_safe (0.3.6) - toxiproxy (1.0.3) - tzinfo (1.2.5) - thread_safe (~> 0.1) - unicode-display_width (1.6.0) - websocket-driver (0.7.1) - websocket-extensions (>= 0.1.0) - websocket-extensions (0.1.4) - zeitwerk (2.2.2) - -PLATFORMS - ruby - -DEPENDENCIES - activerecord-jdbcsqlite3-adapter - hiredis - minitest - pry-byebug - rails (>= 6.0.2) - rake - redis-namespace - sidekiq! - simplecov - sqlite3 - standard - toxiproxy - -BUNDLED WITH - 1.17.2 diff -Nru ruby-sidekiq-6.0.4+dfsg/.github/contributing.md ruby-sidekiq-6.3.1+dfsg/.github/contributing.md --- ruby-sidekiq-6.0.4+dfsg/.github/contributing.md 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/.github/contributing.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,32 +0,0 @@ -# Contributing - -## Issues - -When opening an issue: - -* include the full **backtrace** with your error -* include your Sidekiq initializer -* list versions you are using: Ruby, Rails, Sidekiq, OS, etc. - -It's always better to include more info rather than less. - -## Code - -It's always best to open an issue before investing a lot of time into a -fix or new functionality. Functionality must meet my design goals and -vision for the project to be accepted; I would be happy to discuss how -your idea can best fit into Sidekiq. - -## Legal - -By submitting a Pull Request, you disavow any rights or claims to any changes -submitted to the Sidekiq project and assign the copyright of -those changes to Contributed Systems LLC. - -If you cannot or do not want to reassign those rights (your employment -contract for your employer may not allow this), you should not submit a PR. -Open an issue and someone else can do the work. - -This is a legal way of saying "If you submit a PR to us, that code becomes ours". -99.9% of the time that's what you intend anyways; we hope it doesn't scare you -away from contributing. diff -Nru ruby-sidekiq-6.0.4+dfsg/.github/issue_template.md ruby-sidekiq-6.3.1+dfsg/.github/issue_template.md --- ruby-sidekiq-6.0.4+dfsg/.github/issue_template.md 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/.github/issue_template.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,11 +0,0 @@ -Ruby version: -Sidekiq / Pro / Enterprise version(s): - -Please include your initializer and any error message with the full backtrace. - -Are you using an old version? -Have you checked the changelogs to see if your issue has been fixed in a later version? - -https://github.com/mperham/sidekiq/blob/master/Changes.md -https://github.com/mperham/sidekiq/blob/master/Pro-Changes.md -https://github.com/mperham/sidekiq/blob/master/Ent-Changes.md diff -Nru ruby-sidekiq-6.0.4+dfsg/.gitignore ruby-sidekiq-6.3.1+dfsg/.gitignore --- ruby-sidekiq-6.0.4+dfsg/.gitignore 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/.gitignore 1970-01-01 00:00:00.000000000 +0000 @@ -1,13 +0,0 @@ -.rvmrc -.ruby-version -tags -*.swp -dump.rdb -.rbx -coverage/ -vendor/ -.bundle/ -.sass-cache/ -tmp/ -pkg/*.gem -.byebug_history diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/api.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/api.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/api.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/api.rb 2021-11-18 13:57:25.000000000 +0000 @@ -8,7 +8,7 @@ module Sidekiq class Stats def initialize - fetch_stats! + fetch_stats_fast! end def processed @@ -51,7 +51,8 @@ Sidekiq::Stats::Queues.new.lengths end - def fetch_stats! + # O(1) redis calls + def fetch_stats_fast! pipe1_res = Sidekiq.redis { |conn| conn.pipelined do conn.get("stat:processed") @@ -64,6 +65,33 @@ end } + default_queue_latency = if (entry = pipe1_res[6].first) + job = begin + Sidekiq.load_json(entry) + rescue + {} + end + now = Time.now.to_f + thence = job["enqueued_at"] || now + now - thence + else + 0 + end + + @stats = { + processed: pipe1_res[0].to_i, + failed: pipe1_res[1].to_i, + scheduled_size: pipe1_res[2], + retry_size: pipe1_res[3], + dead_size: pipe1_res[4], + processes_size: pipe1_res[5], + + default_queue_latency: default_queue_latency + } + end + + # O(number of processes + number of queues) redis calls + def fetch_stats_slow! processes = Sidekiq.redis { |conn| conn.sscan_each("processes").to_a } @@ -83,30 +111,14 @@ workers_size = pipe2_res[0...s].sum(&:to_i) enqueued = pipe2_res[s..-1].sum(&:to_i) - default_queue_latency = if (entry = pipe1_res[6].first) - job = begin - Sidekiq.load_json(entry) - rescue - {} - end - now = Time.now.to_f - thence = job["enqueued_at"] || now - now - thence - else - 0 - end - @stats = { - processed: pipe1_res[0].to_i, - failed: pipe1_res[1].to_i, - scheduled_size: pipe1_res[2], - retry_size: pipe1_res[3], - dead_size: pipe1_res[4], - processes_size: pipe1_res[5], + @stats[:workers_size] = workers_size + @stats[:enqueued] = enqueued + @stats + end - default_queue_latency: default_queue_latency, - workers_size: workers_size, - enqueued: enqueued, - } + def fetch_stats! + fetch_stats_fast! + fetch_stats_slow! end def reset(*stats) @@ -126,7 +138,8 @@ private def stat(s) - @stats[s] + fetch_stats_slow! if @stats[s].nil? + @stats[s] || raise(ArgumentError, "Unknown stat #{s}") end class Queues @@ -141,7 +154,7 @@ } array_of_arrays = queues.zip(lengths).sort_by { |_, size| -size } - Hash[array_of_arrays] + array_of_arrays.to_h end end end @@ -255,7 +268,7 @@ break if entries.empty? page += 1 entries.each do |entry| - yield Job.new(entry, @name) + yield JobRecord.new(entry, @name) end deleted_size = initial_size - size end @@ -265,7 +278,7 @@ # Find the job with the given JID within this queue. # # This is a slow, inefficient operation. Do not use under - # normal conditions. Sidekiq Pro contains a faster version. + # normal conditions. def find_job(jid) detect { |j| j.jid == jid } end @@ -273,7 +286,7 @@ def clear Sidekiq.redis do |conn| conn.multi do - conn.del(@rname) + conn.unlink(@rname) conn.srem("queues", name) end end @@ -286,9 +299,9 @@ # sorted set. # # The job should be considered immutable but may be - # removed from the queue via Job#delete. + # removed from the queue via JobRecord#delete. # - class Job + class JobRecord attr_reader :item attr_reader :value @@ -316,21 +329,23 @@ def display_class # Unwrap known wrappers so they show up in a human-friendly manner in the Web UI - @klass ||= case klass - when /\ASidekiq::Extensions::Delayed/ - safe_load(args[0], klass) do |target, method, _| - "#{target}.#{method}" - end - when "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper" - job_class = @item["wrapped"] || args[0] - if job_class == "ActionMailer::DeliveryJob" || job_class == "ActionMailer::MailDeliveryJob" - # MailerClass#mailer_method - args[0]["arguments"][0..1].join("#") - else - job_class - end - else - klass + @klass ||= self["display_class"] || begin + case klass + when /\ASidekiq::Extensions::Delayed/ + safe_load(args[0], klass) do |target, method, _| + "#{target}.#{method}" + end + when "ActiveJob::QueueAdapters::SidekiqAdapter::JobWrapper" + job_class = @item["wrapped"] || args[0] + if job_class == "ActionMailer::DeliveryJob" || job_class == "ActionMailer::MailDeliveryJob" + # MailerClass#mailer_method + args[0]["arguments"][0..1].join("#") + else + job_class + end + else + klass + end end end @@ -443,7 +458,7 @@ end end - class SortedEntry < Job + class SortedEntry < JobRecord attr_reader :score attr_reader :parent @@ -562,7 +577,7 @@ def clear Sidekiq.redis do |conn| - conn.del(name) + conn.unlink(name) end end alias_method :💣, :clear @@ -791,19 +806,23 @@ # you'll be happier this way conn.pipelined do procs.each do |key| - conn.hmget(key, "info", "busy", "beat", "quiet") + conn.hmget(key, "info", "busy", "beat", "quiet", "rss", "rtt_us") end end } - result.each do |info, busy, at_s, quiet| + result.each do |info, busy, at_s, quiet, rss, rtt| # If a process is stopped between when we query Redis for `procs` and # when we query for `result`, we will have an item in `result` that is # composed of `nil` values. next if info.nil? hash = Sidekiq.load_json(info) - yield Process.new(hash.merge("busy" => busy.to_i, "beat" => at_s.to_f, "quiet" => quiet)) + yield Process.new(hash.merge("busy" => busy.to_i, + "beat" => at_s.to_f, + "quiet" => quiet, + "rss" => rss.to_i, + "rtt_us" => rtt.to_i)) end end @@ -815,6 +834,18 @@ Sidekiq.redis { |conn| conn.scard("processes") } end + # Total number of threads available to execute jobs. + # For Sidekiq Enterprise customers this number (in production) must be + # less than or equal to your licensed concurrency. + def total_concurrency + sum { |x| x["concurrency"].to_i } + end + + def total_rss_in_kb + sum { |x| x["rss"].to_i } + end + alias_method :total_rss, :total_rss_in_kb + # Returns the identity of the current cluster leader or "" if no leader. # This is a Sidekiq Enterprise feature, will always return "" in Sidekiq # or Sidekiq Pro. @@ -864,6 +895,10 @@ self["identity"] end + def queues + self["queues"] + end + def quiet! signal("TSTP") end @@ -894,8 +929,8 @@ end ## - # A worker is a thread that is currently processing a job. - # Programmatic access to the current active worker set. + # The WorkSet stores the work being done by this Sidekiq cluster. + # It tracks the process and thread working on each job. # # WARNING WARNING WARNING # @@ -903,25 +938,26 @@ # If you call #size => 5 and then expect #each to be # called 5 times, you're going to have a bad time. # - # workers = Sidekiq::Workers.new - # workers.size => 2 - # workers.each do |process_id, thread_id, work| + # works = Sidekiq::WorkSet.new + # works.size => 2 + # works.each do |process_id, thread_id, work| # # process_id is a unique identifier per Sidekiq process # # thread_id is a unique identifier per thread # # work is a Hash which looks like: - # # { 'queue' => name, 'run_at' => timestamp, 'payload' => msg } + # # { 'queue' => name, 'run_at' => timestamp, 'payload' => job_hash } # # run_at is an epoch Integer. # end # - class Workers + class WorkSet include Enumerable - def each + def each(&block) + results = [] Sidekiq.redis do |conn| procs = conn.sscan_each("processes").to_a procs.sort.each do |key| valid, workers = conn.pipelined { - conn.exists(key) + conn.exists?(key) conn.hgetall("#{key}:workers") } next unless valid @@ -930,10 +966,12 @@ p = hsh["payload"] # avoid breaking API, this is a side effect of the JSON optimization in #4316 hsh["payload"] = Sidekiq.load_json(p) if p.is_a?(String) - yield key, tid, hsh + results << [key, tid, hsh] end end end + + results.sort_by { |(_, _, hsh)| hsh["run_at"] }.each(&block) end # Note that #size is only as accurate as Sidekiq's heartbeat, @@ -957,4 +995,8 @@ end end end + # Since "worker" is a nebulous term, we've deprecated the use of this class name. + # Is "worker" a process, a type of job, a thread? Undefined! + # WorkSet better describes the data. + Workers = WorkSet end diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/client.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/client.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/client.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/client.rb 2021-11-18 13:57:25.000000000 +0000 @@ -19,7 +19,7 @@ # def middleware(&block) @chain ||= Sidekiq.client_middleware - if block_given? + if block @chain = @chain.dup yield @chain end @@ -90,16 +90,17 @@ # Returns an array of the of pushed jobs' jids. The number of jobs pushed can be less # than the number given if the middleware stopped processing for one or more jobs. def push_bulk(items) - arg = items["args"].first - return [] unless arg # no jobs to push - raise ArgumentError, "Bulk arguments must be an Array of Arrays: [[1], [2]]" unless arg.is_a?(Array) + args = items["args"] + raise ArgumentError, "Bulk arguments must be an Array of Arrays: [[1], [2]]" unless args.is_a?(Array) && args.all?(Array) + return [] if args.empty? # no jobs to push at = items.delete("at") - raise ArgumentError, "Job 'at' must be a Numeric or an Array of Numeric timestamps" if at && (Array(at).empty? || !Array(at).all?(Numeric)) + raise ArgumentError, "Job 'at' must be a Numeric or an Array of Numeric timestamps" if at && (Array(at).empty? || !Array(at).all? { |entry| entry.is_a?(Numeric) }) + raise ArgumentError, "Job 'at' Array must have same size as 'args' Array" if at.is_a?(Array) && at.size != args.size normed = normalize_item(items) - payloads = items["args"].map.with_index { |args, index| - copy = normed.merge("args" => args, "jid" => SecureRandom.hex(12), "enqueued_at" => Time.now.to_f) + payloads = args.map.with_index { |job_args, index| + copy = normed.merge("args" => job_args, "jid" => SecureRandom.hex(12), "enqueued_at" => Time.now.to_f) copy["at"] = (at.is_a?(Array) ? at[index] : at) if at result = process_single(items["class"], copy) @@ -185,7 +186,7 @@ def raw_push(payloads) @redis_pool.with do |conn| - conn.multi do + conn.pipelined do atomic_push(conn, payloads) end end @@ -218,16 +219,16 @@ end end + def validate(item) + raise(ArgumentError, "Job must be a Hash with 'class' and 'args' keys: `#{item}`") unless item.is_a?(Hash) && item.key?("class") && item.key?("args") + raise(ArgumentError, "Job args must be an Array: `#{item}`") unless item["args"].is_a?(Array) + raise(ArgumentError, "Job class must be either a Class or String representation of the class name: `#{item}`") unless item["class"].is_a?(Class) || item["class"].is_a?(String) + raise(ArgumentError, "Job 'at' must be a Numeric timestamp: `#{item}`") if item.key?("at") && !item["at"].is_a?(Numeric) + raise(ArgumentError, "Job tags must be an Array: `#{item}`") if item["tags"] && !item["tags"].is_a?(Array) + end + def normalize_item(item) - # 6.0.0 push_bulk bug, #4321 - # TODO Remove after a while... - item.delete("at") if item.key?("at") && item["at"].nil? - - raise(ArgumentError, "Job must be a Hash with 'class' and 'args' keys: { 'class' => SomeWorker, 'args' => ['bob', 1, :foo => 'bar'] }") unless item.is_a?(Hash) && item.key?("class") && item.key?("args") - raise(ArgumentError, "Job args must be an Array") unless item["args"].is_a?(Array) - raise(ArgumentError, "Job class must be either a Class or String representation of the class name") unless item["class"].is_a?(Class) || item["class"].is_a?(String) - raise(ArgumentError, "Job 'at' must be a Numeric timestamp") if item.key?("at") && !item["at"].is_a?(Numeric) - raise(ArgumentError, "Job tags must be an Array") if item["tags"] && !item["tags"].is_a?(Array) + validate(item) # raise(ArgumentError, "Arguments must be native JSON types, see https://github.com/mperham/sidekiq/wiki/Best-Practices") unless JSON.load(JSON.dump(item['args'])) == item['args'] # merge in the default sidekiq_options for the item's class and/or wrapped element @@ -236,6 +237,8 @@ defaults = defaults.merge(item["wrapped"].get_sidekiq_options) if item["wrapped"].respond_to?("get_sidekiq_options") item = defaults.merge(item) + raise(ArgumentError, "Job must include a valid queue name") if item["queue"].nil? || item["queue"] == "" + item["class"] = item["class"].to_s item["queue"] = item["queue"].to_s item["jid"] ||= SecureRandom.hex(12) diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/cli.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/cli.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/cli.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/cli.rb 2021-11-18 13:57:25.000000000 +0000 @@ -33,8 +33,9 @@ # Code within this method is not tested because it alters # global process state irreversibly. PRs which improve the # test coverage of Sidekiq::CLI are welcomed. - def run - boot_system + def run(boot_app: true) + boot_application if boot_app + if environment == "development" && $stdout.tty? && Sidekiq.log_formatter.is_a?(Sidekiq::Logger::Formatters::Pretty) print_banner end @@ -43,9 +44,17 @@ self_read, self_write = IO.pipe sigs = %w[INT TERM TTIN TSTP] # USR1 and USR2 don't work on the JVM - sigs << "USR2" unless jruby? + sigs << "USR2" if Sidekiq.pro? && !jruby? sigs.each do |sig| - trap sig do + old_handler = Signal.trap(sig) do + if old_handler.respond_to?(:call) + begin + old_handler.call + rescue Exception => exc + # signal handlers can't use Logger so puts only + puts ["Error in #{sig} handler", exc].inspect + end + end self_write.puts(sig) end rescue ArgumentError @@ -54,13 +63,26 @@ logger.info "Running in #{RUBY_DESCRIPTION}" logger.info Sidekiq::LICENSE - logger.info "Upgrade to Sidekiq Pro for more features and support: http://sidekiq.org" unless defined?(::Sidekiq::Pro) + logger.info "Upgrade to Sidekiq Pro for more features and support: https://sidekiq.org" unless defined?(::Sidekiq::Pro) # touch the connection pool so it is created before we # fire startup and start multithreading. - ver = Sidekiq.redis_info["redis_version"] + info = Sidekiq.redis_info + ver = info["redis_version"] raise "You are connecting to Redis v#{ver}, Sidekiq requires Redis v4.0.0 or greater" if ver < "4" + maxmemory_policy = info["maxmemory_policy"] + if maxmemory_policy != "noeviction" + logger.warn <<~EOM + + + WARNING: Your Redis instance will evict Sidekiq data under heavy load. + The 'noeviction' maxmemory policy is recommended (current policy: '#{maxmemory_policy}'). + See: https://github.com/mperham/sidekiq/wiki/Using-Redis#memory + + EOM + end + # 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 @@ -163,7 +185,7 @@ Sidekiq.logger.warn "" end end - }, + } } UNHANDLED_SIGNAL_HANDLER = ->(cli) { Sidekiq.logger.info "No signal handler registered, ignoring" } SIGNAL_HANDLERS.default = UNHANDLED_SIGNAL_HANDLER @@ -182,7 +204,11 @@ end def set_environment(cli_env) - @environment = cli_env || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development" + # See #984 for discussion. + # APP_ENV is now the preferred ENV term since it is not tech-specific. + # Both Sinatra 2.0+ and Sidekiq support this term. + # RAILS_ENV and RACK_ENV are there for legacy support. + @environment = cli_env || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development" end def symbolize_keys_deep!(hash) @@ -224,8 +250,7 @@ opts = parse_config(opts[:config_file]).merge(opts) if opts[:config_file] # set defaults - opts[:queues] = ["default"] if opts[:queues].nil? || opts[:queues].empty? - opts[:strict] = true if opts[:strict].nil? + opts[:queues] = ["default"] if opts[:queues].nil? opts[:concurrency] = Integer(ENV["RAILS_MAX_THREADS"]) if opts[:concurrency].nil? && ENV["RAILS_MAX_THREADS"] # merge with defaults @@ -236,7 +261,7 @@ Sidekiq.options end - def boot_system + def boot_application ENV["RACK_ENV"] = ENV["RAILS_ENV"] = environment if File.directory?(options[:require]) @@ -364,6 +389,8 @@ end opts = opts.merge(opts.delete(environment.to_sym) || {}) + opts.delete(:strict) + parse_queues(opts, opts.delete(:queues) || []) opts @@ -375,13 +402,16 @@ def parse_queue(opts, queue, weight = nil) opts[:queues] ||= [] + opts[:strict] = true if opts[:strict].nil? raise ArgumentError, "queues: #{queue} cannot be defined twice" if opts[:queues].include?(queue) - [weight.to_i, 1].max.times { opts[:queues] << queue } + [weight.to_i, 1].max.times { opts[:queues] << queue.to_s } opts[:strict] = false if weight.to_i > 0 end def rails_app? - defined?(::Rails) + defined?(::Rails) && ::Rails.respond_to?(:application) end end end + +require "sidekiq/systemd" diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/extensions/action_mailer.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/extensions/action_mailer.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/extensions/action_mailer.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/extensions/action_mailer.rb 2021-11-18 13:57:25.000000000 +0000 @@ -5,9 +5,10 @@ module Sidekiq module Extensions ## - # Adds 'delay', 'delay_for' and `delay_until` methods to ActionMailer to offload arbitrary email - # delivery to Sidekiq. Example: + # Adds +delay+, +delay_for+ and +delay_until+ methods to ActionMailer to offload arbitrary email + # delivery to Sidekiq. # + # @example # UserMailer.delay.send_welcome_email(new_user) # UserMailer.delay_for(5.days).send_welcome_email(new_user) # UserMailer.delay_until(5.days.from_now).send_welcome_email(new_user) diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/extensions/active_record.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/extensions/active_record.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/extensions/active_record.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/extensions/active_record.rb 2021-11-18 13:57:25.000000000 +0000 @@ -5,10 +5,11 @@ module Sidekiq module Extensions ## - # Adds 'delay', 'delay_for' and `delay_until` methods to ActiveRecord to offload instance method - # execution to Sidekiq. Examples: + # Adds +delay+, +delay_for+ and +delay_until+ methods to ActiveRecord to offload instance method + # execution to Sidekiq. # - # User.recent_signups.each { |user| user.delay.mark_as_awesome } + # @example + # User.recent_signups.each { |user| user.delay.mark_as_awesome } # # Please note, this is not recommended as this will serialize the entire # object to Redis. Your Sidekiq jobs should pass IDs, not entire instances. diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/extensions/class_methods.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/extensions/class_methods.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/extensions/class_methods.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/extensions/class_methods.rb 2021-11-18 13:57:25.000000000 +0000 @@ -5,11 +5,12 @@ module Sidekiq module Extensions ## - # Adds 'delay', 'delay_for' and `delay_until` methods to all Classes to offload class method - # execution to Sidekiq. Examples: + # Adds `delay`, `delay_for` and `delay_until` methods to all Classes to offload class method + # execution to Sidekiq. # - # User.delay.delete_inactive - # Wikipedia.delay.download_changes_for(Date.today) + # @example + # User.delay.delete_inactive + # Wikipedia.delay.download_changes_for(Date.today) # class DelayedClass include Sidekiq::Worker diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/extensions/generic_proxy.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/extensions/generic_proxy.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/extensions/generic_proxy.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/extensions/generic_proxy.rb 2021-11-18 13:57:25.000000000 +0000 @@ -24,7 +24,9 @@ if marshalled.size > SIZE_LIMIT ::Sidekiq.logger.warn { "#{@target}.#{name} job argument is #{marshalled.bytesize} bytes, you should refactor it to reduce the size" } end - @performable.client_push({"class" => @performable, "args" => [marshalled]}.merge(@opts)) + @performable.client_push({"class" => @performable, + "args" => [marshalled], + "display_class" => "#{@target}.#{name}"}.merge(@opts)) end end end diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/fetch.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/fetch.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/fetch.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/fetch.rb 2021-11-18 13:57:25.000000000 +0000 @@ -25,8 +25,10 @@ } def initialize(options) - @strictly_ordered_queues = !!options[:strict] - @queues = options[:queues].map { |q| "queue:#{q}" } + raise ArgumentError, "missing queue list" unless options[:queues] + @options = options + @strictly_ordered_queues = !!@options[:strict] + @queues = @options[:queues].map { |q| "queue:#{q}" } if @strictly_ordered_queues @queues.uniq! @queues << TIMEOUT @@ -34,28 +36,19 @@ end def retrieve_work - work = Sidekiq.redis { |conn| conn.brpop(*queues_cmd) } - UnitOfWork.new(*work) if work - end - - # Creating the Redis#brpop command takes into account any - # configured queue weights. By default Redis#brpop returns - # data from the first queue that has pending elements. We - # recreate the queue command each time we invoke Redis#brpop - # to honor weights and avoid queue starvation. - def queues_cmd - if @strictly_ordered_queues - @queues - else - queues = @queues.shuffle!.uniq - queues << TIMEOUT - queues + qs = queues_cmd + # 4825 Sidekiq Pro with all queues paused will return an + # empty set of queues with a trailing TIMEOUT value. + if qs.size <= 1 + sleep(TIMEOUT) + return nil end + + work = Sidekiq.redis { |conn| conn.brpop(*qs) } + UnitOfWork.new(*work) if work end - # By leaving this as a class method, it can be pluggable and used by the Manager actor. Making it - # an instance method will make it async to the Fetcher actor - def self.bulk_requeue(inprogress, options) + def bulk_requeue(inprogress, options) return if inprogress.empty? Sidekiq.logger.debug { "Re-queueing terminated jobs" } @@ -76,5 +69,21 @@ rescue => ex Sidekiq.logger.warn("Failed to requeue #{inprogress.size} jobs: #{ex.message}") end + + # Creating the Redis#brpop command takes into account any + # configured queue weights. By default Redis#brpop returns + # data from the first queue that has pending elements. We + # recreate the queue command each time we invoke Redis#brpop + # to honor weights and avoid queue starvation. + def queues_cmd + if @strictly_ordered_queues + @queues + else + permute = @queues.shuffle + permute.uniq! + permute << TIMEOUT + permute + end + end end end diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/job_logger.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/job_logger.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/job_logger.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/job_logger.rb 2021-11-18 13:57:25.000000000 +0000 @@ -38,8 +38,8 @@ # If we're using a wrapper class, like ActiveJob, use the "wrapped" # attribute to expose the underlying thing. h = { - class: job_hash["wrapped"] || job_hash["class"], - jid: job_hash["jid"], + class: job_hash["display_class"] || job_hash["wrapped"] || job_hash["class"], + jid: job_hash["jid"] } h[:bid] = job_hash["bid"] if job_hash["bid"] h[:tags] = job_hash["tags"] if job_hash["tags"] diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/job.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/job.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/job.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/job.rb 2021-11-18 13:57:25.000000000 +0000 @@ -0,0 +1,13 @@ +require "sidekiq/worker" + +module Sidekiq + # Sidekiq::Job is a new alias for Sidekiq::Worker as of Sidekiq 6.3.0. + # Use `include Sidekiq::Job` rather than `include Sidekiq::Worker`. + # + # The term "worker" is too generic and overly confusing, used in several + # different contexts meaning different things. Many people call a Sidekiq + # process a "worker". Some people call the thread that executes jobs a + # "worker". This change brings Sidekiq closer to ActiveJob where your job + # classes extend ApplicationJob. + Job = Worker +end diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/job_retry.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/job_retry.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/job_retry.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/job_retry.rb 2021-11-18 13:57:25.000000000 +0000 @@ -61,6 +61,7 @@ # class JobRetry class Handled < ::RuntimeError; end + class Skip < Handled; end include Sidekiq::Util @@ -213,16 +214,12 @@ end def delay_for(worker, count, exception) + jitter = rand(10) * (count + 1) if worker&.sidekiq_retry_in_block custom_retry_in = retry_in(worker, count, exception).to_i - return custom_retry_in if custom_retry_in > 0 + return custom_retry_in + jitter if custom_retry_in > 0 end - seconds_to_delay(count) - end - - # delayed_job uses the same basic formula - def seconds_to_delay(count) - (count**4) + 15 + (rand(30) * (count + 1)) + (count**4) + 15 + jitter end def retry_in(worker, count, exception) diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/launcher.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/launcher.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/launcher.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/launcher.rb 2021-11-18 13:57:25.000000000 +0000 @@ -16,12 +16,13 @@ proc { Sidekiq::VERSION }, proc { |me, data| data["tag"] }, proc { |me, data| "[#{Processor::WORKER_STATE.size} of #{data["concurrency"]} busy]" }, - proc { |me, data| "stopping" if me.stopping? }, + proc { |me, data| "stopping" if me.stopping? } ] attr_accessor :manager, :poller, :fetcher def initialize(options) + options[:fetch] ||= BasicFetch.new(options) @manager = Sidekiq::Manager.new(options) @poller = Sidekiq::Scheduled::Poller.new @done = false @@ -56,7 +57,7 @@ # Requeue everything in case there was a worker who grabbed work while stopped # This call is a no-op in Sidekiq but necessary for Sidekiq Pro. - strategy = (@options[:fetch] || Sidekiq::BasicFetch) + strategy = @options[:fetch] strategy.bulk_requeue([], @options) clear_heartbeat @@ -68,10 +69,12 @@ private unless $TESTING + BEAT_PAUSE = 5 + def start_heartbeat loop do heartbeat - sleep 5 + sleep BEAT_PAUSE end Sidekiq.logger.info("Heartbeat stopping...") end @@ -83,7 +86,7 @@ Sidekiq.redis do |conn| conn.pipelined do conn.srem("processes", identity) - conn.del("#{identity}:workers") + conn.unlink("#{identity}:workers") end end rescue @@ -96,6 +99,32 @@ ❤ end + def self.flush_stats + fails = Processor::FAILURE.reset + procd = Processor::PROCESSED.reset + return if fails + procd == 0 + + nowdate = Time.now.utc.strftime("%Y-%m-%d") + begin + Sidekiq.redis do |conn| + conn.pipelined do + conn.incrby("stat:processed", procd) + conn.incrby("stat:processed:#{nowdate}", procd) + conn.expire("stat:processed:#{nowdate}", STATS_TTL) + + conn.incrby("stat:failed", fails) + conn.incrby("stat:failed:#{nowdate}", fails) + conn.expire("stat:failed:#{nowdate}", STATS_TTL) + end + end + rescue => ex + # we're exiting the process, things might be shut down so don't + # try to handle the exception + Sidekiq.logger.warn("Unable to flush stats: #{ex}") + end + end + at_exit(&method(:flush_stats)) + def ❤ key = identity fails = procd = 0 @@ -118,7 +147,7 @@ conn.incrby("stat:failed:#{nowdate}", fails) conn.expire("stat:failed:#{nowdate}", STATS_TTL) - conn.del(workers_key) + conn.unlink(workers_key) curstate.each_pair do |tid, hash| conn.hset(workers_key, tid, Sidekiq.dump_json(hash)) end @@ -126,13 +155,21 @@ end end + rtt = check_rtt + fails = procd = 0 + kb = memory_usage(::Process.pid) _, exists, _, _, msg = Sidekiq.redis { |conn| conn.multi { conn.sadd("processes", key) - conn.exists(key) - conn.hmset(key, "info", to_json, "busy", curstate.size, "beat", Time.now.to_f, "quiet", @done) + conn.exists?(key) + conn.hmset(key, "info", to_json, + "busy", curstate.size, + "beat", Time.now.to_f, + "rtt_us", rtt, + "quiet", @done, + "rss", kb) conn.expire(key, 60) conn.rpop("#{key}-signals") } @@ -146,34 +183,81 @@ ::Process.kill(msg, ::Process.pid) rescue => e # ignore all redis/network issues - logger.error("heartbeat: #{e.message}") + logger.error("heartbeat: #{e}") # don't lose the counts if there was a network issue Processor::PROCESSED.incr(procd) Processor::FAILURE.incr(fails) end end - def to_data - @data ||= begin - { - "hostname" => hostname, - "started_at" => Time.now.to_f, - "pid" => ::Process.pid, - "tag" => @options[:tag] || "", - "concurrency" => @options[:concurrency], - "queues" => @options[:queues].uniq, - "labels" => @options[:labels], - "identity" => identity, - } + # We run the heartbeat every five seconds. + # Capture five samples of RTT, log a warning if each sample + # is above our warning threshold. + RTT_READINGS = RingBuffer.new(5) + RTT_WARNING_LEVEL = 50_000 + + def check_rtt + a = b = 0 + Sidekiq.redis do |x| + a = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :microsecond) + x.ping + b = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC, :microsecond) end + rtt = b - a + RTT_READINGS << rtt + # Ideal RTT for Redis is < 1000µs + # 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 + 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. + If these values are close to 100,000, that means your Sidekiq process may be + CPU overloaded; see https://github.com/mperham/sidekiq/discussions/5039 + EOM + RTT_READINGS.reset + end + rtt + end + + MEMORY_GRABBER = case RUBY_PLATFORM + when /linux/ + ->(pid) { + IO.readlines("/proc/#{$$}/status").each do |line| + next unless line.start_with?("VmRSS:") + break line.split[1].to_i + end + } + when /darwin|bsd/ + ->(pid) { + `ps -o pid,rss -p #{pid}`.lines.last.split.last.to_i + } + else + ->(pid) { 0 } + end + + def memory_usage(pid) + MEMORY_GRABBER.call(pid) + end + + def to_data + @data ||= { + "hostname" => hostname, + "started_at" => Time.now.to_f, + "pid" => ::Process.pid, + "tag" => @options[:tag] || "", + "concurrency" => @options[:concurrency], + "queues" => @options[:queues].uniq, + "labels" => @options[:labels], + "identity" => identity + } end def to_json - @json ||= begin - # this data changes infrequently so dump it to a string - # now so we don't need to dump it every heartbeat. - Sidekiq.dump_json(to_data) - end + # this data changes infrequently so dump it to a string + # now so we don't need to dump it every heartbeat. + @json ||= Sidekiq.dump_json(to_data) end end end diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/logger.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/logger.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/logger.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/logger.rb 2021-11-18 13:57:25.000000000 +0000 @@ -6,10 +6,11 @@ module Sidekiq module Context def self.with(hash) + orig_context = current.dup current.merge!(hash) yield ensure - hash.each_key { |key| current.delete(key) } + Thread.current[:sidekiq_context] = orig_context end def self.current @@ -23,7 +24,7 @@ "info" => 1, "warn" => 2, "error" => 3, - "fatal" => 4, + "fatal" => 4 } LEVELS.default_proc = proc do |_, level| Sidekiq.logger.warn("Invalid log level: #{level.inspect}") @@ -31,23 +32,23 @@ end def debug? - level >= 0 + level <= 0 end def info? - level >= 1 + level <= 1 end def warn? - level >= 2 + level <= 2 end def error? - level >= 3 + level <= 3 end def fatal? - level >= 4 + level <= 4 end def local_level @@ -83,13 +84,13 @@ # Redefined to check severity against #level, and thus the thread-local level, rather than +@level+. # FIXME: Remove when the minimum Ruby version supports overriding Logger#level. def add(severity, message = nil, progname = nil, &block) - severity ||= UNKNOWN + severity ||= ::Logger::UNKNOWN progname ||= @progname return true if @logdev.nil? || severity < level if message.nil? - if block_given? + if block message = yield else message = progname @@ -104,7 +105,7 @@ class Logger < ::Logger include LoggingUtils - def initialize(*args) + def initialize(*args, **kwargs) super self.formatter = Sidekiq.log_formatter end @@ -152,7 +153,7 @@ pid: ::Process.pid, tid: tid, lvl: severity, - msg: message, + msg: message } c = ctx hash["ctx"] = c unless c.empty? diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/manager.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/manager.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/manager.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/manager.rb 2021-11-18 13:57:25.000000000 +0000 @@ -35,7 +35,7 @@ @done = false @workers = Set.new @count.times do - @workers << Processor.new(self) + @workers << Processor.new(self, options) end @plock = Mutex.new end @@ -56,7 +56,7 @@ end # hack for quicker development / testing environment #2774 - PAUSE_TIME = STDOUT.tty? ? 0.1 : 0.5 + PAUSE_TIME = $stdout.tty? ? 0.1 : 0.5 def stop(deadline) quiet @@ -90,7 +90,7 @@ @plock.synchronize do @workers.delete(processor) unless @done - p = Processor.new(self) + p = Processor.new(self, options) @workers << p p.start end @@ -123,7 +123,7 @@ # 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] || Sidekiq::BasicFetch) + strategy = @options[:fetch] strategy.bulk_requeue(jobs, @options) end diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/middleware/chain.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/middleware/chain.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/middleware/chain.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/middleware/chain.rb 2021-11-18 13:57:25.000000000 +0000 @@ -90,12 +90,12 @@ end def add(klass, *args) - remove(klass) if exists?(klass) + remove(klass) entries << Entry.new(klass, *args) end def prepend(klass, *args) - remove(klass) if exists?(klass) + remove(klass) entries.insert(0, Entry.new(klass, *args)) end @@ -132,8 +132,8 @@ def invoke(*args) return yield if empty? - chain = retrieve.dup - traverse_chain = lambda do + chain = retrieve + traverse_chain = proc do if chain.empty? yield else @@ -144,6 +144,8 @@ end end + private + class Entry attr_reader :klass diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/middleware/current_attributes.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/middleware/current_attributes.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/middleware/current_attributes.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/middleware/current_attributes.rb 2021-11-18 13:57:25.000000000 +0000 @@ -0,0 +1,52 @@ +require "active_support/current_attributes" + +module Sidekiq + ## + # Automatically save and load any current attributes in the execution context + # so context attributes "flow" from Rails actions into any associated jobs. + # This can be useful for multi-tenancy, i18n locale, timezone, any implicit + # per-request attribute. See +ActiveSupport::CurrentAttributes+. + # + # @example + # + # # in your initializer + # require "sidekiq/middleware/current_attributes" + # Sidekiq::CurrentAttributes.persist(Myapp::Current) + # + module CurrentAttributes + class Save + def initialize(cattr) + @klass = cattr + end + + def call(_, job, _, _) + job["cattr"] = @klass.attributes + yield + end + end + + class Load + def initialize(cattr) + @klass = cattr + end + + def call(_, job, _, &block) + if job.has_key?("cattr") + @klass.set(job["cattr"], &block) + else + yield + end + end + end + + def self.persist(klass) + Sidekiq.configure_client do |config| + config.client_middleware.add Save, klass + end + Sidekiq.configure_server do |config| + config.client_middleware.add Save, klass + config.server_middleware.add Load, klass + end + end + end +end diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/monitor.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/monitor.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/monitor.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/monitor.rb 2021-11-18 13:57:25.000000000 +0000 @@ -62,7 +62,7 @@ columns = { name: [:ljust, (["name"] + queue_data.map(&:name)).map(&:length).max + COL_PAD], size: [:rjust, (["size"] + queue_data.map(&:size)).map(&:length).max + COL_PAD], - latency: [:rjust, (["latency"] + queue_data.map(&:latency)).map(&:length).max + COL_PAD], + latency: [:rjust, (["latency"] + queue_data.map(&:latency)).map(&:length).max + COL_PAD] } columns.each { |col, (dir, width)| print col.to_s.upcase.public_send(dir, width) } puts @@ -101,7 +101,7 @@ tags = [ process["tag"], process["labels"], - (process["quiet"] == "true" ? "quiet" : nil), + (process["quiet"] == "true" ? "quiet" : nil) ].flatten.compact tags.any? ? "[#{tags.join("] [")}]" : nil end diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/processor.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/processor.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/processor.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/processor.rb 2021-11-18 13:57:25.000000000 +0000 @@ -28,15 +28,15 @@ attr_reader :thread attr_reader :job - def initialize(mgr) + def initialize(mgr, options) @mgr = mgr @down = false @done = false @job = nil @thread = nil - @strategy = (mgr.options[:fetch] || Sidekiq::BasicFetch).new(mgr.options) - @reloader = Sidekiq.options[:reloader] - @job_logger = (mgr.options[:job_logger] || Sidekiq::JobLogger).new + @strategy = options[:fetch] + @reloader = options[:reloader] || proc { |&block| block.call } + @job_logger = (options[:job_logger] || Sidekiq::JobLogger).new @retrier = Sidekiq::JobRetry.new end @@ -181,7 +181,7 @@ # the retry subsystem (e.g. network partition). We won't acknowledge the job # so it can be rescued when using Sidekiq Pro. handle_exception(ex, {context: "Internal exception!", job: job_hash, jobstr: jobstr}) - raise e + raise ex ensure if ack # We don't want a shutdown signal to interrupt job acknowledgment. diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/rails.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/rails.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/rails.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/rails.rb 2021-11-18 13:57:25.000000000 +0000 @@ -4,6 +4,22 @@ module Sidekiq class Rails < ::Rails::Engine + class Reloader + def initialize(app = ::Rails.application) + @app = app + end + + def call + @app.reloader.wrap do + yield + end + end + + def inspect + "#" + end + end + # By including the Options module, we allow AJs to directly control sidekiq features # via the *sidekiq_options* class method and, for instance, not use AJ's retry system. # AJ retries don't show up in the Sidekiq UI Retries tab, save any error data, can't be @@ -21,10 +37,19 @@ end end + initializer "sidekiq.rails_logger" do + Sidekiq.configure_server do |_| + # This is the integration code necessary so that if code 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 ::ActiveSupport::Logger.logger_outputs_to?(::Rails.logger, $stdout) + ::Rails.logger.extend(::ActiveSupport::Logger.broadcast(::Sidekiq.logger)) + end + end + end + # This hook happens after all initializers are run, just before returning # from config/environment.rb back to sidekiq/cli.rb. - # We have to add the reloader after initialize to see if cache_classes has - # been turned on. # # None of this matters on the client-side, only within the Sidekiq process itself. config.after_initialize do @@ -32,21 +57,5 @@ Sidekiq.options[:reloader] = Sidekiq::Rails::Reloader.new end end - - class Reloader - def initialize(app = ::Rails.application) - @app = app - end - - def call - @app.reloader.wrap do - yield - end - end - - def inspect - "#" - end - end end end diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/redis_connection.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/redis_connection.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/redis_connection.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/redis_connection.rb 2021-11-18 13:57:25.000000000 +0000 @@ -8,15 +8,14 @@ class RedisConnection class << self def create(options = {}) - options.keys.each do |key| - options[key.to_sym] = options.delete(key) - end + symbolized_options = options.transform_keys(&:to_sym) - options[:id] = "Sidekiq-#{Sidekiq.server? ? "server" : "client"}-PID-#{::Process.pid}" unless options.key?(:id) - options[:url] ||= determine_redis_provider + if !symbolized_options[:url] && (u = determine_redis_provider) + symbolized_options[:url] = u + end - size = if options[:size] - options[:size] + size = if symbolized_options[:size] + symbolized_options[:size] elsif Sidekiq.server? # Give ourselves plenty of connections. pool is lazy # so we won't create them until we need them. @@ -29,11 +28,11 @@ verify_sizing(size, Sidekiq.options[:concurrency]) if Sidekiq.server? - pool_timeout = options[:pool_timeout] || 1 - log_info(options) + pool_timeout = symbolized_options[:pool_timeout] || 1 + log_info(symbolized_options) ConnectionPool.new(timeout: pool_timeout, size: size) do - build_client(options) + build_client(symbolized_options) end end @@ -93,9 +92,13 @@ end def log_info(options) - # Don't log Redis AUTH password redacted = "REDACTED" - scrubbed_options = options.dup + + # Deep clone so we can muck with these options all we want and exclude + # params from dump-and-load that may contain objects that Marshal is + # unable to safely dump. + keys = options.keys - [:logger, :ssl_params] + scrubbed_options = Marshal.load(Marshal.dump(options.slice(*keys))) if scrubbed_options[:url] && (uri = URI.parse(scrubbed_options[:url])) && uri.password uri.password = redacted scrubbed_options[:url] = uri.to_s @@ -122,7 +125,7 @@ # initialization code at all. # p = ENV["REDIS_PROVIDER"] - if p && p =~ /\:/ + if p && p =~ /:/ raise <<~EOM REDIS_PROVIDER should be set to the name of the variable which contains the Redis URL, not a URL itself. Platforms like Heroku will sell addons that publish a *_URL variable. You need to tell Sidekiq with REDIS_PROVIDER, e.g.: diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/scheduled.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/scheduled.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/scheduled.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/scheduled.rb 2021-11-18 13:57:25.000000000 +0000 @@ -9,29 +9,48 @@ SETS = %w[retry schedule] class Enq + LUA_ZPOPBYSCORE = <<~LUA + local key, now = KEYS[1], ARGV[1] + local jobs = redis.call("zrangebyscore", key, "-inf", now, "limit", 0, 1) + if jobs[1] then + redis.call("zrem", key, jobs[1]) + return jobs[1] + end + LUA + + def initialize + @lua_zpopbyscore_sha = nil + end + def enqueue_jobs(now = Time.now.to_f.to_s, sorted_sets = SETS) # A job's "score" in Redis is the time at which it should be processed. # Just check Redis for the set of jobs with a timestamp before now. Sidekiq.redis do |conn| sorted_sets.each do |sorted_set| - # Get next items in the queue with scores (time to execute) <= now. - until (jobs = conn.zrangebyscore(sorted_set, "-inf", now, limit: [0, 100])).empty? - # We need to go through the list one at a time to reduce the risk of something - # going wrong between the time jobs are popped from the scheduled queue and when - # they are pushed onto a work queue and losing the jobs. - jobs.each do |job| - # Pop item off the queue and add it to the work queue. If the job can't be popped from - # the queue, it's because another process already popped it so we can move on to the - # next one. - if conn.zrem(sorted_set, job) - Sidekiq::Client.push(Sidekiq.load_json(job)) - Sidekiq.logger.debug { "enqueued #{sorted_set}: #{job}" } - end - end + # Get next item in the queue with score (time to execute) <= now. + # We need to go through the list one at a time to reduce the risk of something + # going wrong between the time jobs are popped from the scheduled queue and when + # they are pushed onto a work queue and losing the jobs. + while (job = zpopbyscore(conn, keys: [sorted_set], argv: [now])) + Sidekiq::Client.push(Sidekiq.load_json(job)) + Sidekiq.logger.debug { "enqueued #{sorted_set}: #{job}" } end end end end + + private + + def zpopbyscore(conn, keys: nil, argv: nil) + @lua_zpopbyscore_sha = conn.script(:load, LUA_ZPOPBYSCORE) if @lua_zpopbyscore_sha.nil? + + conn.evalsha(@lua_zpopbyscore_sha, keys: keys, argv: argv) + rescue Redis::CommandError => e + raise unless e.message.start_with?("NOSCRIPT") + + @lua_zpopbyscore_sha = nil + retry + end end ## @@ -49,6 +68,7 @@ @sleeper = ConnectionPool::TimedStack.new @done = false @thread = nil + @count_calls = 0 end # Shut down this instance, will pause until the thread is dead. @@ -152,8 +172,13 @@ end def process_count - pcount = Sidekiq::ProcessSet.new.size + # The work buried within Sidekiq::ProcessSet#cleanup can be + # expensive at scale. Cut it down by 90% with this counter. + # NB: This method is only called by the scheduler thread so we + # don't need to worry about the thread safety of +=. + pcount = Sidekiq::ProcessSet.new(@count_calls % 10 == 0).size pcount = 1 if pcount == 0 + @count_calls += 1 pcount end diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/sd_notify.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/sd_notify.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/sd_notify.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/sd_notify.rb 2021-11-18 13:57:25.000000000 +0000 @@ -0,0 +1,149 @@ +# frozen_string_literal: true + +# The MIT License +# +# Copyright (c) 2017, 2018, 2019, 2020 Agis Anastasopoulos +# +# Permission is hereby granted, free of charge, to any person obtaining a copy of +# this software and associated documentation files (the "Software"), to deal in +# the Software without restriction, including without limitation the rights to +# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of +# the Software, and to permit persons to whom the Software is furnished to do so, +# subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in all +# copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS +# FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR +# COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER +# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN +# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +# This is a copy of https://github.com/agis/ruby-sdnotify as of commit a7d52ee +# The only changes made was "rehoming" it within the Sidekiq module to avoid +# namespace collisions and applying standard's code formatting style. + +require "socket" + +# SdNotify is a pure-Ruby implementation of sd_notify(3). It can be used to +# notify systemd about state changes. Methods of this package are no-op on +# non-systemd systems (eg. Darwin). +# +# The API maps closely to the original implementation of sd_notify(3), +# therefore be sure to check the official man pages prior to using SdNotify. +# +# @see https://www.freedesktop.org/software/systemd/man/sd_notify.html +module Sidekiq + module SdNotify + # Exception raised when there's an error writing to the notification socket + class NotifyError < RuntimeError; end + + READY = "READY=1" + RELOADING = "RELOADING=1" + STOPPING = "STOPPING=1" + STATUS = "STATUS=" + ERRNO = "ERRNO=" + MAINPID = "MAINPID=" + WATCHDOG = "WATCHDOG=1" + FDSTORE = "FDSTORE=1" + + def self.ready(unset_env = false) + notify(READY, unset_env) + end + + def self.reloading(unset_env = false) + notify(RELOADING, unset_env) + end + + def self.stopping(unset_env = false) + notify(STOPPING, unset_env) + end + + # @param status [String] a custom status string that describes the current + # state of the service + def self.status(status, unset_env = false) + notify("#{STATUS}#{status}", unset_env) + end + + # @param errno [Integer] + def self.errno(errno, unset_env = false) + notify("#{ERRNO}#{errno}", unset_env) + end + + # @param pid [Integer] + def self.mainpid(pid, unset_env = false) + notify("#{MAINPID}#{pid}", unset_env) + end + + def self.watchdog(unset_env = false) + notify(WATCHDOG, unset_env) + end + + def self.fdstore(unset_env = false) + notify(FDSTORE, unset_env) + end + + # @return [Boolean] true if the service manager expects watchdog keep-alive + # notification messages to be sent from this process. + # + # If the $WATCHDOG_USEC environment variable is set, + # and the $WATCHDOG_PID variable is unset or set to the PID of the current + # process + # + # @note Unlike sd_watchdog_enabled(3), this method does not mutate the + # environment. + def self.watchdog? + wd_usec = ENV["WATCHDOG_USEC"] + wd_pid = ENV["WATCHDOG_PID"] + + return false unless wd_usec + + begin + wd_usec = Integer(wd_usec) + rescue + return false + end + + return false if wd_usec <= 0 + return true if !wd_pid || wd_pid == $$.to_s + + false + end + + # Notify systemd with the provided state, via the notification socket, if + # any. + # + # Generally this method will be used indirectly through the other methods + # of the library. + # + # @param state [String] + # @param unset_env [Boolean] + # + # @return [Fixnum, nil] the number of bytes written to the notification + # socket or nil if there was no socket to report to (eg. the program wasn't + # started by systemd) + # + # @raise [NotifyError] if there was an error communicating with the systemd + # socket + # + # @see https://www.freedesktop.org/software/systemd/man/sd_notify.html + def self.notify(state, unset_env = false) + sock = ENV["NOTIFY_SOCKET"] + + return nil unless sock + + ENV.delete("NOTIFY_SOCKET") if unset_env + + begin + Addrinfo.unix(sock, :DGRAM).connect do |s| + s.close_on_exec = true + s.write(state) + end + rescue => e + raise NotifyError, "#{e.class}: #{e.message}", e.backtrace + end + end + end +end diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/systemd.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/systemd.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/systemd.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/systemd.rb 2021-11-18 13:57:25.000000000 +0000 @@ -0,0 +1,24 @@ +# +# Sidekiq's systemd integration allows Sidekiq to inform systemd: +# 1. when it has successfully started +# 2. when it is starting shutdown +# 3. periodically for a liveness check with a watchdog thread +# +module Sidekiq + def self.start_watchdog + usec = Integer(ENV["WATCHDOG_USEC"]) + return Sidekiq.logger.error("systemd Watchdog too fast: " + usec) if usec < 1_000_000 + + sec_f = usec / 1_000_000.0 + # "It is recommended that a daemon sends a keep-alive notification message + # to the service manager every half of the time returned here." + ping_f = sec_f / 2 + Sidekiq.logger.info "Pinging systemd watchdog every #{ping_f.round(1)} sec" + Thread.new do + loop do + sleep ping_f + Sidekiq::SdNotify.watchdog + end + end + end +end diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/testing.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/testing.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/testing.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/testing.rb 2021-11-18 13:57:25.000000000 +0000 @@ -337,8 +337,6 @@ Sidekiq::Extensions::DelayedModel.extend(TestingExtensions) if defined?(Sidekiq::Extensions::DelayedModel) end -if defined?(::Rails) && Rails.respond_to?(:env) && !Rails.env.test? - puts("**************************************************") - puts("⛔️ WARNING: Sidekiq testing API enabled, but this is not the test environment. Your jobs will not go to Redis.") - puts("**************************************************") +if defined?(::Rails) && Rails.respond_to?(:env) && !Rails.env.test? && !$TESTING + warn("⛔️ WARNING: Sidekiq testing API enabled, but this is not the test environment. Your jobs will not go to Redis.", uplevel: 1) end diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/util.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/util.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/util.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/util.rb 2021-11-18 13:57:25.000000000 +0000 @@ -1,5 +1,6 @@ # frozen_string_literal: true +require "forwardable" require "socket" require "securerandom" require "sidekiq/exception_handler" @@ -8,6 +9,33 @@ ## # 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 diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/version.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/version.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/version.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/version.rb 2021-11-18 13:57:25.000000000 +0000 @@ -1,5 +1,5 @@ # frozen_string_literal: true module Sidekiq - VERSION = "6.0.4" + VERSION = "6.3.1" end diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/web/action.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/web/action.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/web/action.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/web/action.rb 2021-11-18 13:57:25.000000000 +0000 @@ -15,7 +15,7 @@ end def halt(res) - throw :halt, res + throw :halt, [res, {"Content-Type" => "text/plain"}, [res.to_s]] end def redirect(location) @@ -68,7 +68,7 @@ end def json(payload) - [200, {"Content-Type" => "application/json", "Cache-Control" => "no-cache"}, [Sidekiq.dump_json(payload)]] + [200, {"Content-Type" => "application/json", "Cache-Control" => "private, no-store"}, [Sidekiq.dump_json(payload)]] end def initialize(env, block) diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/web/application.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/web/application.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/web/application.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/web/application.rb 2021-11-18 13:57:25.000000000 +0000 @@ -4,7 +4,6 @@ class WebApplication extend WebRouter - CONTENT_LENGTH = "Content-Length" REDIS_KEYS = %w[redis_version uptime_in_days connected_clients used_memory_human used_memory_peak_human] CSP_HEADER = [ "default-src 'self' https: http:", @@ -19,7 +18,7 @@ "script-src 'self' https: http: 'unsafe-inline'", "style-src 'self' https: http: 'unsafe-inline'", "worker-src 'self'", - "base-uri 'self'", + "base-uri 'self'" ].join("; ").freeze def initialize(klass) @@ -42,6 +41,13 @@ # nothing, backwards compatibility end + head "/" do + # HEAD / is the cheapest heartbeat possible, + # it hits Redis to ensure connectivity + Sidekiq.redis { |c| c.llen("queue:default") } + "" + end + get "/" do @redis_info = redis_info.select { |k, v| REDIS_KEYS.include? k } stats_history = Sidekiq::Stats::History.new((params["days"] || 30).to_i) @@ -76,15 +82,17 @@ erb(:queues) end + QUEUE_NAME = /\A[a-z_:.\-0-9]+\z/i + get "/queues/:name" do @name = route_params[:name] - halt(404) unless @name + halt(404) if !@name || @name !~ QUEUE_NAME @count = (params["count"] || 25).to_i @queue = Sidekiq::Queue.new(@name) - (@current_page, @total_size, @messages) = page("queue:#{@name}", params["page"], @count, reverse: params["direction"] == "asc") - @messages = @messages.map { |msg| Sidekiq::Job.new(msg, @name) } + (@current_page, @total_size, @jobs) = page("queue:#{@name}", params["page"], @count, reverse: params["direction"] == "asc") + @jobs = @jobs.map { |msg| Sidekiq::JobRecord.new(msg, @name) } erb(:queue) end @@ -105,7 +113,7 @@ post "/queues/:name/delete" do name = route_params[:name] - Sidekiq::Job.new(params["key_val"], name).delete + Sidekiq::JobRecord.new(params["key_val"], name).delete redirect_with_query("#{root_path}queues/#{CGI.escape(name)}") end @@ -275,7 +283,7 @@ scheduled: sidekiq_stats.scheduled_size, retries: sidekiq_stats.retry_size, dead: sidekiq_stats.dead_size, - default_latency: sidekiq_stats.default_queue_latency, + default_latency: sidekiq_stats.default_queue_latency }, redis: redis_stats, server_utc_time: server_utc_time @@ -298,29 +306,25 @@ self.class.run_afters(app, action) end - resp = case resp + case resp when Array + # redirects go here resp else + # rendered content goes here headers = { "Content-Type" => "text/html", - "Cache-Control" => "no-cache", + "Cache-Control" => "private, no-store", "Content-Language" => action.locale, - "Content-Security-Policy" => CSP_HEADER, + "Content-Security-Policy" => CSP_HEADER } - + # we'll let Rack calculate Content-Length for us. [200, headers, [resp]] end - - resp[1] = resp[1].dup - - resp[1][CONTENT_LENGTH] = resp[2].sum(&:bytesize).to_s - - resp end def self.helpers(mod = nil, &block) - if block_given? + if block WebAction.class_eval(&block) else WebAction.send(:include, mod) diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/web/csrf_protection.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/web/csrf_protection.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/web/csrf_protection.rb 1970-01-01 00:00:00.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/web/csrf_protection.rb 2021-11-18 13:57:25.000000000 +0000 @@ -0,0 +1,180 @@ +# frozen_string_literal: true + +# this file originally based on authenticity_token.rb from the sinatra/rack-protection project +# +# The MIT License (MIT) +# +# Copyright (c) 2011-2017 Konstantin Haase +# Copyright (c) 2015-2017 Zachary Scott +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# 'Software'), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, +# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE +# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +require "securerandom" +require "base64" +require "rack/request" + +module Sidekiq + class Web + class CsrfProtection + def initialize(app, options = nil) + @app = app + end + + def call(env) + accept?(env) ? admit(env) : deny(env) + end + + private + + def admit(env) + # On each successful request, we create a fresh masked token + # which will be used in any forms rendered for this request. + s = session(env) + s[:csrf] ||= SecureRandom.base64(TOKEN_LENGTH) + env[:csrf_token] = mask_token(s[:csrf]) + @app.call(env) + end + + def safe?(env) + %w[GET HEAD OPTIONS TRACE].include? env["REQUEST_METHOD"] + end + + def logger(env) + @logger ||= (env["rack.logger"] || ::Logger.new(env["rack.errors"])) + end + + def deny(env) + logger(env).warn "attack prevented by #{self.class}" + [403, {"Content-Type" => "text/plain"}, ["Forbidden"]] + end + + def session(env) + env["rack.session"] || fail(<<~EOM) + Sidekiq::Web needs a valid Rack session for CSRF protection. If this is a Rails app, + make sure you mount Sidekiq::Web *inside* your application routes: + + + Rails.application.routes.draw do + mount Sidekiq::Web => "/sidekiq" + .... + end + + + If this is a Rails app in API mode, you need to enable sessions. + + https://guides.rubyonrails.org/api_app.html#using-session-middlewares + + If this is a bare Rack app, use a session middleware before Sidekiq::Web: + + # first, use IRB to create a shared secret key for sessions and commit it + require 'securerandom'; File.open(".session.key", "w") {|f| f.write(SecureRandom.hex(32)) } + + # now use the secret with a session cookie middleware + use Rack::Session::Cookie, secret: File.read(".session.key"), same_site: true, max_age: 86400 + run Sidekiq::Web + + EOM + end + + def accept?(env) + return true if safe?(env) + + giventoken = ::Rack::Request.new(env).params["authenticity_token"] + valid_token?(env, giventoken) + end + + TOKEN_LENGTH = 32 + + # Checks that the token given to us as a parameter matches + # the token stored in the session. + def valid_token?(env, giventoken) + return false if giventoken.nil? || giventoken.empty? + + begin + token = decode_token(giventoken) + rescue ArgumentError # client input is invalid + return false + end + + sess = session(env) + localtoken = sess[:csrf] + + # Checks that Rack::Session::Cookie actualy contains the csrf toekn + return false if localtoken.nil? + + # Rotate the session token after every use + sess[:csrf] = SecureRandom.base64(TOKEN_LENGTH) + + # See if it's actually a masked token or not. We should be able + # to handle any unmasked tokens that we've issued without error. + + if unmasked_token?(token) + compare_with_real_token token, localtoken + elsif masked_token?(token) + unmasked = unmask_token(token) + compare_with_real_token unmasked, localtoken + else + false # Token is malformed + end + end + + # Creates a masked version of the authenticity token that varies + # on each request. The masking is used to mitigate SSL attacks + # like BREACH. + def mask_token(token) + token = decode_token(token) + one_time_pad = SecureRandom.random_bytes(token.length) + encrypted_token = xor_byte_strings(one_time_pad, token) + masked_token = one_time_pad + encrypted_token + Base64.strict_encode64(masked_token) + end + + # Essentially the inverse of +mask_token+. + def unmask_token(masked_token) + # Split the token into the one-time pad and the encrypted + # value and decrypt it + token_length = masked_token.length / 2 + one_time_pad = masked_token[0...token_length] + encrypted_token = masked_token[token_length..-1] + xor_byte_strings(one_time_pad, encrypted_token) + end + + def unmasked_token?(token) + token.length == TOKEN_LENGTH + end + + def masked_token?(token) + token.length == TOKEN_LENGTH * 2 + end + + def compare_with_real_token(token, local) + ::Rack::Utils.secure_compare(token.to_s, decode_token(local).to_s) + end + + def decode_token(token) + Base64.strict_decode64(token) + end + + def xor_byte_strings(s1, s2) + s1.bytes.zip(s2.bytes).map { |(c1, c2)| c1 ^ c2 }.pack("c*") + end + end + end +end diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/web/helpers.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/web/helpers.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/web/helpers.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/web/helpers.rb 2021-11-18 13:57:25.000000000 +0000 @@ -10,18 +10,25 @@ module WebHelpers def strings(lang) @strings ||= {} - @strings[lang] ||= begin - # Allow sidekiq-web extensions to add locale paths - # so extensions can be localized - settings.locales.each_with_object({}) do |path, global| - find_locale_files(lang).each do |file| - strs = YAML.load(File.open(file)) - global.merge!(strs[lang]) - end + + # Allow sidekiq-web extensions to add locale paths + # so extensions can be localized + @strings[lang] ||= settings.locales.each_with_object({}) do |path, global| + find_locale_files(lang).each do |file| + strs = YAML.load(File.open(file)) + global.merge!(strs[lang]) end end end + def singularize(str, count) + if count == 1 && str.respond_to?(:singularize) # rails + str.singularize + else + str + end + end + def clear_caches @strings = nil @locale_files = nil @@ -63,17 +70,6 @@ @head_html.join if defined?(@head_html) end - def poll_path - if current_path != "" && params["poll"] - path = root_path + current_path - query_string = to_query_string(params.slice(*params.keys - %w[page poll])) - path += "?#{query_string}" unless query_string.empty? - path - else - "" - end - end - def text_direction get_locale["TextDirection"] || "ltr" end @@ -118,7 +114,7 @@ # within is used by Sidekiq Pro def display_tags(job, within = nil) job.tags.map { |tag| - "#{::Rack::Utils.escape_html(tag)}" + "#{::Rack::Utils.escape_html(tag)}" }.join(" ") end @@ -158,8 +154,7 @@ def redis_connection Sidekiq.redis do |conn| - c = conn.connection - "redis://#{c[:location]}/#{c[:db]}" + conn.connection[:id] end end @@ -197,16 +192,13 @@ [score.to_f, jid] end - SAFE_QPARAMS = %w[page poll direction] + SAFE_QPARAMS = %w[page direction] # Merge options with current params, filter safe params, and stringify to query string def qparams(options) - # stringify - options.keys.each do |key| - options[key.to_s] = options.delete(key) - end + stringified_options = options.transform_keys(&:to_s) - to_query_string(params.merge(options)) + to_query_string(params.merge(stringified_options)) end def to_query_string(params) @@ -233,7 +225,7 @@ end def csrf_tag - "" + "" end def to_display(arg) @@ -261,7 +253,21 @@ end end + def format_memory(rss_kb) + return "0" if rss_kb.nil? || rss_kb == 0 + + if rss_kb < 100_000 + "#{number_with_delimiter(rss_kb)} KB" + elsif rss_kb < 10_000_000 + "#{number_with_delimiter((rss_kb / 1024.0).to_i)} MB" + else + "#{number_with_delimiter((rss_kb / (1024.0 * 1024.0)).round(1))} GB" + end + end + def number_with_delimiter(number) + return "" if number.nil? + begin Float(number) rescue ArgumentError, TypeError @@ -295,7 +301,7 @@ end def environment_title_prefix - environment = Sidekiq.options[:environment] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development" + environment = Sidekiq.options[:environment] || ENV["APP_ENV"] || ENV["RAILS_ENV"] || ENV["RACK_ENV"] || "development" "[#{environment.upcase}] " unless environment == "production" end diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/web/router.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/web/router.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/web/router.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/web/router.rb 2021-11-18 13:57:25.000000000 +0000 @@ -15,6 +15,10 @@ REQUEST_METHOD = "REQUEST_METHOD" PATH_INFO = "PATH_INFO" + def head(path, &block) + route(HEAD, path, &block) + end + def get(path, &block) route(GET, path, &block) end @@ -39,7 +43,6 @@ @routes ||= {GET => [], POST => [], PUT => [], PATCH => [], DELETE => [], HEAD => []} @routes[method] << WebRoute.new(method, path, block) - @routes[HEAD] << WebRoute.new(method, path, block) if method == GET end def match(env) @@ -66,7 +69,7 @@ class WebRoute attr_accessor :request_method, :pattern, :block, :name - NAMED_SEGMENTS_PATTERN = /\/([^\/]*):([^\.:$\/]+)/ + NAMED_SEGMENTS_PATTERN = /\/([^\/]*):([^.:$\/]+)/ def initialize(request_method, pattern, block) @request_method = request_method @@ -94,9 +97,7 @@ {} if path == matcher else path_match = path.match(matcher) - if path_match - Hash[path_match.names.map(&:to_sym).zip(path_match.captures)] - end + path_match&.named_captures&.transform_keys(&:to_sym) end end end diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/web.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/web.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/web.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/web.rb 2021-11-18 13:57:25.000000000 +0000 @@ -10,12 +10,11 @@ require "sidekiq/web/router" require "sidekiq/web/action" require "sidekiq/web/application" +require "sidekiq/web/csrf_protection" -require "rack/protection" - +require "rack/content_length" require "rack/builder" -require "rack/file" -require "rack/session/cookie" +require "rack/static" module Sidekiq class Web @@ -31,7 +30,7 @@ "Queues" => "queues", "Retries" => "retries", "Scheduled" => "scheduled", - "Dead" => "morgue", + "Dead" => "morgue" } class << self @@ -39,14 +38,6 @@ self end - def middlewares - @middlewares ||= [] - end - - def use(*middleware_args, &block) - middlewares << [middleware_args, block] - end - def default_tabs DEFAULT_TABS end @@ -72,32 +63,45 @@ opts.each { |key| set(key, false) } end - # Helper for the Sinatra syntax: Sidekiq::Web.set(:session_secret, Rails.application.secrets...) + def middlewares + @middlewares ||= [] + end + + def use(*args, &block) + middlewares << [args, block] + end + def set(attribute, value) send(:"#{attribute}=", value) end - attr_accessor :app_url, :session_secret, :redis_pool, :sessions + def sessions=(val) + puts "WARNING: Sidekiq::Web.sessions= is no longer relevant and will be removed in Sidekiq 7.0. #{caller(1..1).first}" + end + + def session_secret=(val) + puts "WARNING: Sidekiq::Web.session_secret= is no longer relevant and will be removed in Sidekiq 7.0. #{caller(1..1).first}" + end + + attr_accessor :app_url, :redis_pool attr_writer :locales, :views end def self.inherited(child) child.app_url = app_url - child.session_secret = session_secret child.redis_pool = redis_pool - child.sessions = sessions end def settings self.class.settings end - def use(*middleware_args, &block) - middlewares << [middleware_args, block] + def middlewares + @middlewares ||= self.class.middlewares end - def middlewares - @middlewares ||= Web.middlewares.dup + def use(*args, &block) + middlewares << [args, block] end def call(env) @@ -125,18 +129,8 @@ send(:"#{attribute}=", value) end - # Default values - set :sessions, true - - attr_writer :sessions - - def sessions - unless instance_variable_defined?("@sessions") - @sessions = self.class.sessions - @sessions = @sessions.to_hash.dup if @sessions.respond_to?(:to_hash) - end - - @sessions + def sessions=(val) + puts "Sidekiq::Web#sessions= is no longer relevant and will be removed in Sidekiq 7.0. #{caller[2..2].first}" end def self.register(extension) @@ -145,50 +139,20 @@ private - def using?(middleware) - middlewares.any? do |(m, _)| - m.is_a?(Array) && (m[0] == middleware || m[0].is_a?(middleware)) - end - end - - def build_sessions - middlewares = self.middlewares - - unless using?(::Rack::Protection) || ENV["RACK_ENV"] == "test" - middlewares.unshift [[::Rack::Protection, {use: :authenticity_token}], nil] - end - - s = sessions - return unless s - - unless using? ::Rack::Session::Cookie - unless (secret = Web.session_secret) - require "securerandom" - secret = SecureRandom.hex(64) - end - - options = {secret: secret} - options = options.merge(s.to_hash) if s.respond_to? :to_hash - - middlewares.unshift [[::Rack::Session::Cookie, options], nil] - end - end - def build - build_sessions - - middlewares = self.middlewares klass = self.class + m = middlewares - ::Rack::Builder.new do - %w[stylesheets javascripts images].each do |asset_dir| - map "/#{asset_dir}" do - run ::Rack::File.new("#{ASSETS}/#{asset_dir}", {"Cache-Control" => "public, max-age=86400"}) - end - end - - middlewares.each { |middleware, block| use(*middleware, &block) } + rules = [] + rules = [[:all, {"Cache-Control" => "public, max-age=86400"}]] unless ENV["SIDEKIQ_WEB_TESTING"] + ::Rack::Builder.new do + use Rack::Static, urls: ["/stylesheets", "/images", "/javascripts"], + root: ASSETS, + cascade: true, + header_rules: rules + m.each { |middleware, block| use(*middleware, &block) } + use Sidekiq::Web::CsrfProtection unless $TESTING run WebApplication.new(klass) end end diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/worker.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/worker.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq/worker.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq/worker.rb 2021-11-18 13:57:25.000000000 +0000 @@ -9,6 +9,7 @@ # # class HardWorker # include Sidekiq::Worker + # sidekiq_options queue: 'critical', retry: 5 # # def perform(*args) # # do some work @@ -20,6 +21,26 @@ # HardWorker.perform_async(1, 2, 3) # # Note that perform_async is a class method, perform is an instance method. + # + # Sidekiq::Worker also includes several APIs to provide compatibility with + # ActiveJob. + # + # class SomeWorker + # include Sidekiq::Worker + # queue_as :critical + # + # def perform(...) + # end + # end + # + # SomeWorker.set(wait_until: 1.hour).perform_async(123) + # + # Note that arguments passed to the job must still obey Sidekiq's + # best practice for simple, JSON-native data types. Sidekiq will not + # implement ActiveJob's more complex argument serialization. For + # this reason, we don't implement `perform_later` as our call semantics + # are very different. + # module Worker ## # The Options module is extracted so we can include it in ActiveJob::Base @@ -48,8 +69,8 @@ # In practice, any option is allowed. This is the main mechanism to configure the # options for a specific job. def sidekiq_options(opts = {}) - opts = Hash[opts.map { |k, v| [k.to_s, v] }] # stringify - self.sidekiq_options_hash = get_sidekiq_options.merge(Hash[opts.map { |k, v| [k.to_s, v] }]) + opts = opts.transform_keys(&:to_s) # stringify + self.sidekiq_options_hash = get_sidekiq_options.merge(opts) end def sidekiq_retry_in(&block) @@ -153,10 +174,16 @@ def initialize(klass, opts) @klass = klass @opts = opts + + # ActiveJob compatibility + interval = @opts.delete(:wait_until) || @opts.delete(:wait) + at(interval) if interval end def set(options) + interval = options.delete(:wait_until) || options.delete(:wait) @opts.merge!(options) + at(interval) if interval self end @@ -164,19 +191,29 @@ @klass.client_push(@opts.merge("args" => args, "class" => @klass)) end + def perform_bulk(args, batch_size: 1_000) + args.each_slice(batch_size).flat_map do |slice| + Sidekiq::Client.push_bulk(@opts.merge("class" => @klass, "args" => slice)) + end + end + # +interval+ must be a timestamp, numeric or something that acts # numeric (like an activesupport time interval). def perform_in(interval, *args) + at(interval).perform_async(*args) + end + alias_method :perform_at, :perform_in + + private + + def at(interval) int = interval.to_f now = Time.now.to_f ts = (int < 1_000_000_000 ? now + int : int) - - payload = @opts.merge("class" => @klass, "args" => args) # Optimization to enqueue something now that is scheduled to go out now or in the past - payload["at"] = ts if ts > now - @klass.client_push(payload) + @opts["at"] = ts if ts > now + self end - alias_method :perform_at, :perform_in end module ClassMethods @@ -192,6 +229,10 @@ raise ArgumentError, "Do not call .delay_until on a Sidekiq::Worker class, call .perform_at" end + def queue_as(q) + sidekiq_options("queue" => q.to_s) + end + def set(options) Setter.new(self, options) end @@ -200,6 +241,32 @@ client_push("class" => self, "args" => args) end + ## + # Push a large number of jobs to Redis, while limiting the batch of + # each job payload to 1,000. This method helps cut down on the number + # of round trips to Redis, which can increase the performance of enqueueing + # large numbers of jobs. + # + # +items+ must be an Array of Arrays. + # + # For finer-grained control, use `Sidekiq::Client.push_bulk` directly. + # + # Example (3 Redis round trips): + # + # SomeWorker.perform_async(1) + # SomeWorker.perform_async(2) + # SomeWorker.perform_async(3) + # + # Would instead become (1 Redis round trip): + # + # SomeWorker.perform_bulk([[1], [2], [3]]) + # + def perform_bulk(items, batch_size: 1_000) + items.each_slice(batch_size).flat_map do |slice| + Sidekiq::Client.push_bulk("class" => self, "args" => slice) + end + end + # +interval+ must be a timestamp, numeric or something that acts # numeric (like an activesupport time interval). def perform_in(interval, *args) @@ -235,12 +302,9 @@ def client_push(item) # :nodoc: pool = Thread.current[:sidekiq_via_pool] || get_sidekiq_options["pool"] || Sidekiq.redis_pool - # stringify - item.keys.each do |key| - item[key.to_s] = item.delete(key) - end + stringified_item = item.transform_keys(&:to_s) - Sidekiq::Client.new(pool).push(item) + Sidekiq::Client.new(pool).push(stringified_item) end end end diff -Nru ruby-sidekiq-6.0.4+dfsg/lib/sidekiq.rb ruby-sidekiq-6.3.1+dfsg/lib/sidekiq.rb --- ruby-sidekiq-6.0.4+dfsg/lib/sidekiq.rb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/lib/sidekiq.rb 2021-11-18 13:57:25.000000000 +0000 @@ -6,6 +6,7 @@ require "sidekiq/logger" require "sidekiq/client" require "sidekiq/worker" +require "sidekiq/job" require "sidekiq/redis_connection" require "sidekiq/delay" @@ -20,6 +21,7 @@ labels: [], concurrency: 10, require: ".", + strict: true, environment: nil, timeout: 25, poll_interval_average: nil, @@ -30,16 +32,16 @@ startup: [], quiet: [], shutdown: [], - heartbeat: [], + heartbeat: [] }, dead_max_jobs: 10_000, dead_timeout_in_seconds: 180 * 24 * 60 * 60, # 6 months - reloader: proc { |&block| block.call }, + reloader: proc { |&block| block.call } } DEFAULT_WORKER_OPTIONS = { "retry" => true, - "queue" => "default", + "queue" => "default" } FAKE_INFO = { @@ -47,7 +49,7 @@ "uptime_in_days" => "9999", "connected_clients" => "9999", "used_memory_human" => "9P", - "used_memory_peak_human" => "9P", + "used_memory_peak_human" => "9P" } def self.❨╯°□°❩╯︵┻━┻ @@ -95,10 +97,12 @@ retryable = true begin yield conn - rescue Redis::CommandError => ex + rescue Redis::BaseError => ex # 2550 Failover can cause the server to become a replica, need # to disconnect and reopen the socket to get back to the primary. - if retryable && ex.message =~ /READONLY/ + # 4495 Use the same logic if we have a "Not enough replicas" error from the primary + # 4985 Use the same logic when a blocking command is force-unblocked + if retryable && ex.message =~ /READONLY|NOREPLICAS|UNBLOCKED/ conn.disconnect! retryable = false retry @@ -154,7 +158,7 @@ def self.default_worker_options=(hash) # stringify - @default_worker_options = default_worker_options.merge(Hash[hash.map { |k, v| [k.to_s, v] }]) + @default_worker_options = default_worker_options.merge(hash.transform_keys(&:to_s)) end def self.default_worker_options @@ -196,7 +200,7 @@ end def self.logger - @logger ||= Sidekiq::Logger.new(STDOUT, level: Logger::INFO) + @logger ||= Sidekiq::Logger.new($stdout, level: Logger::INFO) end def self.logger=(logger) diff -Nru ruby-sidekiq-6.0.4+dfsg/LICENSE ruby-sidekiq-6.3.1+dfsg/LICENSE --- ruby-sidekiq-6.0.4+dfsg/LICENSE 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/LICENSE 2021-11-18 13:57:25.000000000 +0000 @@ -6,4 +6,4 @@ Sidekiq Pro has a commercial-friendly license allowing private forks and modifications of Sidekiq. Please see https://sidekiq.org/products/pro.html for -more detail. You can find the commercial license terms in COMM-LICENSE. +more detail. You can find the commercial license terms in COMM-LICENSE.txt. diff -Nru ruby-sidekiq-6.0.4+dfsg/Pro-2.0-Upgrade.md ruby-sidekiq-6.3.1+dfsg/Pro-2.0-Upgrade.md --- ruby-sidekiq-6.0.4+dfsg/Pro-2.0-Upgrade.md 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/Pro-2.0-Upgrade.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,138 +0,0 @@ -# Upgrading to Sidekiq Pro 2.0 - -Sidekiq Pro 2.0 allows nested batches for more complex job workflows -and provides a new reliable scheduler which uses Lua to guarantee -atomicity and much higher performance. - -It also removes deprecated APIs, changes the batch data format and -how features are activated. Read carefully to ensure your upgrade goes -smoothly. - -Sidekiq Pro 2.0 requires Sidekiq 3.3.2 or greater. Redis 2.8 is -recommended; Redis 2.4 or 2.6 will work but some functionality will not be -available. - -**Note that you CANNOT go back to Pro 1.x once you've created batches -with 2.x. The new batches will not process correctly with 1.x.** - -**If you are on a version of Sidekiq Pro <1.5, you should upgrade to the -latest 1.x version and run it for a week before upgrading to 2.0.** - -## Nested Batches - -Batches can now be nested within the `jobs` method. -This feature enables Sidekiq Pro to handle workflow processing of any size -and complexity! - -```ruby -a = Sidekiq::Batch.new -a.on(:success, SomeCallback) -a.jobs do - SomeWork.perform_async - - b = Sidekiq::Batch.new - b.on(:success, MyCallback) - b.jobs do - OtherWork.perform_async - end -end -``` - -Parent batch callbacks are not processed until all child batch callbacks have -run successfully. In the example above, `MyCallback` will always fire -before `SomeCallback` because `b` is considered a child of `a`. - -Of course you can dynamically add child batches while a batch job is executing. - -```ruby -def perform(*args) - do_something(args) - - if more_work? - # Sidekiq::Worker#batch returns the Batch this job is part of. - batch.jobs do - b = Sidekiq::Batch.new - b.on(:success, MyCallback) - b.jobs do - OtherWork.perform_async - end - end - end -end -``` - -More context: [#1485] - -## Batch Data - -The batch data model was overhauled. Batch data should take -significantly less space in Redis now. A simple benchmark shows 25% -savings but real world savings should be even greater. - -* Batch 2.x BIDs are 14 character URL-safe Base64-encoded strings, e.g. - "vTF1-9QvLPnREQ". Batch 1.x BIDs were 16 character hex-encoded - strings, e.g. "4a3fc67d30370edf". -* In 1.x, batch data was not removed until it naturally expired in Redis. - In 2.x, all data for a batch is removed from Redis once the batch has - run any success callbacks. -* Because of the former point, batch expiry is no longer a concern. - Batch expiry is hardcoded to 30 days and is no longer user-tunable. -* Failed batch jobs no longer automatically store any associated - backtrace in Redis. - -**There's no data migration required. Sidekiq Pro 2.0 transparently handles -both old and new format.** - -More context: [#2130] - -## Reliability - -2.0 brings a new reliable scheduler which uses Lua inside Redis so enqueuing -scheduled jobs is atomic. Benchmarks show it 50x faster when enqueuing -lots of jobs. - -**Two caveats**: -- Client-side middleware is not executed - for each job when enqueued with the reliable scheduler. No Sidekiq or - Sidekiq Pro functionality is affected by this change but some 3rd party - plugins might be. -- The Lua script used inside the reliable scheduler is not safe for use - with Redis Cluster or other multi-master Redis solutions. - It is safe to use with Redis Sentinel or a typical master/slave replication setup. - -**You no longer require anything to use the Reliability features.** - -* Activate reliable fetch and/or the new reliable scheduler: -```ruby -Sidekiq.configure_server do |config| - config.reliable_fetch! - config.reliable_scheduler! -end -``` -* Activate reliable push: -```ruby -Sidekiq::Client.reliable_push! -``` - -More context: [#2130] - -## Other Changes - -* You must require `sidekiq/pro/notifications` if you want to use the - existing notification schemes. I don't recommend using them as the - newer-style `Sidekiq::Batch#on` method is simpler and more flexible. -* Several classes have been renamed. Generally these classes are ones - you should not need to require/use in your own code, e.g. the Batch - middleware. -* You can add `attr_accessor :jid` to a Batch callback class and Sidekiq - Pro will set it to the jid of the callback job. [#2178] -* There's now an official API to iterate all known Batches [#2191] -```ruby -Sidekiq::BatchSet.new.each {|status| p status.bid } -``` -* The Web UI now shows the Sidekiq Pro version in the footer. [#1991] - -## Thanks - -Adam Prescott, Luke van der Hoeven and Jon Hyman all provided valuable -feedback during the release process. Thank you guys! diff -Nru ruby-sidekiq-6.0.4+dfsg/Pro-3.0-Upgrade.md ruby-sidekiq-6.3.1+dfsg/Pro-3.0-Upgrade.md --- ruby-sidekiq-6.0.4+dfsg/Pro-3.0-Upgrade.md 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/Pro-3.0-Upgrade.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,44 +0,0 @@ -# Welcome to Sidekiq Pro 3.0! - -Sidekiq Pro 3.0 is designed to work with Sidekiq 4.0. - -## What's New - -* **Redis 2.8.0 or greater is required.** Redis 2.8 was released two years - ago and contains **many** useful features which Sidekiq couldn't - leverage until now. **Redis 3.0.3 or greater is recommended** for large - scale use. - -* Sidekiq Pro no longer uses Celluloid. If your application code uses Celluloid, - you will need to pull it in yourself. - -* Pausing and unpausing queues is now instantaneous, no more polling! - -* Reliable fetch has been re-implemented due to the fetch changes in - Sidekiq 4.0. - -* Support for platforms without persistent hostnames. Since the reliable\_fetch - algorithm requires a persistent hostname, an alternative reliability -algorithm is now available for platforms like Heroku and Docker: -```ruby -Sidekiq.configure_server do |config| - config.timed_fetch! -end -``` - The wiki contains [much more detail about each reliability option](https://github.com/mperham/sidekiq/wiki/Pro-Reliability-Server). - -* The old 'sidekiq/notifications' features have been removed. - -## Upgrade - -First, make sure you are using Redis 2.8 or greater. Next: - -* Upgrade to the latest Sidekiq Pro 2.x. -```ruby -gem 'sidekiq-pro', '< 3' -``` -* Fix any deprecation warnings you see. -* Upgrade to 3.x. -```ruby -gem 'sidekiq-pro', '< 4' -``` diff -Nru ruby-sidekiq-6.0.4+dfsg/Pro-4.0-Upgrade.md ruby-sidekiq-6.3.1+dfsg/Pro-4.0-Upgrade.md --- ruby-sidekiq-6.0.4+dfsg/Pro-4.0-Upgrade.md 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/Pro-4.0-Upgrade.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,35 +0,0 @@ -# Welcome to Sidekiq Pro 4.0! - -Sidekiq Pro 4.0 is designed to work with Sidekiq 5.0. - -## What's New - -* Batches now "die" if any of their jobs die. You can enumerate the set - of dead batches and their associated dead jobs. The success callback - for a dead batch will never fire unless these jobs are fixed. -```ruby -Sidekiq::Batch::DeadSet.new.each do |status| - status.dead? # => true - status.dead_jobs # => [...] -end -``` -This API allows you to enumerate the batches which need help. -If you fix the issue and the dead jobs succeed, the batch will succeed. -* The older `reliable_fetch` and `timed_fetch` algorithms have been - removed. Only super\_fetch is available in 4.0. -* The statsd middleware has been tweaked to remove support for legacy, - pre-3.6.0 configuration and add relevant tags. -* Requires Sidekiq 5.0.5+. - -## Upgrade - -* Upgrade to the latest Sidekiq Pro 3.x. -```ruby -gem 'sidekiq-pro', '< 4' -``` -* Fix any deprecation warnings you see. -* Upgrade to 4.x. -```ruby -gem 'sidekiq-pro', '< 5' -``` - diff -Nru ruby-sidekiq-6.0.4+dfsg/Pro-5.0-Upgrade.md ruby-sidekiq-6.3.1+dfsg/Pro-5.0-Upgrade.md --- ruby-sidekiq-6.0.4+dfsg/Pro-5.0-Upgrade.md 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/Pro-5.0-Upgrade.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,25 +0,0 @@ -# Welcome to Sidekiq Pro 5.0! - -Sidekiq Pro 5.0 is mainly a cleanup release for Sidekiq 6.0. The -migration should be as close to trivial as a major version bump can be. -Note that Sidekiq 6.0 does have major breaking changes. - -## What's New - -* New localizations for the Sidekiq Pro Web UI: ES, ZH, PT, JA, RU -* Removed deprecated APIs and warnings. -* Various changes for Sidekiq 6.0 -* Requires Ruby 2.5+ and Redis 4.0+ -* Requires Sidekiq 6.0+. - -## Upgrade - -* Upgrade to the latest Sidekiq Pro 4.x. -```ruby -gem 'sidekiq-pro', '< 5' -``` -* Fix any deprecation warnings you see. -* Upgrade to 5.x. -```ruby -gem 'sidekiq-pro', '< 6' -``` diff -Nru ruby-sidekiq-6.0.4+dfsg/Pro-Changes.md ruby-sidekiq-6.3.1+dfsg/Pro-Changes.md --- ruby-sidekiq-6.0.4+dfsg/Pro-Changes.md 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/Pro-Changes.md 1970-01-01 00:00:00.000000000 +0000 @@ -1,776 +0,0 @@ -# Sidekiq Pro Changelog - -[Sidekiq Changes](https://github.com/mperham/sidekiq/blob/master/Changes.md) | [Sidekiq Pro Changes](https://github.com/mperham/sidekiq/blob/master/Pro-Changes.md) | [Sidekiq Enterprise Changes](https://github.com/mperham/sidekiq/blob/master/Ent-Changes.md) - -Please see [http://sidekiq.org/](http://sidekiq.org/) for more details and how to buy. - -5.0.1 ---------- - -- Rejigger batch failures UI to add direct links to retries and scheduled jobs [#4209] -- Delete batch data with `UNLINK` [#4155] -- Fix bug where a scheduled job can lose its scheduled time when using reliable push [#4267] -- Sidekiq::JobSet#scan and #find_job APIs have been promoted to Sidekiq OSS. [#4259] - -5.0.0 ---------- - -- There is no significant migration from Sidekiq Pro 4.0 to 5.0 - but make sure you read the [update notes for Sidekiq -6.0](https://github.com/mperham/sidekiq/blob/master/6.0-Upgrade.md). -- Removed various deprecated APIs and associated warnings. -- **BREAKING CHANGE** Remove the `Sidekiq::Batch::Status#dead_jobs` API in favor of - `Sidekiq::Batch::Status#dead_jids`. [#4217] -- Update Sidekiq Pro codebase to use StandardRB formatting -- Fix lingering "b-XXX-died" elements in Redis which could cause - excessive memory usage. [#4217] -- Add ES translations, see issues [#3949](https://github.com/mperham/sidekiq/issues/3949) and [#3951](https://github.com/mperham/sidekiq/issues/3951) to add your own language. - -4.0.5 ---------- - -- Increase super\_fetch retriever thread count from 1 to 2 to make it - less sensitive to Redis latency. -- Better handling of invalid job JSON by reliable scheduler [#4053] -- Added ZH, PT, JA and RU translations. - -4.0.4 ---------- - -- Update Sidekiq::Client patches to work with new Module#prepend - mechanism in Sidekiq 5.2.0. [#3930] - -4.0.3 ---------- - -- Add at\_exit handler to push any saved jobs in `reliable_push` when exiting. [#3823] -- Implement batch death callback. This is fired the first time a job within a batch dies. [#3841] -```ruby -batch = Sidekiq::Batch.new -batch.on(:death, ...) -``` - -4.0.2 ---------- - -- Remove super\_fetch edge case leading to an unnecessary `sleep(1)` - call and resulting latency [#3790] -- Fix possible bad statsd metric call on super\_fetch startup -- Remove superfluous `freeze` calls on Strings [#3759] - -4.0.1 ---------- - -- Fix incompatibility with the statsd-ruby gem [#3740] -- Add tags to Statsd metrics when using Datadog [#3744] - -4.0.0 ---------- - -- See the [Sidekiq Pro 4.0](Pro-4.0-Upgrade.md) release notes. - - -3.7.1 ---------- - -- Deprecate timed\_fetch. Switch to super\_fetch: -```ruby -config.super_fetch! -``` - - -3.7.0 ---------- - -- Refactor batch job success/failure to gracefully handle several edge - cases with regard to Sidekiq::Shutdown. This should greatly reduce - the chances of seeing the long-standing "negative pending count" problem. [#3710] - - -3.6.1 ---------- - -- Add support for Datadog::Statsd, it is the recommended Statsd client. [#3699] -```ruby -Sidekiq::Pro.dogstatsd = ->{ Datadog::Statsd.new("metrics.example.com", 8125) } -``` -- Size the statsd connection pool based on Sidekiq's concurrency [#3700] - - -3.6.0 ---------- - -This release overhauls the Statsd metrics support and adds more -metrics for tracking Pro feature usage. In your initializer: -```ruby -Sidekiq::Pro.statsd = ->{ ::Statsd.new("127.0.0.1", 8125) } -``` -Sidekiq Pro will emit more metrics to Statsd: -``` -jobs.expired - when a job is expired -jobs.recovered.push - when a job is recovered by reliable_push after network outage -jobs.recovered.fetch - when a job is recovered by super_fetch after process crash -batch.created - when a batch is created -batch.complete - when a batch is completed -batch.success - when a batch is successful -``` -Sidekiq Pro's existing Statsd middleware has been rewritten to leverage the new API. -Everything should be backwards compatible with one deprecation notice. - - -3.5.4 ---------- - -- Fix case in SuperFetch where Redis downtime can lead to processor thread death [#3684] -- Fix case where TimedFetch might not recover some pending jobs -- Fix edge case in Batch::Status#poll leading to premature completion [#3640] -- Adjust scan API to check 100 elements at a time, to minimize network round trips - when scanning large sets. - -3.5.3 ---------- - -- Restore error check for super\_fetch's job ack [#3601] -- Trim error messages saved in Batch's failure hash, preventing huge - messages from bloating Redis. [#3570] - -3.5.2 ---------- - -- Fix `Status#completed?` when run against a Batch that had succeeded - and was deleted. [#3519] - -3.5.1 ---------- - -- Work with Sidekiq 5.0.2+ -- Improve performance of super\_fetch with weighted queues [#3489] - -3.5.0 ---------- - -- Add queue pause/unpause endpoints for scripting via curl [#3445] -- Change how super\_fetch names private queues to avoid hostname/queue clashes. [#3443] -- Re-implement `Sidekiq::Queue#delete_job` to avoid O(n) runtime [#3408] -- Batch page displays Pending JIDs if less than 10 [#3130] -- Batch page has a Search button to find associated Retries [#3130] -- Make Batch UI progress bar more friendly to the colorblind [#3387] - -3.4.5 ---------- - -- Fix potential job loss with reliable scheduler when lots of jobs are scheduled - at precisely the same time. Thanks to raivil for his hard work in - reproducing the bug. [#3371] - -3.4.4 ---------- - -- Optimize super\_fetch shutdown to restart jobs quicker [#3249] - -3.4.3 ---------- - -- Limit reliable scheduler to enqueue up to 100 jobs per call, minimizing Redis latency [#3332] -- Fix bug in super\_fetch logic for queues with `_` in the name [#3339] - -3.4.2 ---------- - -- Add `Batch::Status#invalidated?` API which returns true if any/all - JIDs were invalidated within the batch. [#3326] - -3.4.1 ---------- - -- Allow super\_fetch's orphan job check to happen as often as every hour [#3273] -- Officially deprecate reliable\_fetch algorithm, I now recommend you use `super_fetch` instead: -```ruby -Sidekiq.configure_server do |config| - config.super_fetch! -end -``` -Also note that Sidekiq's `-i/--index` option is no longer used/relevant with super\_fetch. -- Don't display "Delete/Retry All" buttons when filtering in Web UI [#3243] -- Reimplement Sidekiq::JobSet#find\_job with ZSCAN [#3197] - -3.4.0 ---------- - -- Introducing the newest reliable fetching algorithm: `super_fetch`! This - algorithm will replace reliable\_fetch in Pro 4.0. super\_fetch is - bullet-proof across all environments, no longer requiring stable - hostnames or an index to be set per-process. [#3077] -```ruby -Sidekiq.configure_server do |config| - config.super_fetch! -end -``` - Thank you to @jonhyman for code review and the Sidekiq Pro customers that - beta tested super\_fetch. - -3.3.3 ---------- - -- Update Web UI extension to work with Sidekiq 4.2.0's new Web UI. [#3075] - -3.3.2 ---------- - -- Minimize batch memory usage after success [#3083] -- Extract batch's 24 hr linger expiry to a LINGER constant so it can be tuned. [#3011] - -3.3.1 ---------- - -- If environment is unset, treat it as development so reliable\_fetch works as before 3.2.2. - -3.3.0 ---------- - -- Don't delete batches immediately upon success but set a 24 hr expiry, this allows - Sidekiq::Batch::Status#poll to work, even after batch success. [#3011] -- New `Sidekiq::PendingSet#destroy(jid)` API to remove poison pill jobs [#3015] - -3.2.2 ---------- - -- A default value for -i is only set in development now, staging or - other environments must set an index if you wish to use reliable\_fetch. [#2971] -- Fix nil dereference when checking for jobs over timeout in timed\_fetch - - -3.2.1 ---------- - -- timed\_fetch now works with namespaces. [ryansch] - - -3.2.0 ---------- - -- Fixed detection of missing batches, `NoSuchBatch` should be raised - properly now if `Sidekiq::Batch.new(bid)` is called on a batch no - longer in Redis. -- Remove support for Pro 1.x format batches. This version will no - longer seamlessly process batches created with Sidekiq Pro 1.x. - As always, upgrade one major version at a time to ensure a smooth - transition. -- Fix edge case where a parent batch could expire before a child batch - was finished processing, leading to missing batches [#2889] - -2.1.5 ---------- - -- Fix edge case where a parent batch could expire before a child batch - was finished processing, leading to missing batches [#2889] - -3.1.0 ---------- - -- New container-friendly fetch algorithm: `timed_fetch`. See the - [wiki documentation](https://github.com/mperham/sidekiq/wiki/Pro-Reliability-Server) - for trade offs between the two reliability options. You should - use this if you are on Heroku, Docker, Amazon ECS or EBS or - another container-based system. - - -3.0.6 ---------- - -- Fix race condition on reliable fetch shutdown - -3.0.5 ---------- - -- Statsd metrics now account for ActiveJob class names -- Allow reliable fetch internals to be overridden [jonhyman] - -3.0.4 ---------- - -- Queue pausing no longer requires reliable fetch. [#2786] - -3.0.3, 2.1.4 ------------- - -- Convert Lua-based `Sidekiq::Queue#delete_by_class` to Ruby-based, to - avoid O(N^2) performance and possible Redis failure. [#2806] - -3.0.2 ------------ - -- Make job registration with batch part of the atomic push so batch - metadata can't get out of sync with the job data. [#2714] - -3.0.1 ------------ - -- Remove a number of Redis version checks since we can assume 2.8+ now. -- Fix expiring jobs client middleware not loaded on server - -3.0.0 ------------ - -- See the [Pro 3.0 release notes](Pro-3.0-Upgrade.md). - -2.1.3 ------------ - -- Don't enable strict priority if using weighted queueing like `-q a,1 -q b,1` -- Safer JSON mangling in Lua [#2639] - -2.1.2 ------------ - -- Lock Sidekiq Pro 2.x to Sidekiq 3.x. - -2.1.1 ------------ - -- Make ShardSet lazier so Redis can first be initialized at startup. [#2603] - - -2.1.0 ------------ - -- Explicit support for sharding batches. You list your Redis shards and - Sidekiq Pro will randomly spread batches across the shards. The BID - will indicate which shard contains the batch data. Jobs within a - batch may be spread across all shards too. [#2548, jonhyman] -- Officially deprecate Sidekiq::Notifications code. Notifications have - been undocumented for months now. [#2575] - - -2.0.8 ------------ - -- Fix reliable scheduler mangling large numeric arguments. Lua's CJSON - library cannot accurately encode numbers larger than 14 digits! [#2478] - -2.0.7 ------------ - -- Optimize delete of enormous batches (100,000s of jobs) [#2458] - -2.0.6, 1.9.3 --------------- - -- CSRF protection in Sidekiq 3.4.2 broke job filtering in the Web UI [#2442] -- Sidekiq Pro 1.x is now limited to Sidekiq < 3.5.0. - -2.0.5 ------------ - -- Atomic scheduler now sets `enqueued_at` [#2414] -- Batches now account for jobs which are stopped by client middleware [#2406] -- Ignore redundant calls to `Sidekiq::Client.reliable_push!` [#2408] - -2.0.4 ------------ - -- Reliable push now supports sharding [#2409] -- Reliable push now only catches Redis exceptions [#2307] - -2.0.3 ------------ - -- Display Batch callback data on the Batch details page. [#2347] -- Fix incompatibility with Pro Web and Rack middleware. [#2344] Thank - you to Jason Clark for the tip on how to fix it. - -2.0.2 ------------ - -- Multiple Web UIs can now run in the same process. [#2267] If you have - multiple Redis shards, you can mount UIs for all in the same process: -```ruby -POOL1 = ConnectionPool.new { Redis.new(:url => "redis://localhost:6379/0") } -POOL2 = ConnectionPool.new { Redis.new(:url => "redis://localhost:6378/0") } - -mount Sidekiq::Pro::Web => '/sidekiq' # default -mount Sidekiq::Pro::Web.with(redis_pool: POOL1), at: '/sidekiq1', as: 'sidekiq1' # shard1 -mount Sidekiq::Pro::Web.with(redis_pool: POOL2), at: '/sidekiq2', as: 'sidekiq2' # shard2 -``` -- **SECURITY** Fix batch XSS in error data. Thanks to moneybird.com for - reporting the issue. - -2.0.1 ------------ - -- Add `batch.callback_queue` so batch callbacks can use a higher - priority queue than jobs. [#2200] -- Gracefully recover if someone runs `SCRIPT FLUSH` on Redis. [#2240] -- Ignore errors when attempting `bulk_requeue`, allowing clean shutdown - -2.0.0 ------------ - -- See [the Upgrade Notes](Pro-2.0-Upgrade.md) for detailed notes. - -1.9.2 ------------ - -- As of 1/1/2015, Sidekiq Pro is hosted on a new dedicated server. - Happy new year and let's hope for 100% uptime! -- Fix bug in reliable\_fetch where jobs could be duplicated if a Sidekiq - process crashed and you were using weighted queues. [#2120] - -1.9.1 ------------ - -- **SECURITY** Fix XSS in batch description, thanks to intercom.io for reporting the - issue. If you don't use batch descriptions, you don't need the fix. - -1.9.0 ------------ - -- Add new expiring jobs feature [#1982] -- Show batch expiration on Batch details page [#1981] -- Add '$' batch success token to the pubsub support. [#1953] - - -1.8.0 ------------ - -- Fix race condition where Batches can complete - before they have been fully defined or only half-defined. Requires - Sidekiq 3.2.3. [#1919] - - -1.7.6 ------------ - -- Quick release to verify #1919 - - -1.7.5 ------------ - -- Fix job filtering within the Dead tab. -- Add APIs and wiki documentation for invalidating jobs within a batch. - - -1.7.4 ------------ - -- Awesome ANSI art startup banner! - - -1.7.3 ------------ - -- Batch callbacks should use the same queue as the associated jobs. - -1.7.2 ------------ - -- **DEPRECATION** Use `Batch#on(:complete)` instead of `Batch#notify`. - The specific Campfire, HipChat, email and other notification schemes - will be removed in 2.0.0. -- Remove batch from UI when successful. [#1745] -- Convert batch callbacks to be asynchronous jobs for error handling [#1744] - -1.7.1 ------------ - -- Fix for paused queues being processed for a few seconds when starting - a new Sidekiq process. -- Add a 5 sec delay when starting reliable fetch on Heroku to minimize - any duplicate job processing with another process shutting down. - -1.7.0 ------------ - -- Add ability to pause reliable queues via API. -```ruby -q = Sidekiq::Queue.new("critical") -q.pause! -q.paused? # => true -q.unpause! -``` - -Sidekiq polls Redis every 10 seconds for paused queues so pausing will take -a few seconds to take effect. - -1.6.0 ------------ - -- Compatible with Sidekiq 3. - -1.5.1 ------------ - -- Due to a breaking API change in Sidekiq 3.0, this version is limited - to Sidekiq 2.x. - -1.5.0 ------------ - -- Fix issue on Heroku where reliable fetch could orphan jobs [#1573] - - -1.4.3 ------------ - -- Reverse sorting of Batches in Web UI [#1098] -- Refactoring for Sidekiq 3.0, Pro now requires Sidekiq 2.17.5 - -1.4.2 ------------ - -- Tolerate expired Batches in the web UI. -- Fix 100% CPU usage when using weighted queues and reliable fetch. - -1.4.1 ------------ - -- Add batch progress bar to batch detail page. [#1398] -- Fix race condition in initializing Lua scripts - - -1.4.0 ------------ - -- Default batch expiration has been extended to 3 days, from 1 day previously. -- Batches now sort in the Web UI according to expiry time, not creation time. -- Add user-configurable batch expiry. If your batches might take longer - than 72 hours to process, you can extend the expiration date. - -```ruby -b = Sidekiq::Batch.new -b.expires_in 5.days -... -``` - -1.3.2 ------------ - -- Lazy load Lua scripts so a Redis connection is not required on bootup. - -1.3.1 ------------ - -- Fix a gemspec packaging issue which broke the Batch UI. - -1.3.0 ------------ - -Thanks to @jonhyman for his contributions to this Sidekiq Pro release. - -This release includes new functionality based on the SCAN command newly -added to Redis 2.8. Pro still works with Redis 2.4 but some -functionality will be unavailable. - -- Job Filtering in the Web UI! - You can now filter retries and scheduled jobs in the Web UI so you - only see the jobs relevant to your needs. Queues cannot be filtered; - Redis does not provide the same SCAN operation on the LIST type. - **Redis 2.8** - ![Filtering](https://f.cloud.github.com/assets/2911/1619465/f47529f2-5657-11e3-8cd1-33899eb72aad.png) -- SCAN support in the Sidekiq::SortedSet API. Here's an example that - finds all jobs which contain the substring "Warehouse::OrderShip" - and deletes all matching retries. If the set is large, this API - will be **MUCH** faster than standard iteration using each. - **Redis 2.8** -```ruby - Sidekiq::RetrySet.new.scan("Warehouse::OrderShip") do |job| - job.delete - end -``` - -- Sidekiq::Batch#jobs now returns the set of JIDs added to the batch. -- Sidekiq::Batch#jids returns the complete set of JIDs associated with the batch. -- Sidekiq::Batch#remove\_jobs(jid, jid, ...) removes JIDs from the set, allowing early termination of jobs if they become irrelevant according to application logic. -- Sidekiq::Batch#include?(jid) allows jobs to check if they are still - relevant to a Batch and exit early if not. -- Sidekiq::SortedSet#find\_job(jid) now uses server-side Lua if possible **Redis 2.6** [jonhyman] -- The statsd integration now sets global job counts: -```ruby - jobs.count - jobs.success - jobs.failure -``` - -- Change shutdown logic to push leftover jobs in the private queue back - into the public queue when shutting down with Reliable Fetch. This - allows the safe decommission of a Sidekiq Pro process when autoscaling. [jonhyman] -- Add support for weighted random fetching with Reliable Fetch [jonhyman] -- Pro now requires Sidekiq 2.17.0 - -1.2.5 ------------ - -- Convert Batch UI to use Sidekiq 2.16's support for extension localization. -- Update reliable\_push to work with Sidekiq::Client refactoring in 2.16 -- Pro now requires Sidekiq 2.16.0 - -1.2.4 ------------ - -- Convert Batch UI to Bootstrap 3 -- Pro now requires Sidekiq 2.15.0 -- Add Sidekiq::Batch::Status#delete [#1205] - -1.2.3 ------------ - -- Pro now requires Sidekiq 2.14.0 -- Fix bad exception handling in batch callbacks [#1134] -- Convert Batch UI to ERB - -1.2.2 ------------ - -- Problem with reliable fetch which could lead to lost jobs when Sidekiq - is shut down normally. Thanks to MikaelAmborn for the report. [#1109] - -1.2.1 ------------ - -- Forgot to push paging code necessary for `delete_job` performance. - -1.2.0 ------------ - -- **LEAK** Fix batch key which didn't expire in Redis. Keys match - /b-[a-f0-9]{16}-pending/, e.g. "b-4f55163ddba10aa0-pending" [#1057] -- **Reliable fetch now supports multiple queues**, using the algorithm spec'd - by @jackrg [#1102] -- Fix issue with reliable\_push where it didn't return the JID for a pushed - job when sending previously cached jobs to Redis. -- Add fast Sidekiq::Queue#delete\_job(jid) API which leverages Lua so job lookup is - 100% server-side. Benchmark vs Sidekiq's Job#delete API. **Redis 2.6** - -``` -Sidekiq Pro API - 0.030000 0.020000 0.050000 ( 1.640659) -Sidekiq API - 17.250000 2.220000 19.470000 ( 22.193300) -``` - -- Add fast Sidekiq::Queue#delete\_by\_class(klass) API to remove all - jobs of a given type. Uses server-side Lua for performance. **Redis 2.6** - -1.1.0 ------------ - -- New `sidekiq/pro/reliable_push` which makes Sidekiq::Client resiliant - to Redis network failures. [#793] -- Move `sidekiq/reliable_fetch` to `sidekiq/pro/reliable_fetch` - - -1.0.0 ------------ - -- Sidekiq Pro changelog moved to mperham/sidekiq for public visibility. -- Add new Rack endpoint for easy polling of batch status via JavaScript. See `sidekiq/rack/batch_status` - -0.9.3 ------------ - -- Fix bad /batches path in Web UI -- Fix Sinatra conflict with sidekiq-failures - -0.9.2 ------------ - -- Fix issue with lifecycle notifications not firing. - -0.9.1 ------------ - -- Update due to Sidekiq API changes. - -0.9.0 ------------ - -- Rearchitect Sidekiq's Fetch code to support different fetch -strategies. Add a ReliableFetch strategy which works with Redis' -RPOPLPUSH to ensure we don't lose messages, even when the Sidekiq -process crashes unexpectedly. [mperham/sidekiq#607] - -0.8.2 ------------ - -- Reimplement existing notifications using batch on_complete events. - -0.8.1 ------------ - -- Rejigger batch callback notifications. - - -0.8.0 ------------ - -- Add new Batch 'callback' notification support, for in-process - notification. -- Symbolize option keys passed to Pony [mperham/sidekiq#603] -- Batch no longer requires the Web UI since Web UI usage is optional. - You must require is manually in your Web process: - -```ruby -require 'sidekiq/web' -require 'sidekiq/batch/web' -mount Sidekiq::Web => '/sidekiq' -``` - - -0.7.1 ------------ - -- Worker instances can access the associated jid and bid via simple - accessors. -- Batches can now be modified while being processed so, e.g. a batch - job can add additional jobs to its own batch. - -```ruby -def perform(...) - batch = Sidekiq::Batch.new(bid) # instantiate batch associated with this job - batch.jobs do - SomeWorker.perform_async # add another job - end -end -``` - -- Save error backtraces in batch's failure info for display in Web UI. -- Clean up email notification a bit. - - -0.7.0 ------------ - -- Add optional batch description -- Mutable batches. Batches can now be modified to add additional jobs - at runtime. Example would be a batch job which needs to create more - jobs based on the data it is processing. - -```ruby -batch = Sidekiq::Batch.new(bid) -batch.jobs do - # define more jobs here -end -``` -- Fix issues with symbols vs strings in option hashes - - -0.6.1 ------------ - -- Webhook notification support - - -0.6 ------------ - -- Redis pubsub -- Email polish - - -0.5 ------------ - -- Batches -- Notifications -- Statsd middleware diff -Nru ruby-sidekiq-6.0.4+dfsg/Rakefile ruby-sidekiq-6.3.1+dfsg/Rakefile --- ruby-sidekiq-6.0.4+dfsg/Rakefile 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/Rakefile 1970-01-01 00:00:00.000000000 +0000 @@ -1,10 +0,0 @@ -require "bundler/gem_tasks" -require "rake/testtask" -require "standard/rake" - -Rake::TestTask.new(:test) do |test| - test.warning = true - test.pattern = "test/**/test_*.rb" -end - -task default: [:standard, :test] diff -Nru ruby-sidekiq-6.0.4+dfsg/README.md ruby-sidekiq-6.3.1+dfsg/README.md --- ruby-sidekiq-6.0.4+dfsg/README.md 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/README.md 2021-11-18 13:57:25.000000000 +0000 @@ -2,11 +2,7 @@ ============== [![Gem Version](https://badge.fury.io/rb/sidekiq.svg)](https://rubygems.org/gems/sidekiq) -[![Code Climate](https://codeclimate.com/github/mperham/sidekiq.svg)](https://codeclimate.com/github/mperham/sidekiq) -[![Test Coverage](https://codeclimate.com/github/mperham/sidekiq/badges/coverage.svg)](https://codeclimate.com/github/mperham/sidekiq/coverage) -[![Build Status](https://circleci.com/gh/mperham/sidekiq/tree/master.svg?style=svg)](https://circleci.com/gh/mperham/sidekiq/tree/master) -[![Gitter Chat](https://badges.gitter.im/mperham/sidekiq.svg)](https://gitter.im/mperham/sidekiq) - +![Build](https://github.com/mperham/sidekiq/workflows/CI/badge.svg) Simple, efficient background processing for Ruby. @@ -50,7 +46,7 @@ You can watch [this Youtube playlist](https://www.youtube.com/playlist?list=PLjeHh2LSCFrWGT5uVjUuFKAcrcj5kSai1) to learn all about Sidekiq and see its features in action. Here's the Web UI: -![Web UI](https://github.com/mperham/sidekiq/raw/master/examples/web-ui.png) +![Web UI](https://github.com/mperham/sidekiq/raw/main/examples/web-ui.png) Want to Upgrade? @@ -88,10 +84,10 @@ License ----------------- -Please see [LICENSE](https://github.com/mperham/sidekiq/blob/master/LICENSE) for licensing details. +Please see [LICENSE](https://github.com/mperham/sidekiq/blob/main/LICENSE) for licensing details. Author ----------------- -Mike Perham, [@mperham@mastodon.xyz](https://mastodon.xyz/@mperham) / [@sidekiq](https://twitter.com/sidekiq), [https://www.mikeperham.com](https://www.mikeperham.com) / [https://www.contribsys.com](https://www.contribsys.com) +Mike Perham, [@getajobmike](https://twitter.com/getajobmike) / [@sidekiq](https://twitter.com/sidekiq), [https://www.mikeperham.com](https://www.mikeperham.com) / [https://www.contribsys.com](https://www.contribsys.com) diff -Nru ruby-sidekiq-6.0.4+dfsg/sidekiq.gemspec ruby-sidekiq-6.3.1+dfsg/sidekiq.gemspec --- ruby-sidekiq-6.0.4+dfsg/sidekiq.gemspec 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/sidekiq.gemspec 2021-11-18 13:57:25.000000000 +0000 @@ -5,17 +5,24 @@ gem.email = ["mperham@gmail.com"] gem.summary = "Simple, efficient background processing for Ruby" gem.description = "Simple, efficient background processing for Ruby." - gem.homepage = "http://sidekiq.org" + gem.homepage = "https://sidekiq.org" gem.license = "LGPL-3.0" gem.executables = ["sidekiq", "sidekiqmon"] - gem.files = `git ls-files | grep -Ev '^(test|myapp|examples)'`.split("\n") + gem.files = ["sidekiq.gemspec", "README.md", "Changes.md", "LICENSE"] + `git ls-files | grep -E '^(bin|lib|web)'`.split("\n") gem.name = "sidekiq" gem.version = Sidekiq::VERSION gem.required_ruby_version = ">= 2.5.0" - gem.add_dependency "redis", ">= 4.1.0" + gem.metadata = { + "homepage_uri" => "https://sidekiq.org", + "bug_tracker_uri" => "https://github.com/mperham/sidekiq/issues", + "documentation_uri" => "https://github.com/mperham/sidekiq/wiki", + "changelog_uri" => "https://github.com/mperham/sidekiq/blob/main/Changes.md", + "source_code_uri" => "https://github.com/mperham/sidekiq" + } + + gem.add_dependency "redis", ">= 4.2.0" gem.add_dependency "connection_pool", ">= 2.2.2" - gem.add_dependency "rack", ">= 2.0.0" - gem.add_dependency "rack-protection", ">= 2.0.0" + gem.add_dependency "rack", "~> 2.0" end diff -Nru ruby-sidekiq-6.0.4+dfsg/.standard.yml ruby-sidekiq-6.3.1+dfsg/.standard.yml --- ruby-sidekiq-6.0.4+dfsg/.standard.yml 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/.standard.yml 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ -ruby_version: 2.5.0 -fix: false -parallel: true -ignore: - - test/**/* - - examples/**/* - - myapp/**/* - - 'lib/sidekiq.rb': - - Lint/InheritException - - 'lib/sidekiq/extensions/**/*': - - Style/MethodMissingSuper - - Style/MissingRespondToMissing - - 'lib/**/*': - - Naming/AsciiIdentifiers - - Lint/RescueException - - Security/YAMLLoad - - Naming/AccessorMethodName - - Naming/MethodName - - Style/GlobalVars - - Style/Alias Binary files /tmp/tmprljuy3dy/lrazoJwY61/ruby-sidekiq-6.0.4+dfsg/web/assets/images/apple-touch-icon.png and /tmp/tmprljuy3dy/ZJ_wkVwpA5/ruby-sidekiq-6.3.1+dfsg/web/assets/images/apple-touch-icon.png differ diff -Nru ruby-sidekiq-6.0.4+dfsg/web/assets/stylesheets/application.css ruby-sidekiq-6.3.1+dfsg/web/assets/stylesheets/application.css --- ruby-sidekiq-6.0.4+dfsg/web/assets/stylesheets/application.css 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/assets/stylesheets/application.css 2021-11-18 13:57:25.000000000 +0000 @@ -6,7 +6,6 @@ color: #585454; padding: 0; text-rendering: optimizeLegibility; - -webkit-font-smoothing: antialiased; font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; background: #f3f3f3 url(data:image/png;base64,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); } @@ -22,15 +21,9 @@ a { color: #b1003e; } -a:active, a:hover, a:visited { +a:active, a:hover { color: #4b001a; } -a.btn { - color: #585454; -} -a.btn-primary { - color: white; -} h1, h2, h3, h4, h5, h6, strong { font-weight: 700; @@ -96,11 +89,7 @@ .summary_bar .summary { margin-top: 12px; background-color: #fff; - -webkit-box-shadow: 0 0 5px rgba(50, 50, 50, 0.25); - -moz-box-shadow: 0 0 5px rgba(50, 50, 50, 0.25); box-shadow: 0 0 5px rgba(50, 50, 50, 0.25); - -webkit-border-radius: 4px; - -moz-border-radius: 4px; border-radius: 4px; padding: 8px; margin-bottom: 10px; @@ -109,9 +98,12 @@ .poll-wrapper { margin: 9px; } -#live-poll.active { +.live-poll.active { background-color: #009300; } +.live-poll.active:hover { + background-color: #777; +} .summary_bar ul { margin: 0 0 38px 0; } @@ -127,6 +119,10 @@ width: 14%; } @media (max-width: 767px) and (min-width: 200px) { + .summary_bar { + font-size: 1.5em; + } + .summary_bar ul li { width: 100%; } @@ -147,16 +143,6 @@ width: 96px !important; } } -/*@media (max-width: 1199px) and (min-width: 980px) { - .summary_bar ul li.col-sm-2 { - width: 130px !important; - } -} -@media (min-width: 1200px) { - .summary_bar ul li.col-sm-2 { - width: 154px !important; - } -}*/ .summary_bar ul .desc { display: block; font-size: 1em; @@ -177,10 +163,6 @@ overflow: overlay; } -table.table-white { - background-color: #fff; -} - .queues form { margin: 0; } @@ -190,7 +172,7 @@ } form .btn-group .btn { - margin-right: 1px; + margin-right: 4px; } td form { @@ -201,13 +183,8 @@ padding: 0; } -.jobtag a { - color: white; -} - -.jobtag a:hover { - color: white; - text-decoration: underline; +.jobtag, .jobtag a { + color: black; } table .table-checkbox label { @@ -277,8 +254,7 @@ .navbar .nav a { text-align: center; - } - + } } @media (width: 768px) { @@ -290,18 +266,6 @@ .navbar .poll-wrapper { margin: 4px 4px 0 0; } - - .navbar .dropdown-menu { - min-width: 120px; - } - - .navbar .dropdown-menu a { - text-align: left; - } -} - -.nav .dropdown { - display: none; } .navbar-footer .navbar ul.nav { @@ -356,51 +320,23 @@ .btn { font-weight: 700; border: none; - -webkit-border-radius: 3px; - -moz-border-radius: 3px; - -ms-border-radius: 3px; - -o-border-radius: 3px; border-radius: 3px; - -webkit-box-shadow: 0 0 2px rgba(0, 0, 0, 0.4); - -moz-box-shadow: 0 0 2px rgba(0, 0, 0, 0.4); box-shadow: 0 0 2px rgba(0, 0, 0, 0.4); - background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #fafafa), color-stop(100%, #ededed)); - background-image: -webkit-linear-gradient(#fafafa, #ededed); - background-image: -moz-linear-gradient(#fafafa, #ededed); - background-image: -o-linear-gradient(#fafafa, #ededed); - background-image: linear-gradient(#fafafa, #ededed); -} -.btn:hover { - background-color: #ededed; -} - -.btn-primary { - background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #b1003e), color-stop(100%, #980035)); - background-image: -webkit-linear-gradient(#b1003e, #980035); - background-image: -moz-linear-gradient(#b1003e, #980035); - background-image: -o-linear-gradient(#b1003e, #980035); background-image: linear-gradient(#b1003e, #980035); -} -.btn-primary:hover { background-color: #980035; + color: #ddd; } - -.btn-danger { - background-image: -webkit-gradient(linear, 50% 0%, 50% 100%, color-stop(0%, #b1003e), color-stop(100%, #980035)); - background-image: -webkit-linear-gradient(#b1003e, #980035); - background-image: -moz-linear-gradient(#b1003e, #980035); - background-image: -o-linear-gradient(#b1003e, #980035); - background-image: linear-gradient(#b1003e, #980035); -} -.btn-danger:hover { - background-color: #980035; +.btn:hover { + color: #000; + background-image: none; + background-color: #ddd; } .poll-status { padding: 10px 0; } -.redis-wrapper { +.stats-wrapper { width: 100%; text-align: center; } @@ -442,7 +378,7 @@ margin: 5px 10px 5px 5px; } .stat p{ - font-size: 1em; + font-size: 1.5em; margin: 5px 5px 5px 10px; } } @@ -469,6 +405,10 @@ div.interval-slider input { width: 160px; + height: 3px; + margin-top: 5px; + border-radius: 2px; + background: currentcolor; } #realtime-legend, @@ -540,51 +480,17 @@ background-color: #80002d; border-radius: 10px; box-shadow: 0 0 9px #666; - -moz-box-shadow: 0 0 9px #666; - -webkit-box-shadow: 0 0 9px #666; border: 3px solid transparent; z-index: 10; } .beacon.pulse .dot { - -webkit-animation: beacon-dot-pulse 1s ease-out; - -moz-animation: beacon-dot-pulse 1s ease-out; animation: beacon-dot-pulse 1s ease-out; } -@-webkit-keyframes beacon-dot-pulse { - from { - background-color: #80002d; - -webkit-box-shadow: 0 0 9px #666; - } - 50% { - background-color: #c90047; - -webkit-box-shadow: 0 0 18px #666; - } - to { - background-color: #80002d; - -webkit-box-shadow: 0 0 9px #666; - } -} - -@-moz-keyframes beacon-dot-pulse { - from { - background-color: #80002d; - -moz-box-shadow: 0 0 9px #666; - } - 50% { - background-color: #c90047; - -moz-box-shadow: 0 0 18px #666; - } - to { - background-color: #80002d; - -moz-box-shadow: 0 0 9px #666; - } -} - @keyframes beacon-dot-pulse { from { - background-color: #80002d; + background-color: #50002d; box-shadow: 0 0 9px #666; } 50% { @@ -592,7 +498,7 @@ box-shadow: 0 0 18px #666; } to { - background-color: #80002d; + background-color: #50002d; box-shadow: 0 0 9px #666; } } @@ -608,33 +514,9 @@ } .beacon.pulse .ring { - -webkit-animation: beacon-ring-pulse 1s; - -moz-animation: beacon-ring-pulse 1s; animation: beacon-ring-pulse 1s; } -@-webkit-keyframes beacon-ring-pulse { - 0% { - opacity: 1; - -webkit-transform: scale(0.3); - } - 100% { - opacity: 0; - -webkit-transform: scale(1); - } -} - -@-moz-keyframes beacon-ring-pulse { - 0% { - opacity: 1; - -moz-transform: scale(0.3); - } - 100% { - opacity: 0; - -moz-transform: scale(1); - } -} - @keyframes beacon-ring-pulse { 0% { opacity: 1; @@ -655,7 +537,6 @@ } .history-graph { - font-size: 0.8em; padding: 3px; border-radius: 3px; } @@ -739,13 +620,10 @@ position: absolute; top: 0; z-index: 2; - background: rgba(0, 0, 0, .1); + background: rgba(0, 0, 0, .9); bottom: 0; width: 1px; transition: opacity .25s linear; - -moz-transition: opacity .25s linear; - -o-transition: opacity .25s linear; - -webkit-transition: opacity .25s linear } .rickshaw_graph .detail.inactive { opacity: 0 @@ -757,7 +635,7 @@ font-family: Arial, sans-serif; border-radius: 3px; padding: 6px; - opacity: .5; + opacity: .7; border: 1px solid #e0e0e0; font-size: 12px; position: absolute; @@ -827,7 +705,6 @@ position: absolute; box-shadow: 0 0 2px rgba(0, 0, 0, .6); box-sizing: content-box; - -moz-box-sizing: content-box; background: #fff; border-width: 2px; border-style: solid; @@ -849,96 +726,16 @@ top: 0; bottom: 0; width: 0; - border-left: 1px dotted rgba(0, 0, 0, .2); + border-left: 1px dotted rgba(0, 0, 0, .5); pointer-events: none } .rickshaw_graph .x_tick .title { position: absolute; - font-size: 12px; font-family: Arial, sans-serif; - opacity: .5; white-space: nowrap; margin-left: 3px; bottom: 1px } -.rickshaw_annotation_timeline { - height: 1px; - border-top: 1px solid #e0e0e0; - margin-top: 10px; - position: relative -} -.rickshaw_annotation_timeline .annotation { - position: absolute; - height: 6px; - width: 6px; - margin-left: -2px; - top: -3px; - border-radius: 5px; - background-color: rgba(0, 0, 0, .25) -} -.rickshaw_graph .annotation_line { - position: absolute; - top: 0; - bottom: -6px; - width: 0; - border-left: 2px solid rgba(0, 0, 0, .3); - display: none -} -.rickshaw_graph .annotation_line.active { - display: block -} -.rickshaw_graph .annotation_range { - background: rgba(0, 0, 0, .1); - display: none; - position: absolute; - top: 0; - bottom: -6px -} -.rickshaw_graph .annotation_range.active { - display: block -} -.rickshaw_graph .annotation_range.active.offscreen { - display: none -} -.rickshaw_annotation_timeline .annotation .content { - background: #fff; - color: #000; - opacity: .9; - padding: 5px; - box-shadow: 0 0 2px rgba(0, 0, 0, .8); - border-radius: 3px; - position: relative; - z-index: 20; - font-size: 12px; - padding: 6px 8px 8px; - top: 18px; - left: -11px; - width: 160px; - display: none; - cursor: pointer -} -.rickshaw_annotation_timeline .annotation .content:before { - content: "\25b2"; - position: absolute; - top: -11px; - color: #fff; - text-shadow: 0 -1px 1px rgba(0, 0, 0, .8) -} -.rickshaw_annotation_timeline .annotation.active, -.rickshaw_annotation_timeline .annotation:hover { - background-color: rgba(0, 0, 0, .8); - cursor: none -} -.rickshaw_annotation_timeline .annotation .content:hover { - z-index: 50 -} -.rickshaw_annotation_timeline .annotation.active .content { - display: block -} -.rickshaw_annotation_timeline .annotation:hover .content { - display: block; - z-index: 50 -} .rickshaw_graph .y_axis, .rickshaw_graph .x_axis_d3 { fill: none @@ -972,7 +769,7 @@ } .rickshaw_graph .y_ticks text, .rickshaw_graph .x_ticks_d3 text { - opacity: .5; + opacity: .7; font-size: 12px; pointer-events: none } @@ -990,7 +787,6 @@ } .rickshaw_legend { font-family: Arial; - font-size: 12px; color: #fff; background: #404040; display: inline-block; @@ -1033,10 +829,8 @@ } .rickshaw_legend .action { margin-right: .2em; - font-size: 10px; - opacity: .2; + opacity: .5; cursor: pointer; - font-size: 14px } .rickshaw_legend .line.disabled { opacity: .4 @@ -1151,3 +945,13 @@ .delete-confirm { width: 20%; } + +.info-circle { + color: #ccc; + background-color: #000; + border-radius: 50%; + text-align: center; + vertical-align: middle; + padding: 3px 7px; + margin-left: 5px; +} diff -Nru ruby-sidekiq-6.0.4+dfsg/web/assets/stylesheets/application-dark.css ruby-sidekiq-6.3.1+dfsg/web/assets/stylesheets/application-dark.css --- ruby-sidekiq-6.0.4+dfsg/web/assets/stylesheets/application-dark.css 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/assets/stylesheets/application-dark.css 2021-11-18 13:57:25.000000000 +0000 @@ -1,125 +1,147 @@ -@media (prefers-color-scheme: dark) { +html, body { + background-color: #333 !important; + color: #ddd; +} + +a, +.title, +.summary_bar ul .count, +span.current-interval, +.navbar .navbar-brand { + color: #d04; +} + +.history-graph.active, +.beacon .dot { + background-color: #d04; +} + +.navbar .navbar-brand:hover { + color: #ddd; +} + +.navbar .navbar-brand .status { + color: #ddd; +} + +.navbar-default .navbar-nav > li > a { + color: #ddd; +} + +.navbar-inverse { + background-color: #222; + border-color: #555; +} + +table { + background-color: #282828; +} + +.table-striped > tbody > tr:nth-of-type(odd) { + background-color: #333; +} + +.table-bordered, +.table-bordered > tbody > tr > td, +.table-bordered > tbody > tr > th, +.table-bordered > tfoot > tr > td, +.table-bordered > tfoot > tr > th, +.table-bordered > thead > tr > td, +.table-bordered > thead > tr > th { + border: 1px solid #555; +} + +.table-hover > tbody > tr:hover { + background-color: #444; +} + +.alert { + border: none; + color: #ddd; +} + +.alert-success { + background-color: #484; +} + +.alert-danger { + background-color: #980035; +} + +.alert-info { + background-color: #31708f; +} + +a:link, +a:active, +a:hover { + color: #ddd; +} + +input { + background-color: #444; + color: #ccc; + padding: 3px; +} + +.summary_bar .summary { + background-color: #222; + border: 1px solid #555; + + box-shadow: 0 0 5px rgba(255, 255, 255, .5); +} + +.navbar-default { + background-color: #222; + border-color: #555; +} + +.navbar-default .navbar-nav > .active > a, +.navbar-default .navbar-nav > .active > a:focus, +.navbar-default .navbar-nav > .active > a:hover { + color: #ddd; + background-color: #333; +} + +.navbar-default .navbar-nav > li > a:hover { + color: #ddd; +} + +.pagination > li > a, +.pagination > li > a:hover, +.pagination > li > span { + color: #ddd; + background-color: #333; + border-color: #555; +} +.pagination > .disabled > a, +.pagination > .disabled > a:focus, +.pagination > .disabled > a:hover, +.pagination > .disabled > span, +.pagination > .disabled > span:focus, +.pagination > .disabled > span:hover { + color: #ddd; + background-color: #333; + border-color: #555; +} + +.stat { + border: 1px solid #888; +} + +.rickshaw_graph .detail { + background: #888; +} +.rickshaw_graph .x_tick { + border-color: #888; +} + +.rickshaw_graph .y_ticks.glow text { + fill: #ddd; + color: #ddd; +} - body { - background-color: #000; - color: #ccc; - } - - a, - .title, - .summary_bar ul .count, - .navbar .navbar-brand { - color: #af0014; - } - - .navbar .navbar-brand:hover { - color: #ccc; - } - - .navbar .navbar-brand .status { - color: #ccc; - } - - .navbar-inverse { - background-color: #000; - border-color: #333; - } - - table.table-white { - background-color: #111; - } - - .table-striped > tbody > tr:nth-of-type(odd) { - background-color: #222; - } - - .table-bordered, - .table-bordered > tbody > tr > td, - .table-bordered > tbody > tr > th, - .table-bordered > tfoot > tr > td, - .table-bordered > tfoot > tr > th, - .table-bordered > thead > tr > td, - .table-bordered > thead > tr > th { - border: 1px solid #333; - } - - .table-hover > tbody > tr:hover { - background-color: #333; - } - - .alert { - border: none; - color: #ccc; - } - - .alert-success { - background-color: #000; - } - - a:link, - a:active, - a:hover, - a:visited { - color: #63798c; - } - - a.btn { - color: #000; - } - - .summary_bar .summary { - background-color: #000; - border: 1px solid #333; - } - - .navbar-default { - background-color: #000; - border-color: #3d3d3d; - } - - .navbar-default .navbar-nav > .active > a, - .navbar-default .navbar-nav > .active > a:focus, - .navbar-default .navbar-nav > .active > a:hover { - color: #ccc; - background-color: #282828; - } - - .navbar-default .navbar-nav > li > a:hover { - color: #ccc; - } - - .pagination > li > a, - .pagination > li > a:hover, - .pagination > li > span { - color: #ccc; - background-color: #282828; - border-color: #353535; - } - .pagination > .disabled > a, - .pagination > .disabled > a:focus, - .pagination > .disabled > a:hover, - .pagination > .disabled > span, - .pagination > .disabled > span:focus, - .pagination > .disabled > span:hover { - color: #a5a5a5; - background-color: #282828; - border-color: #353535; - } - - .stat { - border: 1px solid rgba(255, 255, 255, 0.1); - } - - #live-poll { - color: #ccc; - } - - .btn-warn { - color: #333; - } - - .rickshaw_graph .y_ticks.glow text { - fill: #ccc; - color: #ccc; - } +.info-circle { + color: #222; + background-color: #888; } diff -Nru ruby-sidekiq-6.0.4+dfsg/web/assets/stylesheets/application-rtl.css ruby-sidekiq-6.3.1+dfsg/web/assets/stylesheets/application-rtl.css --- ruby-sidekiq-6.0.4+dfsg/web/assets/stylesheets/application-rtl.css 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/assets/stylesheets/application-rtl.css 2021-11-18 13:57:25.000000000 +0000 @@ -46,10 +46,6 @@ .navbar .poll-wrapper { margin: 4px 0 0 4px; } - - .navbar .dropdown-menu a { - text-align: right; - } } .navbar-footer .navbar ul.nav a.navbar-brand { diff -Nru ruby-sidekiq-6.0.4+dfsg/web/locales/ar.yml ruby-sidekiq-6.3.1+dfsg/web/locales/ar.yml --- ruby-sidekiq-6.0.4+dfsg/web/locales/ar.yml 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/locales/ar.yml 2021-11-18 13:57:25.000000000 +0000 @@ -8,6 +8,7 @@ Realtime: الزمن الفعلي History: تاريخ Busy: مشغول + Utilization: الاستخدام Processed: تمت المعالجة Failed: فشل Scheduled: مجدول @@ -65,11 +66,13 @@ DeadJobs: وظائف ميتة NoDeadJobsFound: لاتوجد وظائف ميتة Dead: ميتة + Process: عملية Processes: عمليات + Name: الاسم Thread: نيسب Threads: نياسب Jobs: وظائف - Paused: إيقاف مؤقت + Paused: موقفة مؤقتاً Stop: إيقاف Quiet: هدوء StopAll: إيقاف الكل @@ -78,4 +81,7 @@ Plugins: الإضافات NotYetEnqueued: لم تدخل الرتل بعد CreatedAt: أنشئت في - BackToApp: العودة إلى التطبيق \ No newline at end of file + BackToApp: العودة إلى التطبيق + Latency: زمن الانتظار + Pause: إيقاف مؤقت + Unpause: متابعة \ No newline at end of file diff -Nru ruby-sidekiq-6.0.4+dfsg/web/locales/en.yml ruby-sidekiq-6.3.1+dfsg/web/locales/en.yml --- ruby-sidekiq-6.0.4+dfsg/web/locales/en.yml 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/locales/en.yml 2021-11-18 13:57:25.000000000 +0000 @@ -7,6 +7,7 @@ Realtime: Real-time History: History Busy: Busy + Utilization: Utilization Processed: Processed Failed: Failed Scheduled: Scheduled @@ -26,7 +27,7 @@ Delete: Delete AddToQueue: Add to queue AreYouSureDeleteJob: Are you sure you want to delete this job? - AreYouSureDeleteQueue: Are you sure you want to delete the %{queue} queue? + AreYouSureDeleteQueue: Are you sure you want to delete the %{queue} queue? This will delete all jobs within the queue, it will reappear if you push more jobs to it in the future. Queues: Queues Size: Size Actions: Actions @@ -64,7 +65,9 @@ DeadJobs: Dead Jobs NoDeadJobsFound: No dead jobs were found Dead: Dead + Process: Process Processes: Processes + Name: Name Thread: Thread Threads: Threads Jobs: Jobs diff -Nru ruby-sidekiq-6.0.4+dfsg/web/locales/es.yml ruby-sidekiq-6.3.1+dfsg/web/locales/es.yml --- ruby-sidekiq-6.0.4+dfsg/web/locales/es.yml 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/locales/es.yml 2021-11-18 13:57:25.000000000 +0000 @@ -7,6 +7,7 @@ Realtime: Tiempo Real History: Historial Busy: Ocupado + Utilization: Utilización Processed: Procesadas Failed: Fallidas Scheduled: Programadas @@ -24,9 +25,9 @@ ShowAll: Mostrar Todo CurrentMessagesInQueue: Mensajes actualmente en %{queue} Delete: Eliminar - AddToQueue: Añadir a fila + AddToQueue: Añadir a la cola AreYouSureDeleteJob: ¿Estás seguro de eliminar este trabajo? - AreYouSureDeleteQueue: ¿Estás seguro de eliminar la fila %{queue}? + AreYouSureDeleteQueue: ¿Estás seguro de eliminar la cola %{queue}? Queues: Colas Size: Tamaño Actions: Acciones @@ -39,6 +40,7 @@ AreYouSure: ¿Estás seguro? DeleteAll: Borrar Todo RetryAll: Reintentar Todo + KillAll: Matar Todo NoRetriesFound: No se encontraron reintentos Error: Error ErrorClass: Clase del Error @@ -63,8 +65,22 @@ DeadJobs: Trabajos muertos NoDeadJobsFound: No hay trabajos muertos Dead: Muerto + Process: Proceso Processes: Procesos + Name: Nombre Thread: Hilo Threads: Hilos Jobs: Trabajos + Paused: Pausado + Stop: Detener + Quiet: Silenciar + StopAll: Detener Todo + QuietAll: Silenciar Todo + PollingInterval: Intervalo de Sondeo + Plugins: Plugins + NotYetEnqueued: Aún no en cola + CreatedAt: Creado en + BackToApp: Volver a la Aplicación Latency: Latencia + Pause: Pausar + Unpause: Reanudar diff -Nru ruby-sidekiq-6.0.4+dfsg/web/locales/fr.yml ruby-sidekiq-6.3.1+dfsg/web/locales/fr.yml --- ruby-sidekiq-6.0.4+dfsg/web/locales/fr.yml 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/locales/fr.yml 2021-11-18 13:57:25.000000000 +0000 @@ -7,6 +7,7 @@ Realtime: Temps réel History: Historique Busy: En cours + Utilization: Utilisation Processed: Traitées Failed: Échouées Scheduled: Planifiées @@ -39,6 +40,7 @@ AreYouSure: Êtes-vous certain ? DeleteAll: Tout supprimer RetryAll: Tout réessayer + KillAll: Tout tuer NoRetriesFound: Aucune tâche à réessayer n’a été trouvée Error: Erreur ErrorClass: Classe d’erreur @@ -63,16 +65,21 @@ DeadJobs: Tâches mortes NoDeadJobsFound: Aucune tâche morte n'a été trouvée Dead: Mortes + Process: Processus Processes: Processus Thread: Thread Threads: Threads Jobs: Tâches Paused: Mise en pause Stop: Arrêter - Quiet: Clôturer + Quiet: Clore StopAll: Tout arrêter - QuietAll: Tout clôturer - PollingInterval: Interval de rafraîchissement + QuietAll: Tout clore + PollingInterval: Intervalle de rafraîchissement Plugins: Plugins NotYetEnqueued: Pas encore en file d'attente CreatedAt: Créée le + Back to App: Retour à l'application + Latency: Latence + Pause: Pause + Unpause: Unpause diff -Nru ruby-sidekiq-6.0.4+dfsg/web/locales/ja.yml ruby-sidekiq-6.3.1+dfsg/web/locales/ja.yml --- ruby-sidekiq-6.0.4+dfsg/web/locales/ja.yml 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/locales/ja.yml 2021-11-18 13:57:25.000000000 +0000 @@ -7,6 +7,7 @@ Realtime: リアルタイム History: 履歴 Busy: 実行中 + Utilization: 使用率 Processed: 完了 Failed: 失敗 Scheduled: 予定 @@ -64,7 +65,9 @@ DeadJobs: デッドジョブ NoDeadJobsFound: デッドジョブはありません Dead: デッド + Process: プロセス Processes: プロセス + Name: 名前 Thread: スレッド Threads: スレッド Jobs: ジョブ @@ -79,3 +82,5 @@ CreatedAt: 作成日時 BackToApp: アプリに戻る Latency: レイテンシ + Pause: 一時停止 + Unpause: 一時停止を解除 diff -Nru ruby-sidekiq-6.0.4+dfsg/web/locales/lt.yml ruby-sidekiq-6.3.1+dfsg/web/locales/lt.yml --- ruby-sidekiq-6.0.4+dfsg/web/locales/lt.yml 1970-01-01 00:00:00.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/locales/lt.yml 2021-11-18 13:57:25.000000000 +0000 @@ -0,0 +1,83 @@ +# elements like %{queue} are variables and should not be translated +lt: + Dashboard: Valdymo skydas + Status: Būsena + Time: Laikas + Namespace: Vardų erdvė + Realtime: Realiu laiku + History: Istorija + Busy: Užimti + Processed: Įvykdyti + Failed: Nepavykę + Scheduled: Suplanuoti + Retries: Kartojami + Enqueued: Eilėje + Worker: Darbuotojas + LivePoll: Užklausti gyvai + StopPolling: Stabdyti užklausas + Queue: Eilė + Class: Klasė + Job: Darbas + Arguments: Parametrai + Extras: Papildomi + Started: Pradėti + ShowAll: Rodyti Visus + CurrentMessagesInQueue: Esami darbai eilėje %{queue} + Delete: Pašalinti + AddToQueue: Pridėti į eilę + AreYouSureDeleteJob: Ar tikrai norite pašalinti šį darbą? + AreYouSureDeleteQueue: Ar tikrai norite pašalinti šią eilę %{queue}? + Queues: Eilės + Size: Dydis + Actions: Veiksmai + NextRetry: Sekantis Kartojimas + RetryCount: Kartojimų Skaičius + RetryNow: Kartoti Dabar + Kill: Priverstinai Nutraukti + LastRetry: Paskutinis Kartojimas + OriginallyFailed: Iš pradžių Nepavykę + AreYouSure: Ar jūs įsitikinę? + DeleteAll: Pašalinti Visus + RetryAll: Kartoti Visus + KillAll: Priverstinai Nutraukti Visus + NoRetriesFound: Nerasta kartojimų + Error: Klaida + ErrorClass: Klaidos Klasė + ErrorMessage: Klaidos Žinutė + ErrorBacktrace: Klaidos Pėdsakai + GoBack: ← Atgal + NoScheduledFound: Planuojamų darbų nerasta + When: Kada + ScheduledJobs: Planuojami Darbai + idle: neveiksnus + active: aktyvus + Version: Versija + Connections: Ryšiai + MemoryUsage: Atminties Vartojimas + PeakMemoryUsage: Atminties Vartojimo Pikas + Uptime: Gyvavimo laikas (dienomis) + OneWeek: 1 savaitė + OneMonth: 1 mėnuo + ThreeMonths: 3 mėnesiai + SixMonths: 6 mėnesiai + Failures: Nesėkmingi vykdymai + DeadJobs: Negyvi Darbai + NoDeadJobsFound: Negyvų darbų nerasta + Dead: Negyvi + Processes: Procesai + Thread: Gija + Threads: Gijos + Jobs: Darbai + Paused: Pristabdytas + Stop: Sustabdyti + Quiet: Nutildyti + StopAll: Sustabdyti Visus + QuietAll: Nutildyti Visus + PollingInterval: Užklausimų intervalas + Plugins: Įskiepiai + NotYetEnqueued: Dar neįtraukti į eilę + CreatedAt: Sukurta + BackToApp: Atgal į Aplikaciją + Latency: Vėlavimas + Pause: Pristabdyti + Unpause: Pratęsti diff -Nru ruby-sidekiq-6.0.4+dfsg/web/locales/pl.yml ruby-sidekiq-6.3.1+dfsg/web/locales/pl.yml --- ruby-sidekiq-6.0.4+dfsg/web/locales/pl.yml 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/locales/pl.yml 2021-11-18 13:57:25.000000000 +0000 @@ -10,7 +10,7 @@ Processed: Ukończone Failed: Nieudane Scheduled: Zaplanowane - Retries: Prób + Retries: Do ponowienia Enqueued: Zakolejkowane Worker: Worker LivePoll: Wczytuj na żywo @@ -29,15 +29,15 @@ Queues: Kolejki Size: Rozmiar Actions: Akcje - NextRetry: Kolejna próba - RetryCount: Liczba prób + NextRetry: Następne ponowienie + RetryCount: Ilość ponowień RetryNow: Ponów teraz LastRetry: Ostatnie ponowienie OriginallyFailed: Ostatnio nieudane AreYouSure: Na pewno? DeleteAll: Usuń wszystko RetryAll: Powtórz wszystko - NoRetriesFound: Brak powtórzeń + NoRetriesFound: Brak zadań do ponowienia Error: Błąd ErrorClass: Klasa błędu ErrorMessage: Wiadomosć błędu diff -Nru ruby-sidekiq-6.0.4+dfsg/web/locales/ru.yml ruby-sidekiq-6.3.1+dfsg/web/locales/ru.yml --- ruby-sidekiq-6.0.4+dfsg/web/locales/ru.yml 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/locales/ru.yml 2021-11-18 13:57:25.000000000 +0000 @@ -38,6 +38,7 @@ AreYouSure: Вы уверены? DeleteAll: Удалить все RetryAll: Повторить все + KillAll: Убить всё NoRetriesFound: Нет попыток Error: Ошибка ErrorClass: Класс ошибки @@ -76,3 +77,6 @@ NotYetEnqueued: Пока не в очереди CreatedAt: Создан BackToApp: Назад + Latency: Задержка + Pause: Пауза + Unpause: Возобновить diff -Nru ruby-sidekiq-6.0.4+dfsg/web/locales/vi.yml ruby-sidekiq-6.3.1+dfsg/web/locales/vi.yml --- ruby-sidekiq-6.0.4+dfsg/web/locales/vi.yml 1970-01-01 00:00:00.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/locales/vi.yml 2021-11-18 13:57:25.000000000 +0000 @@ -0,0 +1,83 @@ +# elements like %{queue} are variables and should not be translated +vi: # <---- change this to your locale code + Dashboard: Bảng điều khiển + Status: Trạng thái + Time: Thời gian + Namespace: Không gian tên + Realtime: Thời gian thực + History: Lịch sử + Busy: Bận rộn + Processed: Đã xử lí + Failed: Đã thất bại + Scheduled: Đã lên lịch + Retries: Số lần thử + Enqueued: Đã xếp hàng đợi + Worker: Máy xử lí + LivePoll: Thăm dò trực tiếp + StopPolling: Ngừng thăm dò + Queue: Hàng đợi + Class: Lớp + Job: Tác vụ + Arguments: Tham số + Extras: Thêm + Started: Đã bắt đầu + ShowAll: Hiện tất cả + CurrentMessagesInQueue: Số lượng công việc trong %{queue} + Delete: Xóa + AddToQueue: Thêm vào hàng đợi + AreYouSureDeleteJob: Bạn có chắc là muốn xóa tác vụ này? + AreYouSureDeleteQueue: Bạn có chắc là muốn xóa %{queue} này? + Queues: Các hàng đợi + Size: Kích thước + Actions: Những hành động + NextRetry: Lần thử lại tiếp theo + RetryCount: Số lần thử lại + RetryNow: Thử lại ngay bây giờ + Kill: Giết + LastRetry: Lần thử cuối + OriginallyFailed: Đã thất bại từ đầu + AreYouSure: Bạn chắc chứ? + DeleteAll: Xóa hết + RetryAll: Thử lại tất cả + KillAll: Giết hết + NoRetriesFound: Không có lần thử nào được tìm thấy + Error: Lỗi + ErrorClass: Lớp lỗi + ErrorMessage: Tin nhắn lỗi + ErrorBacktrace: Dấu vết của lỗi + GoBack: ← Trở lại + NoScheduledFound: Không có tác vụ đã lên lịch nào được tìm thấy + When: Khi nào + ScheduledJobs: Những Tác Vụ Được Hẹn + idle: Đang chờ + active: Đang hoạt động + Version: Phiên bản + Connections: Các kết nối + MemoryUsage: Lượng bộ nhớ sử dụng + PeakMemoryUsage: Lượng bộ nhớ sử dụng đỉnh điểm + Uptime: Thời gian hệ thống đã online (days) + OneWeek: 1 tuần + OneMonth: 1 tháng + ThreeMonths: 3 tháng + SixMonths: 6 tháng + Failures: Các thất bại + DeadJobs: Những tác vụ đã chết + NoDeadJobsFound: Không có tác vụ đã chết nào được tìm thấy + Dead: Chết + Processes: Tiến trình xử lí + Thread: Luồng xử lí + Threads: Những luồng xử lí + Jobs: Các tác vụ + Paused: Đã tạm dừng + Stop: Dừng Lại + Quiet: Im lặng + StopAll: Dừng lại tất cả + QuietAll: Làm cho tất cả im lặng + PollingInterval: Khoảng thời gian giữa các lần thăm dò + Plugins: Hệ thống đính kèm + NotYetEnqueued: Chưa được bỏ vào hàng đợi + CreatedAt: Được tạo vào lúc + BackToApp: Trở về ứng dụng + Latency: Độ trễ + Pause: Tạm dừng + Unpause: Hủy tạm dừng diff -Nru ruby-sidekiq-6.0.4+dfsg/web/views/busy.erb ruby-sidekiq-6.3.1+dfsg/web/views/busy.erb --- ruby-sidekiq-6.0.4+dfsg/web/views/busy.erb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/views/busy.erb 2021-11-18 13:57:25.000000000 +0000 @@ -1,8 +1,39 @@
-
+
+

<%= t('Status') %>

+
+
+ +
+
+
+

<%= s = processes.size; number_with_delimiter(s) %>

+

<%= t('Processes') %>

+
+
+

<%= x = processes.total_concurrency; number_with_delimiter(x) %>

+

<%= t('Threads') %>

+
+
+

<%= ws = workers.size; number_with_delimiter(ws) %>

+

<%= t('Busy') %>

+
+
+

<%= x == 0 ? 0 : ((ws / x.to_f) * 100).round(0) %>%

+

<%= t('Utilization') %>

+
+
+

<%= format_memory(processes.total_rss) %>

+

<%= t('RSS') %>

+
+
+
+ +
+

<%= t('Processes') %>

-
+
<%= csrf_tag %>
@@ -12,14 +43,14 @@
-
- +
- - + + + <% lead = processes.leader %> @@ -39,22 +70,22 @@ <% end %>
<%= "#{t('Queues')}: " %> - <%= process['queues'] * ", " %> + <%= process.queues.join(", ") %> + <% end %> @@ -68,7 +99,7 @@
-
<%= t('Name') %> <%= t('Started') %><%= t('Threads') %><%= t('Busy') %><%= t('RSS') %>?<%= t('Threads') %><%= t('Busy') %>  
<%= relative_time(Time.at(process['started_at'])) %><%= format_memory(process['rss'].to_i) %> <%= process['concurrency'] %> <%= process['busy'] %> -
-
- <%= csrf_tag %> - - <% unless process.stopping? %> - - <% end %> - -
-
+
+ <%= csrf_tag %> + + +
+ <% unless process.stopping? %><% end %> + +
+
+
@@ -79,7 +110,7 @@ <% workers.each do |process, thread, msg| %> - <% job = Sidekiq::Job.new(msg['payload']) %> + <% job = Sidekiq::JobRecord.new(msg['payload']) %> diff -Nru ruby-sidekiq-6.0.4+dfsg/web/views/dashboard.erb ruby-sidekiq-6.3.1+dfsg/web/views/dashboard.erb --- ruby-sidekiq-6.0.4+dfsg/web/views/dashboard.erb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/views/dashboard.erb 2021-11-18 13:57:25.000000000 +0000 @@ -2,16 +2,16 @@

<%= t('Dashboard') %> - +

<%= t('PollingInterval') %>: - 5 sec + 5 sec
- +
@@ -20,54 +20,62 @@
-
-
- <%= t('History') %> +
+
+

<%= t('History') %>

+
+
+
+

-
Redis
-
+
+
+

Redis

+
+
+
<% if @redis_info.fetch("redis_version", nil) %>
-

<%= @redis_info.fetch("redis_version") %>

+

<%= @redis_info.fetch("redis_version") %>

<%= t('Version') %>

<% end %> <% if @redis_info.fetch("uptime_in_days", nil) %>
-

<%= @redis_info.fetch("uptime_in_days") %>

+

<%= @redis_info.fetch("uptime_in_days") %>

<%= t('Uptime') %>

<% end %> <% if @redis_info.fetch("connected_clients", nil) %>
-

<%= @redis_info.fetch("connected_clients") %>

+

<%= @redis_info.fetch("connected_clients") %>

<%= t('Connections') %>

<% end %> <% if @redis_info.fetch("used_memory_human", nil) %>
-

<%= @redis_info.fetch("used_memory_human") %>

+

<%= @redis_info.fetch("used_memory_human") %>

<%= t('MemoryUsage') %>

<% end %> <% if @redis_info.fetch("used_memory_peak_human", nil) %>
-

<%= @redis_info.fetch("used_memory_peak_human") %>

+

<%= @redis_info.fetch("used_memory_peak_human") %>

<%= t('PeakMemoryUsage') %>

<% end %> diff -Nru ruby-sidekiq-6.0.4+dfsg/web/views/dead.erb ruby-sidekiq-6.3.1+dfsg/web/views/dead.erb --- ruby-sidekiq-6.0.4+dfsg/web/views/dead.erb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/views/dead.erb 2021-11-18 13:57:25.000000000 +0000 @@ -2,7 +2,7 @@

<%= t('Error') %>

-
<%= t('Process') %> <%= t('TID') %><%= t('Started') %>
<%= process %> <%= thread %>
+
diff -Nru ruby-sidekiq-6.0.4+dfsg/web/views/_footer.erb ruby-sidekiq-6.3.1+dfsg/web/views/_footer.erb --- ruby-sidekiq-6.0.4+dfsg/web/views/_footer.erb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/views/_footer.erb 2021-11-18 13:57:25.000000000 +0000 @@ -9,7 +9,7 @@
  • - +
  • diff -Nru ruby-sidekiq-6.0.4+dfsg/web/views/_job_info.erb ruby-sidekiq-6.3.1+dfsg/web/views/_job_info.erb --- ruby-sidekiq-6.0.4+dfsg/web/views/_job_info.erb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/views/_job_info.erb 2021-11-18 13:57:25.000000000 +0000 @@ -3,7 +3,7 @@
    -
  • <%= t('ErrorClass') %>
    +
    diff -Nru ruby-sidekiq-6.0.4+dfsg/web/views/layout.erb ruby-sidekiq-6.3.1+dfsg/web/views/layout.erb --- ruby-sidekiq-6.0.4+dfsg/web/views/layout.erb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/views/layout.erb 2021-11-18 13:57:25.000000000 +0000 @@ -11,17 +11,18 @@ <% end %> - + <% if rtl? %> <% end %> + <%= display_custom_head %> - + <%= erb :_nav %>
    diff -Nru ruby-sidekiq-6.0.4+dfsg/web/views/morgue.erb ruby-sidekiq-6.3.1+dfsg/web/views/morgue.erb --- ruby-sidekiq-6.0.4+dfsg/web/views/morgue.erb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/views/morgue.erb 2021-11-18 13:57:25.000000000 +0000 @@ -14,7 +14,7 @@
    <%= csrf_tag %>
    -
    <%= t('Queue') %>
    +
    @@ -44,7 +44,7 @@ <%= entry.display_class %> - <%= display_tags(entry, "morgue") %> + <%= display_tags(entry, "dead") %>
    <%= display_args(entry.display_args) %>
    @@ -58,18 +58,18 @@ <% end %>
    - - + + <% unfiltered? do %>
    <%= csrf_tag %> - +
    <%= csrf_tag %> - +
    <% end %> diff -Nru ruby-sidekiq-6.0.4+dfsg/web/views/_poll_link.erb ruby-sidekiq-6.3.1+dfsg/web/views/_poll_link.erb --- ruby-sidekiq-6.0.4+dfsg/web/views/_poll_link.erb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/views/_poll_link.erb 2021-11-18 13:57:25.000000000 +0000 @@ -1,7 +1,4 @@ <% if current_path != '' %> - <% if params[:poll] %> - <%= t('StopPolling') %> - <% else %> - <%= t('LivePoll') %> - <% end %> + <%= t('LivePoll') %> + <%= t('StopPolling') %> <% end %> diff -Nru ruby-sidekiq-6.0.4+dfsg/web/views/queue.erb ruby-sidekiq-6.3.1+dfsg/web/views/queue.erb --- ruby-sidekiq-6.0.4+dfsg/web/views/queue.erb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/views/queue.erb 2021-11-18 13:57:25.000000000 +0000 @@ -20,31 +20,31 @@ <%= t('Arguments') %> - <% @messages.each_with_index do |msg, index| %> - + <% @jobs.each_with_index do |job, index| %> + <% if params[:direction] == 'asc' %> <%= @count * (@current_page - 1) + index + 1 %> <% else %> <%= @total_size - (@count * (@current_page - 1) + index) %> <% end %> - <%= h(msg.display_class) %> - <%= display_tags(msg, nil) %> + <%= h(job.display_class) %> + <%= display_tags(job, nil) %> - <% a = msg.display_args %> + <% a = job.display_args %> <% if a.inspect.size > 100 %> - <%= h(a.inspect[0..100]) + "... " %> - -
    <%= display_args(a) %>
    + <%= h(a.inspect[0..100]) + "... " %> + +
    <%= display_args(a) %>
    <% else %> - <%= display_args(msg.display_args) %> + <%= display_args(job.display_args) %> <% end %>
    <%= csrf_tag %> - +
    @@ -52,4 +52,4 @@ <% end %>
    -<%= erb :_paging, locals: { url: "#{root_path}queues/#{@name}" } %> +<%= erb :_paging, locals: { url: "#{root_path}queues/#{CGI.escape(@name)}" } %> diff -Nru ruby-sidekiq-6.0.4+dfsg/web/views/queues.erb ruby-sidekiq-6.3.1+dfsg/web/views/queues.erb --- ruby-sidekiq-6.0.4+dfsg/web/views/queues.erb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/views/queues.erb 2021-11-18 13:57:25.000000000 +0000 @@ -1,7 +1,7 @@

    <%= t('Queues') %>

    - +
    @@ -21,13 +21,13 @@
    <%= t('Queue') %> <%= t('Size') %>
    <%= csrf_tag %> - + <% if Sidekiq.pro? %> <% if queue.paused? %> - + <% else %> - + <% end %> <% end %>
    diff -Nru ruby-sidekiq-6.0.4+dfsg/web/views/retries.erb ruby-sidekiq-6.3.1+dfsg/web/views/retries.erb --- ruby-sidekiq-6.0.4+dfsg/web/views/retries.erb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/views/retries.erb 2021-11-18 13:57:25.000000000 +0000 @@ -14,7 +14,7 @@
    <%= csrf_tag %>
    - +
    @@ -58,23 +58,23 @@ <% end %>
    - - - + + +
    <% unfiltered? do %>
    <%= csrf_tag %> - +
    <%= csrf_tag %> - +
    <%= csrf_tag %> - +
    <% end %> diff -Nru ruby-sidekiq-6.0.4+dfsg/web/views/retry.erb ruby-sidekiq-6.3.1+dfsg/web/views/retry.erb --- ruby-sidekiq-6.0.4+dfsg/web/views/retry.erb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/views/retry.erb 2021-11-18 13:57:25.000000000 +0000 @@ -2,7 +2,7 @@

    <%= t('Error') %>

    - +
    diff -Nru ruby-sidekiq-6.0.4+dfsg/web/views/scheduled.erb ruby-sidekiq-6.3.1+dfsg/web/views/scheduled.erb --- ruby-sidekiq-6.0.4+dfsg/web/views/scheduled.erb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/views/scheduled.erb 2021-11-18 13:57:25.000000000 +0000 @@ -15,7 +15,7 @@ <%= csrf_tag %>
    -
    <%= t('ErrorClass') %>
    +
    diff -Nru ruby-sidekiq-6.0.4+dfsg/web/views/_summary.erb ruby-sidekiq-6.3.1+dfsg/web/views/_summary.erb --- ruby-sidekiq-6.0.4+dfsg/web/views/_summary.erb 2020-02-07 11:33:46.000000000 +0000 +++ ruby-sidekiq-6.3.1+dfsg/web/views/_summary.erb 2021-11-18 13:57:25.000000000 +0000 @@ -1,39 +1,39 @@