├── .github ├── ISSUE_TEMPLATE │ └── bug_report.md ├── contributing.md ├── dependabot.yml └── workflows │ ├── depsreview.yaml │ ├── dragonfly.yml │ └── redis.yml ├── .gitignore ├── .standard.yml ├── .yardopts ├── COMM-LICENSE.txt ├── Changes.md ├── Ent-Changes.md ├── Gemfile ├── LICENSE.txt ├── Pro-Changes.md ├── README.md ├── Rakefile ├── bare ├── Gemfile ├── bare.ru ├── boot.rb └── simple.ru ├── bench ├── client.rb └── redis.rb ├── bin ├── multi_queue_bench ├── sidekiq ├── sidekiqload └── sidekiqmon ├── docs ├── 3.0-Upgrade.md ├── 4.0-Upgrade.md ├── 5.0-Upgrade.md ├── 6.0-Upgrade.md ├── 7.0-API-Migration.md ├── 7.0-Upgrade.md ├── Ent-2.0-Upgrade.md ├── Ent-7.0-Upgrade.md ├── Pro-2.0-Upgrade.md ├── Pro-3.0-Upgrade.md ├── Pro-4.0-Upgrade.md ├── Pro-5.0-Upgrade.md ├── Pro-7.0-Upgrade.md ├── SECURITY.md ├── capsule.md ├── code_of_conduct.md ├── internals.md ├── menu.md └── middleware.md ├── examples ├── busy-ui.png ├── complex_batch_workflow.png ├── complex_batch_workflow.svg ├── config.yml ├── ent-bucket.png ├── ent-concurrent.png ├── ent-periodic.png ├── metrics.png ├── metrics_job.png ├── por.rb ├── systemd │ └── sidekiq.service ├── upstart │ ├── sidekiq.conf │ └── workers.conf └── web-ui.png ├── lib ├── generators │ └── sidekiq │ │ ├── job_generator.rb │ │ └── templates │ │ ├── job.rb.erb │ │ ├── job_spec.rb.erb │ │ └── job_test.rb.erb ├── sidekiq.rb └── sidekiq │ ├── api.rb │ ├── capsule.rb │ ├── cli.rb │ ├── client.rb │ ├── component.rb │ ├── config.rb │ ├── deploy.rb │ ├── embedded.rb │ ├── fetch.rb │ ├── job.rb │ ├── job_logger.rb │ ├── job_retry.rb │ ├── job_util.rb │ ├── launcher.rb │ ├── logger.rb │ ├── manager.rb │ ├── metrics │ ├── query.rb │ ├── shared.rb │ └── tracking.rb │ ├── middleware │ ├── chain.rb │ ├── current_attributes.rb │ ├── i18n.rb │ └── modules.rb │ ├── monitor.rb │ ├── paginator.rb │ ├── processor.rb │ ├── rails.rb │ ├── redis_client_adapter.rb │ ├── redis_connection.rb │ ├── ring_buffer.rb │ ├── scheduled.rb │ ├── sd_notify.rb │ ├── systemd.rb │ ├── testing.rb │ ├── testing │ └── inline.rb │ ├── transaction_aware_client.rb │ ├── version.rb │ ├── web.rb │ ├── web │ ├── action.rb │ ├── application.rb │ ├── csrf_protection.rb │ ├── helpers.rb │ └── router.rb │ └── worker_compatibility_alias.rb ├── myapp ├── .gitattributes ├── .gitignore ├── Gemfile ├── Procfile ├── Rakefile ├── app │ ├── controllers │ │ ├── application_controller.rb │ │ └── job_controller.rb │ ├── helpers │ │ └── application_helper.rb │ ├── jobs │ │ ├── application_job.rb │ │ ├── exit_job.rb │ │ └── some_job.rb │ ├── lib │ │ └── myapp │ │ │ └── current.rb │ ├── mailers │ │ ├── .gitkeep │ │ └── user_mailer.rb │ ├── models │ │ ├── .gitkeep │ │ ├── application_record.rb │ │ ├── exiter.rb │ │ └── post.rb │ ├── sidekiq │ │ ├── exit_job.rb │ │ ├── hard_job.rb │ │ └── lazy_job.rb │ └── views │ │ ├── job │ │ └── index.html.erb │ │ ├── layouts │ │ └── application.html.erb │ │ └── user_mailer │ │ └── greetings.html.erb ├── bin │ ├── bundle │ ├── rails │ ├── rake │ └── setup ├── config.ru ├── config │ ├── application.rb │ ├── boot.rb │ ├── database.yml │ ├── environment.rb │ ├── environments │ │ ├── development.rb │ │ ├── production.rb │ │ └── test.rb │ ├── initializers │ │ ├── backtrace_silencers.rb │ │ ├── cookies_serializer.rb │ │ ├── filter_parameter_logging.rb │ │ ├── secret_token.rb │ │ ├── session_store.rb │ │ ├── sidekiq.rb │ │ └── wrap_parameters.rb │ ├── locales │ │ └── en.yml │ ├── puma.rb │ ├── routes.rb │ ├── secrets.yml │ └── sidekiq.yml ├── db │ ├── migrate │ │ └── 20120123214055_create_posts.rb │ ├── schema.rb │ └── seeds.rb └── simple.ru ├── sidekiq.gemspec ├── test ├── actors_test.rb ├── api_test.rb ├── capsule_test.rb ├── cfg │ ├── config__FILE__and__dir__.yml │ ├── config_capsules.yml │ ├── config_empty.yml │ ├── config_environment.yml │ ├── config_queues_without_weights.yml │ ├── config_string.yml │ ├── config_with_alias.yml │ └── config_with_internal_options.yml ├── cli_test.rb ├── client_test.rb ├── config.yml ├── config_test.rb ├── csrf_test.rb ├── current_attributes_test.rb ├── dead_set_test.rb ├── dummy │ ├── config │ │ ├── application.rb │ │ ├── database.yml │ │ ├── environment.rb │ │ └── sidekiq.yml │ └── tmp │ │ └── .keep ├── exception_handler_test.rb ├── fake_env.rb ├── fetch_test.rb ├── filtering_test.rb ├── fixtures │ └── en.yml ├── helper.rb ├── job_generator_test.rb ├── job_logger_test.rb ├── job_test.rb ├── launcher_test.rb ├── logger_test.rb ├── manager_test.rb ├── metrics_test.rb ├── middleware_test.rb ├── processor_test.rb ├── rails_test.rb ├── redis_connection_test.rb ├── retry_exhausted_test.rb ├── retry_test.rb ├── scheduled_test.rb ├── scheduling_test.rb ├── sharding_test.rb ├── sidekiq_test.rb ├── sidekiqmon_test.rb ├── systemd_test.rb ├── testing_fake_test.rb ├── testing_inline_test.rb ├── testing_test.rb ├── transaction_aware_client_test.rb ├── web_helpers_test.rb └── web_test.rb └── web ├── assets ├── images │ ├── apple-touch-icon.png │ ├── favicon.ico │ ├── logo.png │ └── status.png ├── javascripts │ ├── application.js │ ├── base-charts.js │ ├── chart.min.js │ ├── chartjs-plugin-annotation.min.js │ ├── dashboard-charts.js │ ├── dashboard.js │ └── metrics.js └── stylesheets │ ├── application-dark.css │ ├── application-rtl.css │ ├── application.css │ ├── bootstrap-rtl.min.css │ └── bootstrap.css ├── locales ├── ar.yml ├── cs.yml ├── da.yml ├── de.yml ├── el.yml ├── en.yml ├── es.yml ├── fa.yml ├── fr.yml ├── gd.yml ├── he.yml ├── hi.yml ├── it.yml ├── ja.yml ├── ko.yml ├── lt.yml ├── nb.yml ├── nl.yml ├── pl.yml ├── pt-br.yml ├── pt.yml ├── ru.yml ├── sv.yml ├── ta.yml ├── uk.yml ├── ur.yml ├── vi.yml ├── zh-cn.yml └── zh-tw.yml └── views ├── _footer.erb ├── _job_info.erb ├── _metrics_period_select.erb ├── _nav.erb ├── _paging.erb ├── _poll_link.erb ├── _status.erb ├── _summary.erb ├── busy.erb ├── dashboard.erb ├── dead.erb ├── filtering.erb ├── layout.erb ├── metrics.erb ├── metrics_for_job.erb ├── morgue.erb ├── queue.erb ├── queues.erb ├── retries.erb ├── retry.erb ├── scheduled.erb └── scheduled_job_info.erb /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | Ruby version: 11 | Rails version: 12 | Sidekiq / Pro / Enterprise version(s): 13 | 14 | Please include your initializer, sidekiq.yml, and any error message with the full backtrace. 15 | 16 | If you are using an old version, have you checked the changelogs to see if your issue has been fixed in a later version? 17 | 18 | https://github.com/sidekiq/sidekiq/blob/main/Changes.md 19 | https://github.com/sidekiq/sidekiq/blob/main/Pro-Changes.md 20 | https://github.com/sidekiq/sidekiq/blob/main/Ent-Changes.md 21 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "github-actions" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | -------------------------------------------------------------------------------- /.github/workflows/depsreview.yaml: -------------------------------------------------------------------------------- 1 | name: 'Dependency Review' 2 | on: [pull_request] 3 | 4 | permissions: 5 | contents: read 6 | 7 | jobs: 8 | dependency-review: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - name: 'Checkout Repository' 12 | uses: actions/checkout@v4 13 | - name: 'Dependency Review' 14 | uses: actions/dependency-review-action@v4 15 | -------------------------------------------------------------------------------- /.github/workflows/dragonfly.yml: -------------------------------------------------------------------------------- 1 | name: DragonflyDB CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | test: 14 | 15 | name: "Ruby ${{ matrix.ruby }} / Dragonfly ${{ matrix.redis }}" 16 | runs-on: ubuntu-latest 17 | 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | ruby: ["2.7", "3.0", "3.1", "3.2", "3.3"] 22 | redis: ["latest"] 23 | 24 | steps: 25 | - uses: actions/checkout@v4 26 | - name: Set up Ruby ${{ matrix.ruby }} 27 | # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby, 28 | # change this to (see https://github.com/ruby/setup-ruby#versioning): 29 | uses: ruby/setup-ruby@v1 30 | with: 31 | bundler-cache: true # 'bundle install' and cache gems 32 | ruby-version: ${{ matrix.ruby }} 33 | - name: Set up Redis ${{ matrix.redis }} 34 | uses: supercharge/redis-github-action@1.8.0 35 | with: 36 | redis-version: ${{ matrix.redis }} 37 | redis-image: docker.dragonflydb.io/dragonflydb/dragonfly 38 | - name: Run tests 39 | run: bundle exec rake 40 | -------------------------------------------------------------------------------- /.github/workflows/redis.yml: -------------------------------------------------------------------------------- 1 | name: Redis CI 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | pull_request: 7 | branches: [ "main" ] 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | test: 14 | 15 | runs-on: ubuntu-latest 16 | 17 | # on-hover of the checkmark, show "Ruby 3 / Redis 6" instead of "(3 / 6)" 18 | name: "Ruby ${{ matrix.ruby }} / Redis ${{ matrix.redis }}" 19 | 20 | strategy: 21 | fail-fast: false 22 | matrix: 23 | ruby: ["2.7", "3.0", "3.1", "3.2", "3.3"] 24 | redis: [6, 7] 25 | 26 | steps: 27 | - uses: actions/checkout@v4 28 | - name: Set up Ruby ${{ matrix.ruby }} 29 | # To automatically get bug fixes and new Ruby versions for ruby/setup-ruby, 30 | # change this to (see https://github.com/ruby/setup-ruby#versioning): 31 | uses: ruby/setup-ruby@v1 32 | with: 33 | bundler-cache: true # 'bundle install' and cache gems 34 | ruby-version: ${{ matrix.ruby }} 35 | - name: Set up Redis ${{ matrix.redis }} 36 | uses: supercharge/redis-github-action@1.8.0 37 | with: 38 | redis-version: ${{ matrix.redis }} 39 | - name: Run tests 40 | run: bundle exec rake 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .rvmrc 2 | .ruby-version 3 | tags 4 | *.swp 5 | dump.rdb 6 | .rbx 7 | coverage/ 8 | vendor/ 9 | .bundle/ 10 | .sass-cache/ 11 | tmp/ 12 | pkg/*.gem 13 | .byebug_history 14 | development.log 15 | /Dockerfile 16 | /Makefile 17 | /docker-compose.yml 18 | Gemfile.lock 19 | *.DS_Store 20 | doc/ 21 | .yardoc/ -------------------------------------------------------------------------------- /.standard.yml: -------------------------------------------------------------------------------- 1 | ruby_version: 2.7.0 2 | fix: true 3 | parallel: true 4 | ignore: 5 | - 'lib/sidekiq.rb': 6 | - Lint/InheritException 7 | - '**/*': 8 | - Lint/RescueException 9 | - Style/GlobalVars 10 | -------------------------------------------------------------------------------- /.yardopts: -------------------------------------------------------------------------------- 1 | --title "Sidekiq" 2 | --readme docs/menu.md 3 | --hide-api private 4 | lib/sidekiq/api.rb lib/sidekiq/middleware/chain.rb - Changes.md 5 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source "https://rubygems.org" 2 | 3 | gemspec 4 | 5 | gem "rake" 6 | RAILS_VERSION = "~> 7.1" 7 | gem "actionmailer", RAILS_VERSION 8 | gem "actionpack", RAILS_VERSION 9 | gem "activejob", RAILS_VERSION 10 | gem "activerecord", RAILS_VERSION 11 | gem "railties", RAILS_VERSION 12 | gem "redis-client" 13 | # gem "bumbler" 14 | # gem "debug" 15 | 16 | gem "sqlite3", "~> 1.4", platforms: :ruby 17 | gem "activerecord-jdbcsqlite3-adapter", platforms: :jruby 18 | gem "after_commit_everywhere", require: false 19 | gem "yard" 20 | 21 | group :test do 22 | gem "maxitest" 23 | gem "simplecov" 24 | end 25 | 26 | group :development, :test do 27 | gem "standard", require: false 28 | end 29 | 30 | group :load_test do 31 | gem "toxiproxy" 32 | gem "ruby-prof" 33 | end 34 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) Contributed Systems LLC 2 | 3 | Sidekiq is an Open Source project licensed under the terms of 4 | the LGPLv3 license. Please see 5 | for license text. 6 | 7 | Sidekiq Pro and Sidekiq Enterprise have a commercial-friendly license. 8 | You can find the commercial license in COMM-LICENSE.txt. 9 | Please see https://sidekiq.org for purchasing options. 10 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | require "bundler/gem_tasks" 2 | require "rake/testtask" 3 | require "standard/rake" 4 | 5 | # If you want to generate API docs: 6 | # gem install yard && yard && open doc/index.html 7 | # YARD readme: https://rubydoc.info/gems/yard/file/README.md 8 | # YARD tags: https://www.rubydoc.info/gems/yard/file/docs/Tags.md 9 | # YARD cheatsheet: https://gist.github.com/phansch/db18a595d2f5f1ef16646af72fe1fb0e 10 | 11 | # To check code coverage, include simplecov in the Gemfile and 12 | # run `COVERAGE=1 bundle exec rake` 13 | 14 | Rake::TestTask.new(:test) do |test| 15 | test.warning = true 16 | test.pattern = "test/**/*.rb" 17 | end 18 | 19 | task default: [:standard, :test] 20 | -------------------------------------------------------------------------------- /bare/Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | 5 | gem "sidekiq", path: ".." 6 | -------------------------------------------------------------------------------- /bare/bare.ru: -------------------------------------------------------------------------------- 1 | require "securerandom" 2 | require "sidekiq/web" 3 | 4 | secret_key = SecureRandom.hex(32) 5 | use Rack::Session::Cookie, secret: secret_key, same_site: true, max_age: 86400 6 | run Sidekiq::Web 7 | -------------------------------------------------------------------------------- /bare/boot.rb: -------------------------------------------------------------------------------- 1 | Sidekiq.configure_server do |config| 2 | config.redis = {db: 14} 3 | config.capsule("single") do |cap| 4 | cap.concurrency = 1 5 | cap.queues = %w[single_threaded] 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /bare/simple.ru: -------------------------------------------------------------------------------- 1 | # Easiest way to run Sidekiq::Web. 2 | # Run with "bundle exec rackup simple.ru" 3 | 4 | require "sidekiq/web" 5 | 6 | # A Web process always runs as client, no need to configure server 7 | Sidekiq.configure_client do |config| 8 | config.redis = {url: "redis://localhost:6379/0", size: 1} 9 | end 10 | 11 | Sidekiq::Client.push("class" => "HardWorker", "args" => []) 12 | 13 | # In a multi-process deployment, all Web UI instances should share 14 | # this secret key so they can all decode the encrypted browser cookies 15 | # and provide a working session. 16 | # Rails does this in /config/initializers/secret_token.rb 17 | secret_key = SecureRandom.hex(32) 18 | use Rack::Session::Cookie, secret: secret_key, same_site: true, max_age: 86400 19 | run Sidekiq::Web 20 | -------------------------------------------------------------------------------- /bench/client.rb: -------------------------------------------------------------------------------- 1 | require "benchmark/ips" 2 | require "sidekiq" 3 | require "active_job" 4 | 5 | ActiveJob::Base.logger = nil 6 | ActiveJob::Base.queue_adapter = :sidekiq 7 | 8 | class MyJob 9 | include Sidekiq::Job 10 | end 11 | 12 | class AJob < ActiveJob::Base 13 | queue_as :default 14 | end 15 | 16 | Benchmark.ips do |x| 17 | x.hold! "bench.txt" 18 | x.report("Sidekiq::Job v7") do |times| 19 | i = 0 20 | while i < times 21 | MyJob.perform_async("foo", 123, {"mike" => true}, Time.now.to_f) 22 | i += 1 23 | end 24 | end 25 | x.report("ActiveJob v#{ActiveJob.version}") do |times| 26 | i = 0 27 | while i < times 28 | AJob.perform_later(:foo, 123, {mike: 0..5}, Time.now) 29 | i += 1 30 | end 31 | end 32 | x.report("Sidekiq::Job v8") do |times| 33 | Sidekiq::JSON.flavor!(:v8) 34 | i = 0 35 | while i < times 36 | MyJob.perform_async(:foo, 123, {"mike" => 0..5}, Time.now) 37 | i += 1 38 | end 39 | end 40 | end 41 | 42 | # 43 | # Local results: 44 | # 45 | # Sidekiq::Job v7 20.076k (± 1.2%) i/s - 100.940k in 5.028478s 46 | # Sidekiq::Job v8 19.177k (± 0.6%) i/s - 97.410k in 5.079620s 47 | # ActiveJob v7.0.8.1 11.793k (± 1.4%) i/s - 60.078k in 5.095490s 48 | # 49 | # Sidekiq's v8 flavor gets you support for many more Ruby types with 50 | # almost no performance penalty. 51 | -------------------------------------------------------------------------------- /bin/sidekiq: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | # Quiet some warnings we see when running in warning mode: 4 | # RUBYOPT=-w bundle exec sidekiq 5 | $TESTING = false 6 | 7 | require_relative "../lib/sidekiq/cli" 8 | 9 | def integrate_with_systemd 10 | return unless ENV["NOTIFY_SOCKET"] 11 | 12 | Sidekiq.configure_server do |config| 13 | config.logger.info "Enabling systemd notification integration" 14 | require "sidekiq/sd_notify" 15 | config.on(:startup) do 16 | Sidekiq::SdNotify.ready 17 | end 18 | config.on(:shutdown) do 19 | Sidekiq::SdNotify.stopping 20 | end 21 | Sidekiq.start_watchdog if Sidekiq::SdNotify.watchdog? 22 | end 23 | end 24 | 25 | begin 26 | cli = Sidekiq::CLI.instance 27 | cli.parse 28 | 29 | integrate_with_systemd 30 | 31 | cli.run 32 | rescue => e 33 | raise e if $DEBUG 34 | warn e.message 35 | warn e.backtrace.join("\n") 36 | exit 1 37 | end 38 | -------------------------------------------------------------------------------- /bin/sidekiqmon: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require "sidekiq/monitor" 4 | 5 | # disable the Redis connection pool logging 6 | Sidekiq.default_configuration.logger.level = :warn 7 | 8 | section = "all" 9 | section = ARGV[0] if ARGV.size == 1 10 | 11 | Sidekiq::Monitor::Status.new.display(section) 12 | -------------------------------------------------------------------------------- /docs/4.0-Upgrade.md: -------------------------------------------------------------------------------- 1 | # Welcome to Sidekiq 4.0! 2 | 3 | Sidekiq 4.0 contains a redesigned, more efficient core with less overhead per job. 4 | See my blog for [an overview of Sidekiq 4's higher performance](http://www.mikeperham.com/2015/10/14/optimizing-sidekiq/). 5 | 6 | ## What's New 7 | 8 | * Sidekiq no longer uses Celluloid. If your application code uses Celluloid, 9 | you will need to pull it in yourself. 10 | 11 | * `redis-namespace` has been removed from Sidekiq's gem dependencies. If 12 | 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: 13 | ```ruby 14 | gem 'redis-namespace' 15 | ``` 16 | 17 | * **Redis 2.8.0 or greater is required.** Redis 2.8 was released two years 18 | ago and contains **many** useful features which Sidekiq couldn't 19 | leverage until now. **Redis 3.0.3 or greater is recommended** for large 20 | scale use [#2431](https://github.com/mperham/sidekiq/issues/2431). 21 | 22 | * Jobs are now fetched from Redis in parallel, making Sidekiq more 23 | resilient to high network latency. This means that Sidekiq requires 24 | more Redis connections per process. You must have a minimum of 25 | `concurrency + 2` connections in your pool or Sidekiq will exit. 26 | When in doubt, let Sidekiq size the connection pool for you. 27 | 28 | * Worker data is no longer updated in real-time but rather upon every 29 | heartbeat. Don't expect the `Sidekiq::Workers` API to be millisecond-precise. 30 | 31 | * There's a new testing API based off the `Sidekiq::Queues` namespace. All 32 | assertions made against the Worker class still work as expected. 33 | ```ruby 34 | assert_equal 0, Sidekiq::Queues["default"].size 35 | HardWorker.perform_async("log") 36 | assert_equal 1, Sidekiq::Queues["default"].size 37 | assert_equal "log", Sidekiq::Queues["default"].first['args'][0] 38 | Sidekiq::Queues.clear_all 39 | ``` 40 | 41 | ## Upgrade 42 | 43 | First, make sure you are using Redis 2.8 or greater. Next: 44 | 45 | * Upgrade to the latest Sidekiq 3.x. 46 | ```ruby 47 | gem 'sidekiq', '< 4' 48 | ``` 49 | * Fix any deprecation warnings you see. 50 | * Upgrade to 4.x. 51 | ```ruby 52 | gem 'sidekiq', '< 5' 53 | ``` 54 | -------------------------------------------------------------------------------- /docs/5.0-Upgrade.md: -------------------------------------------------------------------------------- 1 | # Welcome to Sidekiq 5.0! 2 | 3 | Sidekiq 5.0 contains a reworked job dispatch and execution core to integrate 4 | better with the new Rails 5.0 Executor. It also drops support for older 5 | versions of Ruby and Rails and adds support for RTL languages in the Web UI. 6 | 7 | ## What's New 8 | 9 | * Integrate job logging and retry logic directly in with the job 10 | execution logic in Sidekiq::Processor. Previously this logic was 11 | defined as middleware. In Rails 5.0, ActiveSupport::Executor handles ActiveRecord 12 | connection management, job callbacks, development mode class loading, 13 | etc. Because of its extensive responsibilities, the Executor can't be 14 | integrated as Sidekiq middleware; the logging/retry logic had to be pulled out 15 | too. Sidekiq 4.2 had a hack to make it work but this redesign provides 16 | a cleaner integration. [#3235] 17 | * The Delayed Extensions `delay`, `delay_for` and `delay_until` APIs are 18 | no longer available by default. The extensions allow you to marshal 19 | job arguments as YAML, leading to cases where job payloads could be many 20 | 100s of KB or larger if not careful, leading to Redis networking 21 | timeouts or other problems. As noted in the Best Practices wiki page, 22 | Sidekiq is designed for jobs with small, simple arguments. 23 | 24 | Add this line to your initializer to re-enable them and get the old behavior: 25 | ```ruby 26 | Sidekiq::Extensions.enable_delay! 27 | ``` 28 | The old `Sidekiq.remove_delay!` API has been removed as it is now the default. [#3299] 29 | * Sidekiq's quiet signal is now `TSTP` (think of it as **T**hread 30 | **ST**o**P**) instead of USR1 as USR1 is not available on JRuby. 31 | USR1 will continue to be supported in Sidekiq 5.x for backwards 32 | compatibility and will be removed in Sidekiq 6.x. [#3302] 33 | * The Web UI is now bi-directional - it can render either LTR 34 | (left-to-right) or RTL languages. With this change, **Farsi, Arabic, 35 | Hebrew and Urdu** are officially supported. [#3381] 36 | * Jobs which can't be parsed due to invalid JSON are now pushed 37 | immediately to the Dead set since they require manual intervention and 38 | will never execute successfully as is. The Web UI has been updated to 39 | more gracefully display these jobs. [#3296] 40 | * **Rails 3.2** is no longer supported. 41 | * **Ruby 2.0 and Ruby 2.1** are no longer supported. Ruby 2.2.2+ is required. 42 | 43 | ## Upgrade 44 | 45 | As always, please upgrade Sidekiq **one major version at a time**. 46 | If you are already running Sidekiq 4.x, then: 47 | 48 | * Upgrade to the latest Sidekiq 4.x. 49 | ```ruby 50 | gem 'sidekiq', '< 5' 51 | ``` 52 | * Fix any deprecation warnings you see. 53 | * Upgrade to 5.x. 54 | ```ruby 55 | gem 'sidekiq', '< 6' 56 | ``` 57 | -------------------------------------------------------------------------------- /docs/7.0-API-Migration.md: -------------------------------------------------------------------------------- 1 | # Sidekiq 7.0 API Migration Guide 2 | 3 | Sidekiq 7.0 has some significant API refactoring, meaning an upgrade can be harder than usual for people who are touching Sidekiq's APIs in their initializer. 4 | 5 | ## Logging 6 | 7 | ```ruby 8 | # broken, logger is no longer a top-level attribute 9 | Sidekiq.logger = ... 10 | 11 | # fixed 12 | Sidekiq.configure_server do |cfg| 13 | cfg.logger = ... 14 | end 15 | ``` 16 | 17 | Custom log formatter is a part of new logger API 18 | ```ruby 19 | # broken 20 | Sidekiq.configure_server do |cfg| 21 | cfg.log_formatter = ... 22 | end 23 | 24 | # fixed 25 | Sidekiq.configure_server do |cfg| 26 | cfg.logger.formatter = ... 27 | end 28 | ``` 29 | 30 | ## Connection Pools 31 | 32 | Sidekiq no longer allows raw ConnectionPools as people were often 33 | undersizing the pool leading to terrible performance. 34 | This way Sidekiq will automatically tune the size based on concurrency settings. 35 | Pools are lazy-loaded so they do not create connections until the system actually needs them. 36 | 37 | ```ruby 38 | # broken, can't pass connection pools directly anymore 39 | POOL1 = ConnectionPool.new(size: 5) { Redis.new(ENV['MY_REDIS_URL']) } 40 | Sidekiq.configure_server do |cfg| 41 | cfg.redis = POOL1 42 | end 43 | 44 | # fixed 45 | Sidekiq.configure_server do |cfg| 46 | cfg.redis = { url: ENV['MY_REDIS_URL'] } 47 | end 48 | ``` 49 | 50 | ## Redis sentinels 51 | 52 | Due to Sidekiq's use of the new redis-client gem for connections, the configuration for it has changed. 53 | More details - https://github.com/redis-rb/redis-client#sentinel-support 54 | 55 | ```ruby 56 | # broken - missing name keyword argument 57 | Sidekiq.configure_server do |cfg| 58 | cfg.redis = { 59 | url: "redis://myredis/0", 60 | sentinels: [ 61 | {host: "host1", port: 26379}, 62 | {host: "host2", port: 26379}, 63 | {host: "host3", port: 26379} 64 | ] 65 | } 66 | end 67 | 68 | # fixed - don't forget to fix connection settings for both client and server 69 | Sidekiq.configure_server do |cfg| 70 | cfg.redis = { 71 | url: "redis://myredis/0", 72 | name: "primary", 73 | sentinels: [ 74 | {host: "host1", port: 26379}, 75 | {host: "host2", port: 26379}, 76 | {host: "host3", port: 26379} 77 | ] 78 | } 79 | end 80 | ``` 81 | 82 | ## Reading Configuration 83 | 84 | ```ruby 85 | Sidekiq.configure_server do |cfg| 86 | cfg[:average_scheduled_poll_interval] = 5 87 | end 88 | 89 | # broken, can not read configuration directly anymore 90 | Sidekiq[:average_scheduled_poll_interval] NoMethodError: undefined method '[]' for Sidekiq:Module 91 | 92 | # fixed 93 | Sidekiq.default_configuration[:average_scheduled_poll_interval] # 5 94 | ``` 95 | 96 | Have more APIs which need a migration tip? Edit this file and open a PR! 97 | -------------------------------------------------------------------------------- /docs/Ent-2.0-Upgrade.md: -------------------------------------------------------------------------------- 1 | # Welcome to Sidekiq Enterprise 2.0! 2 | 3 | Sidekiq Enterprise 2.0 adds a few new features and adds the requirement that license 4 | credentials be available at runtime. Note that Sidekiq 6.0 does have major breaking changes. 5 | 6 | ## What's New 7 | 8 | * Sidekiq Enterprise now requires license credentials at runtime. If you 9 | configured Bundler as described in the access email you need do 10 | nothing, everything should just work. If you are vendoring Sidekiq 11 | Enterprise you will need to configure Bundler also or set 12 | `SIDEKIQ_ENT_USERNAME=abcdef12 bundle exec sidekiq...` when starting the 13 | process. [#4232] 14 | * Dead jobs now release any unique locks they were holding when they died [#4162] 15 | * Backoff can now be customized per rate limiter by passing in a Proc [#4219] 16 | ```ruby 17 | limiter = Sidekiq::Limiter.bucket(:stripe, 10, :second, backoff: ->(limiter, job) { 18 | return job['overrated'] || 5 # wait for N seconds, where N is the number of 19 | # times we've failed the rate limit 20 | }) 21 | ``` 22 | * Removed deprecated APIs and warnings. 23 | * Various changes for Sidekiq 6.0 24 | * Requires Ruby 2.5+ and Redis 4.0+ 25 | * Requires Sidekiq 6.0+ and Sidekiq Pro 5.0+ 26 | 27 | ## Upgrade 28 | 29 | * Upgrade to the latest Sidekiq Enterprise 1.x. 30 | ```ruby 31 | gem 'sidekiq-ent', '< 2' 32 | ``` 33 | * Fix any deprecation warnings you see. 34 | * Upgrade to 2.x. 35 | ```ruby 36 | gem 'sidekiq-ent', '< 3' 37 | ``` 38 | -------------------------------------------------------------------------------- /docs/Ent-7.0-Upgrade.md: -------------------------------------------------------------------------------- 1 | # Welcome to Sidekiq Enterprise 7.0 2 | 3 | Sidekiq Enterprise 7.0 contains some breaking changes which refactor internals, remove deprecated features and update required dependency versions. 4 | 5 | Note that major versions 3-6 were skipped in order to synchronize Sidekiq Enterprise's major version number with Sidekiq 7. 6 | 7 | ## What's New 8 | 9 | ### Refactoring internals 10 | 11 | Sidekiq 7.0's new Embedding support required substantial refactoring of Enterprise internals. 12 | I've tried to maintain compatibility where possible. 13 | 14 | ## Unique Locks in Version 7.0.4 15 | 16 | Sidekiq Enterprise v7.0.4 accidentally broke data compatibility with unique 17 | locks set by previous versions. You may see duplicate jobs for a short 18 | period until the new-style locks are populated in Redis. 19 | 20 | ## Version Support 21 | 22 | - Redis 6.2+ is now required 23 | - Ruby 2.7+ is now required 24 | - Rails 6.0+ is now supported 25 | 26 | Support is only guaranteed for the current and previous major versions. 27 | With the release of Sidekiq Enterprise 7, Sidekiq Enterprise 1.x is no longer supported. 28 | 29 | ## Upgrading 30 | 31 | Upgrade your Sidekiq gems with `bundle up sidekiq-ent`. 32 | This will pull upgrades for sidekiq-ent, sidekiq-pro, sidekiq and all lower-level dependent gems. 33 | 34 | **Warning**: using `bundle up sidekiq` can lead to incompatible gem versions in use. -------------------------------------------------------------------------------- /docs/Pro-3.0-Upgrade.md: -------------------------------------------------------------------------------- 1 | # Welcome to Sidekiq Pro 3.0! 2 | 3 | Sidekiq Pro 3.0 is designed to work with Sidekiq 4.0. 4 | 5 | ## What's New 6 | 7 | * **Redis 2.8.0 or greater is required.** Redis 2.8 was released two years 8 | ago and contains **many** useful features which Sidekiq couldn't 9 | leverage until now. **Redis 3.0.3 or greater is recommended** for large 10 | scale use. 11 | 12 | * Sidekiq Pro no longer uses Celluloid. If your application code uses Celluloid, 13 | you will need to pull it in yourself. 14 | 15 | * Pausing and unpausing queues is now instantaneous, no more polling! 16 | 17 | * Reliable fetch has been re-implemented due to the fetch changes in 18 | Sidekiq 4.0. 19 | 20 | * Support for platforms without persistent hostnames. Since the reliable\_fetch 21 | algorithm requires a persistent hostname, an alternative reliability 22 | algorithm is now available for platforms like Heroku and Docker: 23 | ```ruby 24 | Sidekiq.configure_server do |config| 25 | config.timed_fetch! 26 | end 27 | ``` 28 | The wiki contains [much more detail about each reliability option](https://github.com/mperham/sidekiq/wiki/Pro-Reliability-Server). 29 | 30 | * The old 'sidekiq/notifications' features have been removed. 31 | 32 | ## Upgrade 33 | 34 | First, make sure you are using Redis 2.8 or greater. Next: 35 | 36 | * Upgrade to the latest Sidekiq Pro 2.x. 37 | ```ruby 38 | gem 'sidekiq-pro', '< 3' 39 | ``` 40 | * Fix any deprecation warnings you see. 41 | * Upgrade to 3.x. 42 | ```ruby 43 | gem 'sidekiq-pro', '< 4' 44 | ``` 45 | -------------------------------------------------------------------------------- /docs/Pro-4.0-Upgrade.md: -------------------------------------------------------------------------------- 1 | # Welcome to Sidekiq Pro 4.0! 2 | 3 | Sidekiq Pro 4.0 is designed to work with Sidekiq 5.0. 4 | 5 | ## What's New 6 | 7 | * Batches now "die" if any of their jobs die. You can enumerate the set 8 | of dead batches and their associated dead jobs. The success callback 9 | for a dead batch will never fire unless these jobs are fixed. 10 | ```ruby 11 | Sidekiq::Batch::DeadSet.new.each do |status| 12 | status.dead? # => true 13 | status.dead_jobs # => [...] 14 | end 15 | ``` 16 | This API allows you to enumerate the batches which need help. 17 | If you fix the issue and the dead jobs succeed, the batch will succeed. 18 | * The older `reliable_fetch` and `timed_fetch` algorithms have been 19 | removed. Only super\_fetch is available in 4.0. 20 | * The statsd middleware has been tweaked to remove support for legacy, 21 | pre-3.6.0 configuration and add relevant tags. 22 | * Requires Sidekiq 5.0.5+. 23 | 24 | ## Upgrade 25 | 26 | * Upgrade to the latest Sidekiq Pro 3.x. 27 | ```ruby 28 | gem 'sidekiq-pro', '< 4' 29 | ``` 30 | * Fix any deprecation warnings you see. 31 | * Upgrade to 4.x. 32 | ```ruby 33 | gem 'sidekiq-pro', '< 5' 34 | ``` 35 | 36 | -------------------------------------------------------------------------------- /docs/Pro-5.0-Upgrade.md: -------------------------------------------------------------------------------- 1 | # Welcome to Sidekiq Pro 5.0! 2 | 3 | Sidekiq Pro 5.0 is mainly a cleanup release for Sidekiq 6.0. The 4 | migration should be as close to trivial as a major version bump can be. 5 | Note that Sidekiq 6.0 does have major breaking changes. 6 | 7 | ## What's New 8 | 9 | * New localizations for the Sidekiq Pro Web UI: ES, ZH, PT, JA, RU 10 | * Removed deprecated APIs and warnings. 11 | * Various changes for Sidekiq 6.0 12 | * Requires Ruby 2.5+ and Redis 4.0+ 13 | * Requires Sidekiq 6.0+. 14 | 15 | ## Upgrade 16 | 17 | * Upgrade to the latest Sidekiq Pro 4.x. 18 | ```ruby 19 | gem 'sidekiq-pro', '< 5' 20 | ``` 21 | * Fix any deprecation warnings you see. 22 | * Upgrade to 5.x. 23 | ```ruby 24 | gem 'sidekiq-pro', '< 6' 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/Pro-7.0-Upgrade.md: -------------------------------------------------------------------------------- 1 | # Welcome to Sidekiq Pro 7.0 2 | 3 | Sidekiq Pro 7.0 contains some breaking changes which refactor internals, remove deprecated features and update required dependency versions. 4 | 5 | Note that version 6.x was skipped in order to synchronize Sidekiq Pro's major version number with Sidekiq 7. 6 | 7 | ## What's New 8 | 9 | ### Refactoring internals 10 | 11 | Sidekiq 7.0's new Embedding support required substantial refactoring of Pro internals. 12 | I've tried to maintain compatibility where possible. 13 | 14 | ### Remove statsd 15 | 16 | The `statsd-ruby` gem doesn't see much maintenance these days whereas the `dogstatsd-ruby` gem is active and still adding features. 17 | For this reason, statsd support has been removed and the configuration method has changed slightly: 18 | 19 | ```ruby 20 | Sidekiq::Pro.dogstatsd = -> { Datadog::Statsd.new("localhost", 8125) } # old way 21 | 22 | Sidekiq.configure_server do |config| 23 | config.dogstatsd = -> { Datadog::Statsd.new("localhost", 8125) } # new way 24 | end 25 | ``` 26 | 27 | ## Version Support 28 | 29 | - Redis 6.2+ is now required 30 | - Ruby 2.7+ is now required 31 | - Rails 6.0+ is now supported 32 | 33 | Support is only guaranteed for the current and previous major versions. With the release of Sidekiq Pro 7, Sidekiq Pro 4.x is no longer supported. 34 | 35 | ## Upgrading 36 | 37 | Upgrade your Sidekiq gems with `bundle up sidekiq-pro`. 38 | This will pull upgrades for sidekiq-pro, sidekiq and all lower-level dependent gems. 39 | 40 | **Warning**: using `bundle up sidekiq` can lead to incompatible gem versions in use. -------------------------------------------------------------------------------- /docs/SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting a Vulnerability 4 | 5 | Please report security issues to `info@contribsys.com` -------------------------------------------------------------------------------- /docs/code_of_conduct.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, and in the interest of 4 | fostering an open and welcoming community, we pledge to respect all people who 5 | contribute through reporting issues, posting feature requests, updating 6 | documentation, submitting pull requests or patches, and other activities. 7 | 8 | We are committed to making participation in this project a harassment-free 9 | experience for everyone, regardless of level of experience, gender, gender 10 | identity and expression, sexual orientation, disability, personal appearance, 11 | body size, race, ethnicity, age, religion, or nationality. 12 | 13 | Examples of unacceptable behavior by participants include: 14 | 15 | * The use of sexualized language or imagery 16 | * Personal attacks 17 | * Trolling or insulting/derogatory comments 18 | * Public or private harassment 19 | * Publishing other's private information, such as physical or electronic 20 | addresses, without explicit permission 21 | * Other unethical or unprofessional conduct 22 | 23 | Project maintainers have the right and responsibility to remove, edit, or 24 | reject comments, commits, code, wiki edits, issues, and other contributions 25 | that are not aligned to this Code of Conduct, or to ban temporarily or 26 | permanently any contributor for other behaviors that they deem inappropriate, 27 | threatening, offensive, or harmful. 28 | 29 | By adopting this Code of Conduct, project maintainers commit themselves to 30 | fairly and consistently applying these principles to every aspect of managing 31 | this project. Project maintainers who do not follow or enforce the Code of 32 | Conduct may be permanently removed from the project team. 33 | 34 | This Code of Conduct applies both within project spaces and in public spaces 35 | when an individual is representing the project or its community. 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 38 | reported by contacting the project maintainer at mperham AT gmail.com. All 39 | complaints will be reviewed and investigated and will result in a response that 40 | is deemed necessary and appropriate to the circumstances. Maintainers are 41 | obligated to maintain confidentiality with regard to the reporter of an 42 | incident. 43 | 44 | 45 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 46 | version 1.3.0, available at 47 | [http://contributor-covenant.org/version/1/3/0/][version] 48 | 49 | [homepage]: http://contributor-covenant.org 50 | [version]: http://contributor-covenant.org/version/1/3/0/ 51 | -------------------------------------------------------------------------------- /docs/menu.md: -------------------------------------------------------------------------------- 1 | # Sidekiq public API documentation 2 | 3 | Sidekiq provides a number of public APIs for various functionality. 4 | 5 | 1. Middleware 6 | 2. Lifecycle Events 7 | 3. Data API 8 | 4. Components 9 | 10 | ## Middleware 11 | 12 | Middleware run around the the client-side push and the server-side execution of jobs. This allows plugins which mutate job data or provide additional functionality during the executing of specific jobs. 13 | 14 | ## Lifecycle Events 15 | 16 | With lifecycle events, Sidekiq plugins can register a callback upon `startup`, `quiet` or `shutdown`. 17 | This is useful for starting and stopping your own Threads or services within the Sidekiq process. 18 | 19 | ## Data API 20 | 21 | The code in `sidekiq/api` provides a Ruby facade on top of Sidekiq's persistent data within Redis. 22 | It contains many classes and methods for discovering, searching and iterating through the real-time job data within the queues and sets inside Redis. 23 | This API powers the Sidekiq::Web UI. -------------------------------------------------------------------------------- /docs/middleware.md: -------------------------------------------------------------------------------- 1 | # Middleware Changes in Sidekiq 7.0 2 | 3 | With the internal refactoring in Sidekiq 7.0 it is necessary 4 | to make minor changes to the Middleware API. 5 | 6 | > tl;dr - middleware should now include Sidekiq::ClientMiddleware or Sidekiq::ServerMiddleware. 7 | 8 | Currently the middleware API looks like this: 9 | 10 | ## Existing Client API 11 | 12 | Client middleware is run when pushing a job to Redis. 13 | 14 | ```ruby 15 | class Client 16 | def initialize(optional_args) 17 | @args = optional_args 18 | end 19 | def call(worker, job, queue, redis_pool) 20 | yield 21 | end 22 | end 23 | 24 | Sidekiq.configure_client do |config| 25 | config.client_middleware do |chain| 26 | chain.add Client, optional_args 27 | end 28 | end 29 | ``` 30 | 31 | ## Server 32 | 33 | Server middleware is run around job execution. 34 | 35 | ```ruby 36 | class Server 37 | def initialize(optional_args) 38 | @args = optional_args 39 | end 40 | def call(worker, job, queue) 41 | Sidekiq.redis {|c| c.do_something } 42 | Sidekiq.logger.info { "Some message" } 43 | yield 44 | end 45 | end 46 | 47 | Sidekiq.configure_server do |config| 48 | config.server_middleware do |chain| 49 | chain.add Server, optional_args 50 | end 51 | end 52 | ``` 53 | 54 | ## Updated API 55 | 56 | The updated middleware API requires the middleware class to include 57 | a helper module. 58 | 59 | ```ruby 60 | class Client 61 | include Sidekiq::ClientMiddleware 62 | 63 | def initialize(optional_args) 64 | @args = optional_args 65 | end 66 | # @see https://github.com/sidekiq/sidekiq/wiki/Middleware 67 | def call(job_class_or_string, job, queue, redis_pool) 68 | yield 69 | end 70 | end 71 | ``` 72 | 73 | ```ruby 74 | class Server 75 | include Sidekiq::ServerMiddleware 76 | 77 | def initialize(optional_args) 78 | @args = optional_args 79 | end 80 | 81 | # @see https://github.com/sidekiq/sidekiq/wiki/Middleware 82 | def call(job_instance, job_payload, queue) 83 | # note we no longer need to use the global Sidekiq module 84 | # to access Redis and the logger 85 | redis {|c| c.do_something } 86 | logger.info { "Some message" } 87 | yield 88 | end 89 | end 90 | ``` 91 | -------------------------------------------------------------------------------- /examples/busy-ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/touchasky/sidekiq/dddf20bf0a6decfa6e19b04611fcb3a281d009a3/examples/busy-ui.png -------------------------------------------------------------------------------- /examples/complex_batch_workflow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/touchasky/sidekiq/dddf20bf0a6decfa6e19b04611fcb3a281d009a3/examples/complex_batch_workflow.png -------------------------------------------------------------------------------- /examples/config.yml: -------------------------------------------------------------------------------- 1 | # Sample configuration file for Sidekiq. 2 | # 3 | # Options here can still be overridden by cmd line args. 4 | # Place this file at config/sidekiq.yml and Sidekiq will pick it up automatically. 5 | --- 6 | # :verbose: false 7 | # :timeout: 25 8 | 9 | # Raising concurrency can cause CPU overload. For example, Heroku's basic dynos have very little CPU compared to modern servers. 10 | # :concurrency: 5 11 | 12 | # Concurrency can be overridden based on environment as well. 13 | # production: 14 | # :concurrency: 5 15 | # staging: 16 | # :concurrency: 5 17 | 18 | # Sidekiq will run this file through ERB when reading it so you can even put in dynamic logic, like a host-specific queue. 19 | # http://www.mikeperham.com/2013/11/13/advanced-sidekiq-host-specific-queues/ 20 | :queues: 21 | - critical 22 | - default 23 | - <%= `hostname`.strip %> 24 | - mailers 25 | - active_storage_analysis 26 | - active_storage_purge 27 | - action_mailbox_routing 28 | - action_mailbox_incineration 29 | - low 30 | -------------------------------------------------------------------------------- /examples/ent-bucket.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/touchasky/sidekiq/dddf20bf0a6decfa6e19b04611fcb3a281d009a3/examples/ent-bucket.png -------------------------------------------------------------------------------- /examples/ent-concurrent.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/touchasky/sidekiq/dddf20bf0a6decfa6e19b04611fcb3a281d009a3/examples/ent-concurrent.png -------------------------------------------------------------------------------- /examples/ent-periodic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/touchasky/sidekiq/dddf20bf0a6decfa6e19b04611fcb3a281d009a3/examples/ent-periodic.png -------------------------------------------------------------------------------- /examples/metrics.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/touchasky/sidekiq/dddf20bf0a6decfa6e19b04611fcb3a281d009a3/examples/metrics.png -------------------------------------------------------------------------------- /examples/metrics_job.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/touchasky/sidekiq/dddf20bf0a6decfa6e19b04611fcb3a281d009a3/examples/metrics_job.png -------------------------------------------------------------------------------- /examples/por.rb: -------------------------------------------------------------------------------- 1 | require "sidekiq" 2 | 3 | # Start up sidekiq via 4 | # bundle exec bin/sidekiq -r ./examples/por.rb 5 | # and then you can open up an IRB session like so: 6 | # bundle exec irb -r ./examples/por.rb 7 | # where you can then say 8 | # PlainOldRuby.perform_async "like a dog", 3 9 | # 10 | class PlainOldRuby 11 | include Sidekiq::Job 12 | 13 | def perform(how_hard = "super hard", how_long = 1) 14 | sleep how_long 15 | puts "Workin' #{how_hard}" 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /examples/upstart/sidekiq.conf: -------------------------------------------------------------------------------- 1 | # /etc/init/sidekiq.conf - Sidekiq config 2 | 3 | # This example config should work with Ubuntu 12.04+. It 4 | # allows you to manage multiple Sidekiq instances with 5 | # Upstart, Ubuntu's native service management tool. 6 | # 7 | # See workers.conf for how to manage all Sidekiq instances at once. 8 | # 9 | # Save this config as /etc/init/sidekiq.conf then manage sidekiq with: 10 | # sudo start sidekiq index=0 11 | # sudo stop sidekiq index=0 12 | # sudo status sidekiq index=0 13 | # 14 | # Hack Upstart's reload command to 'quiet' Sidekiq: 15 | # 16 | # sudo reload sidekiq index=0 17 | # 18 | # or use the service command: 19 | # sudo service sidekiq {start,stop,restart,status} 20 | # 21 | 22 | description "Sidekiq Background Worker" 23 | 24 | # This script is not meant to start on bootup, workers.conf 25 | # will start all sidekiq instances explicitly when it starts. 26 | #start on runlevel [2345] 27 | #stop on runlevel [06] 28 | 29 | # change to match your deployment user 30 | # setuid deploy 31 | # setgid deploy 32 | # env HOME=/home/deploy 33 | 34 | # Greatly reduce Ruby memory fragmentation and heap usage 35 | # https://www.mikeperham.com/2018/04/25/taming-rails-memory-bloat/ 36 | env MALLOC_ARENA_MAX=2 37 | 38 | respawn 39 | respawn limit 3 30 40 | 41 | # TERM is used when stopping sidekiq. Without declaring these as 42 | # normal exit codes, it just respawns. 43 | normal exit 0 TERM 44 | 45 | # Older versions of Upstart might not support the reload command and need 46 | # this commented out. 47 | reload signal TSTP 48 | 49 | # Upstart waits 5 seconds by default to kill a process. Increase timeout to 50 | # give sidekiq process enough time to exit. 51 | kill timeout 30 52 | 53 | instance $index 54 | 55 | script 56 | # this script runs in /bin/sh by default 57 | # respawn as bash so we can source in rbenv 58 | exec /bin/bash <<'EOT' 59 | # Pick your poison :) Or none if you're using a system wide installed Ruby. 60 | # rbenv 61 | # source /home/apps/.bash_profile 62 | # OR 63 | # source /home/apps/.profile 64 | # OR system: 65 | # source /etc/profile.d/rbenv.sh 66 | # 67 | # rvm 68 | # source /home/apps/.rvm/scripts/rvm 69 | 70 | # Logs out to /var/log/upstart/sidekiq.log by default 71 | 72 | cd /var/www/app 73 | exec bundle exec sidekiq -e production 74 | EOT 75 | end script 76 | -------------------------------------------------------------------------------- /examples/upstart/workers.conf: -------------------------------------------------------------------------------- 1 | # /etc/init/workers.conf - manage a set of Sidekiqs 2 | 3 | # This example config should work with Ubuntu 14.10 and below It 4 | # allows you to manage multiple Sidekiq instances with 5 | # Upstart, Ubuntu's native service management tool. 6 | # 7 | # See sidekiq.conf for how to manage a single Sidekiq instance. 8 | # 9 | # Use "stop workers" to stop all Sidekiq instances. 10 | # Use "start workers" to start all instances. 11 | # Use "restart workers" to restart all instances. 12 | # Crazy, right? 13 | # 14 | 15 | description "manages the set of sidekiq processes" 16 | 17 | # This starts upon bootup and stops on shutdown 18 | start on runlevel [2345] 19 | stop on runlevel [06] 20 | 21 | # Set this to the number of Sidekiq processes you want 22 | # to run on this machine 23 | env NUM_WORKERS=2 24 | 25 | pre-start script 26 | for i in `seq 1 ${NUM_WORKERS}` 27 | do 28 | start sidekiq index=$i 29 | done 30 | end script 31 | 32 | post-stop script 33 | for i in `seq 1 ${NUM_WORKERS}` 34 | do 35 | stop sidekiq index=$i 36 | done 37 | end script 38 | -------------------------------------------------------------------------------- /examples/web-ui.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/touchasky/sidekiq/dddf20bf0a6decfa6e19b04611fcb3a281d009a3/examples/web-ui.png -------------------------------------------------------------------------------- /lib/generators/sidekiq/job_generator.rb: -------------------------------------------------------------------------------- 1 | require "rails/generators/named_base" 2 | 3 | module Sidekiq 4 | module Generators # :nodoc: 5 | class JobGenerator < ::Rails::Generators::NamedBase # :nodoc: 6 | desc "This generator creates a Sidekiq Job in app/sidekiq and a corresponding test" 7 | 8 | check_class_collision suffix: "Job" 9 | 10 | def self.default_generator_root 11 | File.dirname(__FILE__) 12 | end 13 | 14 | def create_job_file 15 | template "job.rb.erb", File.join("app/sidekiq", class_path, "#{file_name}_job.rb") 16 | end 17 | 18 | def create_test_file 19 | return unless test_framework 20 | 21 | if test_framework == :rspec 22 | create_job_spec 23 | else 24 | create_job_test 25 | end 26 | end 27 | 28 | private 29 | 30 | def create_job_spec 31 | template_file = File.join( 32 | "spec/sidekiq", 33 | class_path, 34 | "#{file_name}_job_spec.rb" 35 | ) 36 | template "job_spec.rb.erb", template_file 37 | end 38 | 39 | def create_job_test 40 | template_file = File.join( 41 | "test/sidekiq", 42 | class_path, 43 | "#{file_name}_job_test.rb" 44 | ) 45 | template "job_test.rb.erb", template_file 46 | end 47 | 48 | def file_name 49 | @_file_name ||= super.sub(/_?job\z/i, "") 50 | end 51 | 52 | def test_framework 53 | ::Rails.application.config.generators.options[:rails][:test_framework] 54 | end 55 | end 56 | end 57 | end 58 | -------------------------------------------------------------------------------- /lib/generators/sidekiq/templates/job.rb.erb: -------------------------------------------------------------------------------- 1 | <% module_namespacing do -%> 2 | class <%= class_name %>Job 3 | include Sidekiq::Job 4 | 5 | def perform(*args) 6 | # Do something 7 | end 8 | end 9 | <% end -%> -------------------------------------------------------------------------------- /lib/generators/sidekiq/templates/job_spec.rb.erb: -------------------------------------------------------------------------------- 1 | require 'rails_helper' 2 | <% module_namespacing do -%> 3 | RSpec.describe <%= class_name %>Job, type: :job do 4 | pending "add some examples to (or delete) #{__FILE__}" 5 | end 6 | <% end -%> 7 | -------------------------------------------------------------------------------- /lib/generators/sidekiq/templates/job_test.rb.erb: -------------------------------------------------------------------------------- 1 | require 'test_helper' 2 | <% module_namespacing do -%> 3 | class <%= class_name %>JobTest < Minitest::Test 4 | def test_example 5 | skip "add some examples to (or delete) #{__FILE__}" 6 | end 7 | end 8 | <% end -%> 9 | -------------------------------------------------------------------------------- /lib/sidekiq/component.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Sidekiq 4 | ## 5 | # Sidekiq::Component assumes a config instance is available at @config 6 | module Component # :nodoc: 7 | attr_reader :config 8 | 9 | def watchdog(last_words) 10 | yield 11 | rescue Exception => ex 12 | handle_exception(ex, {context: last_words}) 13 | raise ex 14 | end 15 | 16 | def safe_thread(name, &block) 17 | Thread.new do 18 | Thread.current.name = "sidekiq.#{name}" 19 | watchdog(name, &block) 20 | end 21 | end 22 | 23 | def logger 24 | config.logger 25 | end 26 | 27 | def redis(&block) 28 | config.redis(&block) 29 | end 30 | 31 | def tid 32 | Thread.current["sidekiq_tid"] ||= (Thread.current.object_id ^ ::Process.pid).to_s(36) 33 | end 34 | 35 | def hostname 36 | ENV["DYNO"] || Socket.gethostname 37 | end 38 | 39 | def process_nonce 40 | @@process_nonce ||= SecureRandom.hex(6) 41 | end 42 | 43 | def identity 44 | @@identity ||= "#{hostname}:#{::Process.pid}:#{process_nonce}" 45 | end 46 | 47 | def handle_exception(ex, ctx = {}) 48 | config.handle_exception(ex, ctx) 49 | end 50 | 51 | def fire_event(event, options = {}) 52 | oneshot = options.fetch(:oneshot, true) 53 | reverse = options[:reverse] 54 | reraise = options[:reraise] 55 | logger.debug("Firing #{event} event") if oneshot 56 | 57 | arr = config[:lifecycle_events][event] 58 | arr.reverse! if reverse 59 | arr.each do |block| 60 | block.call 61 | rescue => ex 62 | handle_exception(ex, {context: "Exception during Sidekiq lifecycle event.", event: event}) 63 | raise ex if reraise 64 | end 65 | arr.clear if oneshot # once we've fired an event, we never fire it again 66 | end 67 | end 68 | end 69 | -------------------------------------------------------------------------------- /lib/sidekiq/deploy.rb: -------------------------------------------------------------------------------- 1 | require "sidekiq/redis_connection" 2 | require "time" 3 | 4 | # This file is designed to be required within the user's 5 | # deployment script; it should need a bare minimum of dependencies. 6 | # Usage: 7 | # 8 | # require "sidekiq/deploy" 9 | # Sidekiq::Deploy.mark!("Some change") 10 | # 11 | # If you do not pass a label, Sidekiq will try to use the latest 12 | # git commit info. 13 | # 14 | 15 | module Sidekiq 16 | class Deploy 17 | MARK_TTL = 90 * 24 * 60 * 60 # 90 days 18 | 19 | LABEL_MAKER = -> { 20 | `git log -1 --format="%h %s"`.strip 21 | } 22 | 23 | def self.mark!(label = nil) 24 | Sidekiq::Deploy.new.mark!(label: label) 25 | end 26 | 27 | def initialize(pool = Sidekiq::RedisConnection.create) 28 | @pool = pool 29 | end 30 | 31 | def mark!(at: Time.now, label: nil) 32 | label ||= LABEL_MAKER.call 33 | # we need to round the timestamp so that we gracefully 34 | # handle an very common error in marking deploys: 35 | # having every process mark its deploy, leading 36 | # to N marks for each deploy. Instead we round the time 37 | # to the minute so that multiple marks within that minute 38 | # will all naturally rollup into one mark per minute. 39 | whence = at.utc 40 | floor = Time.utc(whence.year, whence.month, whence.mday, whence.hour, whence.min, 0) 41 | datecode = floor.strftime("%Y%m%d") 42 | key = "#{datecode}-marks" 43 | stamp = floor.iso8601 44 | 45 | @pool.with do |c| 46 | # only allow one deploy mark for a given label for the next minute 47 | lock = c.set("deploylock-#{label}", stamp, "nx", "ex", "60") 48 | if lock 49 | c.multi do |pipe| 50 | pipe.hsetnx(key, stamp, label) 51 | pipe.expire(key, MARK_TTL) 52 | end 53 | end 54 | end 55 | end 56 | 57 | def fetch(date = Time.now.utc.to_date) 58 | datecode = date.strftime("%Y%m%d") 59 | @pool.with { |c| c.hgetall("#{datecode}-marks") } 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /lib/sidekiq/embedded.rb: -------------------------------------------------------------------------------- 1 | require "sidekiq/component" 2 | require "sidekiq/launcher" 3 | require "sidekiq/metrics/tracking" 4 | 5 | module Sidekiq 6 | class Embedded 7 | include Sidekiq::Component 8 | 9 | def initialize(config) 10 | @config = config 11 | end 12 | 13 | def run 14 | housekeeping 15 | fire_event(:startup, reverse: false, reraise: true) 16 | @launcher = Sidekiq::Launcher.new(@config, embedded: true) 17 | @launcher.run 18 | sleep 0.2 # pause to give threads time to spin up 19 | 20 | logger.info "Sidekiq running embedded, total process thread count: #{Thread.list.size}" 21 | logger.debug { Thread.list.map(&:name) } 22 | end 23 | 24 | def quiet 25 | @launcher&.quiet 26 | end 27 | 28 | def stop 29 | @launcher&.stop 30 | end 31 | 32 | private 33 | 34 | def housekeeping 35 | logger.info "Running in #{RUBY_DESCRIPTION}" 36 | logger.info Sidekiq::LICENSE 37 | logger.info "Upgrade to Sidekiq Pro for more features and support: https://sidekiq.org" unless defined?(::Sidekiq::Pro) 38 | 39 | # touch the connection pool so it is created before we 40 | # fire startup and start multithreading. 41 | info = config.redis_info 42 | ver = Gem::Version.new(info["redis_version"]) 43 | raise "You are connecting to Redis #{ver}, Sidekiq requires Redis 6.2.0 or greater" if ver < Gem::Version.new("6.2.0") 44 | 45 | maxmemory_policy = info["maxmemory_policy"] 46 | if maxmemory_policy != "noeviction" 47 | logger.warn <<~EOM 48 | 49 | 50 | WARNING: Your Redis instance will evict Sidekiq data under heavy load. 51 | The 'noeviction' maxmemory policy is recommended (current policy: '#{maxmemory_policy}'). 52 | See: https://github.com/sidekiq/sidekiq/wiki/Using-Redis#memory 53 | 54 | EOM 55 | end 56 | 57 | logger.debug { "Client Middleware: #{@config.default_capsule.client_middleware.map(&:klass).join(", ")}" } 58 | logger.debug { "Server Middleware: #{@config.default_capsule.server_middleware.map(&:klass).join(", ")}" } 59 | end 60 | end 61 | end 62 | -------------------------------------------------------------------------------- /lib/sidekiq/fetch.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "sidekiq" 4 | require "sidekiq/component" 5 | require "sidekiq/capsule" 6 | 7 | module Sidekiq # :nodoc: 8 | class BasicFetch 9 | include Sidekiq::Component 10 | # We want the fetch operation to timeout every few seconds so the thread 11 | # can check if the process is shutting down. 12 | TIMEOUT = 2 13 | 14 | UnitOfWork = Struct.new(:queue, :job, :config) { 15 | def acknowledge 16 | # nothing to do 17 | end 18 | 19 | def queue_name 20 | queue.delete_prefix("queue:") 21 | end 22 | 23 | def requeue 24 | config.redis do |conn| 25 | conn.rpush(queue, job) 26 | end 27 | end 28 | } 29 | 30 | def initialize(cap) 31 | raise ArgumentError, "missing queue list" unless cap.queues 32 | @config = cap 33 | @strictly_ordered_queues = cap.mode == :strict 34 | @queues = config.queues.map { |q| "queue:#{q}" } 35 | @queues.uniq! if @strictly_ordered_queues 36 | end 37 | 38 | def retrieve_work 39 | qs = queues_cmd 40 | # 4825 Sidekiq Pro with all queues paused will return an 41 | # empty set of queues 42 | if qs.size <= 0 43 | sleep(TIMEOUT) 44 | return nil 45 | end 46 | 47 | queue, job = redis { |conn| conn.blocking_call(conn.read_timeout + TIMEOUT, "brpop", *qs, TIMEOUT) } 48 | UnitOfWork.new(queue, job, config) if queue 49 | end 50 | 51 | def bulk_requeue(inprogress) 52 | return if inprogress.empty? 53 | 54 | logger.debug { "Re-queueing terminated jobs" } 55 | jobs_to_requeue = {} 56 | inprogress.each do |unit_of_work| 57 | jobs_to_requeue[unit_of_work.queue] ||= [] 58 | jobs_to_requeue[unit_of_work.queue] << unit_of_work.job 59 | end 60 | 61 | redis do |conn| 62 | conn.pipelined do |pipeline| 63 | jobs_to_requeue.each do |queue, jobs| 64 | pipeline.rpush(queue, jobs) 65 | end 66 | end 67 | end 68 | logger.info("Pushed #{inprogress.size} jobs back to Redis") 69 | rescue => ex 70 | logger.warn("Failed to requeue #{inprogress.size} jobs: #{ex.message}") 71 | end 72 | 73 | # Creating the Redis#brpop command takes into account any 74 | # configured queue weights. By default Redis#brpop returns 75 | # data from the first queue that has pending elements. We 76 | # recreate the queue command each time we invoke Redis#brpop 77 | # to honor weights and avoid queue starvation. 78 | def queues_cmd 79 | if @strictly_ordered_queues 80 | @queues 81 | else 82 | permute = @queues.shuffle 83 | permute.uniq! 84 | permute 85 | end 86 | end 87 | end 88 | end 89 | -------------------------------------------------------------------------------- /lib/sidekiq/job_logger.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Sidekiq 4 | class JobLogger 5 | include Sidekiq::Component 6 | 7 | def initialize(config) 8 | @config = config 9 | @logger = logger 10 | end 11 | 12 | # If true we won't do any job logging out of the box. 13 | # The user is responsible for any logging. 14 | def skip_default_logging? 15 | config[:skip_default_job_logging] 16 | end 17 | 18 | def call(item, queue) 19 | return yield if skip_default_logging? 20 | 21 | begin 22 | start = ::Process.clock_gettime(::Process::CLOCK_MONOTONIC) 23 | @logger.info("start") 24 | 25 | yield 26 | 27 | Sidekiq::Context.add(:elapsed, elapsed(start)) 28 | @logger.info("done") 29 | rescue Exception 30 | Sidekiq::Context.add(:elapsed, elapsed(start)) 31 | @logger.info("fail") 32 | 33 | raise 34 | end 35 | end 36 | 37 | def prepare(job_hash, &block) 38 | # If we're using a wrapper class, like ActiveJob, use the "wrapped" 39 | # attribute to expose the underlying thing. 40 | h = { 41 | class: job_hash["display_class"] || job_hash["wrapped"] || job_hash["class"], 42 | jid: job_hash["jid"] 43 | } 44 | h[:bid] = job_hash["bid"] if job_hash.has_key?("bid") 45 | h[:tags] = job_hash["tags"] if job_hash.has_key?("tags") 46 | 47 | Thread.current[:sidekiq_context] = h 48 | level = job_hash["log_level"] 49 | if level && @logger.respond_to?(:log_at) 50 | @logger.log_at(level, &block) 51 | else 52 | yield 53 | end 54 | ensure 55 | Thread.current[:sidekiq_context] = nil 56 | end 57 | 58 | private 59 | 60 | def elapsed(start) 61 | (::Process.clock_gettime(::Process::CLOCK_MONOTONIC) - start).round(3) 62 | end 63 | end 64 | end 65 | -------------------------------------------------------------------------------- /lib/sidekiq/middleware/i18n.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | # 4 | # Simple middleware to save the current locale and restore it when the job executes. 5 | # Use it by requiring it in your initializer: 6 | # 7 | # require 'sidekiq/middleware/i18n' 8 | # 9 | module Sidekiq::Middleware::I18n 10 | # Get the current locale and store it in the message 11 | # to be sent to Sidekiq. 12 | class Client 13 | include Sidekiq::ClientMiddleware 14 | def call(_jobclass, job, _queue, _redis) 15 | job["locale"] ||= I18n.locale 16 | yield 17 | end 18 | end 19 | 20 | # Pull the msg locale out and set the current thread to use it. 21 | class Server 22 | include Sidekiq::ServerMiddleware 23 | def call(_jobclass, job, _queue, &block) 24 | I18n.with_locale(job.fetch("locale", I18n.default_locale), &block) 25 | end 26 | end 27 | end 28 | 29 | Sidekiq.configure_client do |config| 30 | config.client_middleware do |chain| 31 | chain.add Sidekiq::Middleware::I18n::Client 32 | end 33 | end 34 | 35 | Sidekiq.configure_server do |config| 36 | config.client_middleware do |chain| 37 | chain.add Sidekiq::Middleware::I18n::Client 38 | end 39 | config.server_middleware do |chain| 40 | chain.add Sidekiq::Middleware::I18n::Server 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /lib/sidekiq/middleware/modules.rb: -------------------------------------------------------------------------------- 1 | module Sidekiq 2 | # Server-side middleware must import this Module in order 3 | # to get access to server resources during `call`. 4 | module ServerMiddleware 5 | attr_accessor :config 6 | def redis_pool 7 | config.redis_pool 8 | end 9 | 10 | def logger 11 | config.logger 12 | end 13 | 14 | def redis(&block) 15 | config.redis(&block) 16 | end 17 | end 18 | 19 | # no difference for now 20 | ClientMiddleware = ServerMiddleware 21 | end 22 | -------------------------------------------------------------------------------- /lib/sidekiq/paginator.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Sidekiq 4 | module Paginator 5 | def page(key, pageidx = 1, page_size = 25, opts = nil) 6 | current_page = (pageidx.to_i < 1) ? 1 : pageidx.to_i 7 | pageidx = current_page - 1 8 | total_size = 0 9 | items = [] 10 | starting = pageidx * page_size 11 | ending = starting + page_size - 1 12 | 13 | Sidekiq.redis do |conn| 14 | type = conn.type(key) 15 | rev = opts && opts[:reverse] 16 | 17 | case type 18 | when "zset" 19 | total_size, items = conn.multi { |transaction| 20 | transaction.zcard(key) 21 | if rev 22 | transaction.zrange(key, starting, ending, "REV", "withscores") 23 | else 24 | transaction.zrange(key, starting, ending, "withscores") 25 | end 26 | } 27 | [current_page, total_size, items] 28 | when "list" 29 | total_size, items = conn.multi { |transaction| 30 | transaction.llen(key) 31 | if rev 32 | transaction.lrange(key, -ending - 1, -starting - 1) 33 | else 34 | transaction.lrange(key, starting, ending) 35 | end 36 | } 37 | items.reverse! if rev 38 | [current_page, total_size, items] 39 | when "none" 40 | [1, 0, []] 41 | else 42 | raise "can't page a #{type}" 43 | end 44 | end 45 | end 46 | 47 | def page_items(items, pageidx = 1, page_size = 25) 48 | current_page = (pageidx.to_i < 1) ? 1 : pageidx.to_i 49 | pageidx = current_page - 1 50 | starting = pageidx * page_size 51 | items = items.to_a 52 | [current_page, items.size, items[starting, page_size]] 53 | end 54 | end 55 | end 56 | -------------------------------------------------------------------------------- /lib/sidekiq/rails.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "sidekiq/job" 4 | require "rails" 5 | 6 | module Sidekiq 7 | class Rails < ::Rails::Engine 8 | class Reloader 9 | def initialize(app = ::Rails.application) 10 | @app = app 11 | end 12 | 13 | def call 14 | params = (::Rails::VERSION::STRING >= "7.1") ? {source: "job.sidekiq"} : {} 15 | @app.reloader.wrap(**params) do 16 | yield 17 | end 18 | end 19 | 20 | def inspect 21 | "#" 22 | end 23 | 24 | def to_hash 25 | {app: @app.class.name} 26 | end 27 | end 28 | 29 | # By including the Options module, we allow AJs to directly control sidekiq features 30 | # via the *sidekiq_options* class method and, for instance, not use AJ's retry system. 31 | # AJ retries don't show up in the Sidekiq UI Retries tab, don't save any error data, can't be 32 | # manually retried, don't automatically die, etc. 33 | # 34 | # class SomeJob < ActiveJob::Base 35 | # queue_as :default 36 | # sidekiq_options retry: 3, backtrace: 10 37 | # def perform 38 | # end 39 | # end 40 | initializer "sidekiq.active_job_integration" do 41 | ActiveSupport.on_load(:active_job) do 42 | include ::Sidekiq::Job::Options unless respond_to?(:sidekiq_options) 43 | end 44 | end 45 | 46 | initializer "sidekiq.backtrace_cleaner" do 47 | Sidekiq.configure_server do |config| 48 | config[:backtrace_cleaner] = ->(backtrace) { ::Rails.backtrace_cleaner.clean(backtrace) } 49 | end 50 | end 51 | 52 | # This hook happens after all initializers are run, just before returning 53 | # from config/environment.rb back to sidekiq/cli.rb. 54 | # 55 | # None of this matters on the client-side, only within the Sidekiq process itself. 56 | config.after_initialize do 57 | Sidekiq.configure_server do |config| 58 | config[:reloader] = Sidekiq::Rails::Reloader.new 59 | 60 | # This is the integration code necessary so that if a job uses `Rails.logger.info "Hello"`, 61 | # it will appear in the Sidekiq console with all of the job context. 62 | unless ::Rails.logger == config.logger || ::ActiveSupport::Logger.logger_outputs_to?(::Rails.logger, $stdout) 63 | if ::Rails.logger.respond_to?(:broadcast_to) 64 | ::Rails.logger.broadcast_to(config.logger) 65 | else 66 | ::Rails.logger.extend(::ActiveSupport::Logger.broadcast(config.logger)) 67 | end 68 | end 69 | end 70 | end 71 | end 72 | end 73 | -------------------------------------------------------------------------------- /lib/sidekiq/ring_buffer.rb: -------------------------------------------------------------------------------- 1 | require "forwardable" 2 | 3 | module Sidekiq 4 | class RingBuffer 5 | include Enumerable 6 | extend Forwardable 7 | def_delegators :@buf, :[], :each, :size 8 | 9 | def initialize(size, default = 0) 10 | @size = size 11 | @buf = Array.new(size, default) 12 | @index = 0 13 | end 14 | 15 | def <<(element) 16 | @buf[@index % @size] = element 17 | @index += 1 18 | element 19 | end 20 | 21 | def buffer 22 | @buf 23 | end 24 | 25 | def reset(default = 0) 26 | @buf.fill(default) 27 | end 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /lib/sidekiq/systemd.rb: -------------------------------------------------------------------------------- 1 | # 2 | # Sidekiq's systemd integration allows Sidekiq to inform systemd: 3 | # 1. when it has successfully started 4 | # 2. when it is starting shutdown 5 | # 3. periodically for a liveness check with a watchdog thread 6 | # 7 | module Sidekiq 8 | def self.start_watchdog 9 | usec = Integer(ENV["WATCHDOG_USEC"]) 10 | return Sidekiq.logger.error("systemd Watchdog too fast: " + usec) if usec < 1_000_000 11 | 12 | sec_f = usec / 1_000_000.0 13 | # "It is recommended that a daemon sends a keep-alive notification message 14 | # to the service manager every half of the time returned here." 15 | ping_f = sec_f / 2 16 | Sidekiq.logger.info "Pinging systemd watchdog every #{ping_f.round(1)} sec" 17 | Thread.new do 18 | loop do 19 | sleep ping_f 20 | Sidekiq::SdNotify.watchdog 21 | end 22 | end 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /lib/sidekiq/testing/inline.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "sidekiq/testing" 4 | 5 | ## 6 | # The Sidekiq inline infrastructure overrides perform_async so that it 7 | # actually calls perform instead. This allows jobs to be run inline in a 8 | # testing environment. 9 | # 10 | # This is similar to `Resque.inline = true` functionality. 11 | # 12 | # Example: 13 | # 14 | # require 'sidekiq/testing/inline' 15 | # 16 | # $external_variable = 0 17 | # 18 | # class ExternalJob 19 | # include Sidekiq::Job 20 | # 21 | # def perform 22 | # $external_variable = 1 23 | # end 24 | # end 25 | # 26 | # assert_equal 0, $external_variable 27 | # ExternalJob.perform_async 28 | # assert_equal 1, $external_variable 29 | # 30 | Sidekiq::Testing.inline! 31 | -------------------------------------------------------------------------------- /lib/sidekiq/transaction_aware_client.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "securerandom" 4 | require "sidekiq/client" 5 | 6 | module Sidekiq 7 | class TransactionAwareClient 8 | def initialize(pool: nil, config: nil) 9 | @redis_client = Client.new(pool: pool, config: config) 10 | end 11 | 12 | def batching? 13 | Thread.current[:sidekiq_batch] 14 | end 15 | 16 | def push(item) 17 | # 6160 we can't support both Sidekiq::Batch and transactions. 18 | return @redis_client.push(item) if batching? 19 | 20 | # pre-allocate the JID so we can return it immediately and 21 | # save it to the database as part of the transaction. 22 | item["jid"] ||= SecureRandom.hex(12) 23 | AfterCommitEverywhere.after_commit { @redis_client.push(item) } 24 | item["jid"] 25 | end 26 | 27 | ## 28 | # We don't provide transactionality for push_bulk because we don't want 29 | # to hold potentially hundreds of thousands of job records in memory due to 30 | # a long running enqueue process. 31 | def push_bulk(items) 32 | @redis_client.push_bulk(items) 33 | end 34 | end 35 | end 36 | 37 | ## 38 | # Use `Sidekiq.transactional_push!` in your sidekiq.rb initializer 39 | module Sidekiq 40 | def self.transactional_push! 41 | begin 42 | require "after_commit_everywhere" 43 | rescue LoadError 44 | raise %q(You need to add `gem "after_commit_everywhere"` to your Gemfile to use Sidekiq's transactional client) 45 | end 46 | 47 | Sidekiq.default_job_options["client_class"] = Sidekiq::TransactionAwareClient 48 | Sidekiq::JobUtil::TRANSIENT_ATTRIBUTES << "client_class" 49 | true 50 | end 51 | end 52 | -------------------------------------------------------------------------------- /lib/sidekiq/version.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Sidekiq 4 | VERSION = "7.3.0" 5 | MAJOR = 7 6 | end 7 | -------------------------------------------------------------------------------- /lib/sidekiq/web/action.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Sidekiq 4 | class WebAction 5 | RACK_SESSION = "rack.session" 6 | 7 | attr_accessor :env, :block, :type 8 | 9 | def settings 10 | Web.settings 11 | end 12 | 13 | def request 14 | @request ||= ::Rack::Request.new(env) 15 | end 16 | 17 | def halt(res) 18 | throw :halt, [res, {Rack::CONTENT_TYPE => "text/plain"}, [res.to_s]] 19 | end 20 | 21 | def redirect(location) 22 | throw :halt, [302, {Web::LOCATION => "#{request.base_url}#{location}"}, []] 23 | end 24 | 25 | def reload_page 26 | current_location = request.referer.gsub(request.base_url, "") 27 | redirect current_location 28 | end 29 | 30 | def params 31 | indifferent_hash = Hash.new { |hash, key| hash[key.to_s] if Symbol === key } 32 | 33 | indifferent_hash.merge! request.params 34 | route_params.each { |k, v| indifferent_hash[k.to_s] = v } 35 | 36 | indifferent_hash 37 | end 38 | 39 | def route_params 40 | env[WebRouter::ROUTE_PARAMS] 41 | end 42 | 43 | def session 44 | env[RACK_SESSION] 45 | end 46 | 47 | def erb(content, options = {}) 48 | if content.is_a? Symbol 49 | unless respond_to?(:"_erb_#{content}") 50 | src = ERB.new(File.read("#{Web.settings.views}/#{content}.erb")).src 51 | WebAction.class_eval <<-RUBY, __FILE__, __LINE__ + 1 52 | def _erb_#{content} 53 | #{src} 54 | end 55 | RUBY 56 | end 57 | end 58 | 59 | if @_erb 60 | _erb(content, options[:locals]) 61 | else 62 | @_erb = true 63 | content = _erb(content, options[:locals]) 64 | 65 | _render { content } 66 | end 67 | end 68 | 69 | def render(engine, content, options = {}) 70 | raise "Only erb templates are supported" if engine != :erb 71 | 72 | erb(content, options) 73 | end 74 | 75 | def json(payload) 76 | [200, {Rack::CONTENT_TYPE => "application/json", Rack::CACHE_CONTROL => "private, no-store"}, [Sidekiq.dump_json(payload)]] 77 | end 78 | 79 | def initialize(env, block) 80 | @_erb = false 81 | @env = env 82 | @block = block 83 | @files ||= {} 84 | end 85 | 86 | private 87 | 88 | def _erb(file, locals) 89 | locals&.each { |k, v| define_singleton_method(k) { v } unless singleton_methods.include? k } 90 | 91 | if file.is_a?(String) 92 | ERB.new(file).result(binding) 93 | else 94 | send(:"_erb_#{file}") 95 | end 96 | end 97 | end 98 | end 99 | -------------------------------------------------------------------------------- /lib/sidekiq/web/router.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rack" 4 | 5 | module Sidekiq 6 | module WebRouter 7 | GET = "GET" 8 | DELETE = "DELETE" 9 | POST = "POST" 10 | PUT = "PUT" 11 | PATCH = "PATCH" 12 | HEAD = "HEAD" 13 | 14 | ROUTE_PARAMS = "rack.route_params" 15 | REQUEST_METHOD = "REQUEST_METHOD" 16 | PATH_INFO = "PATH_INFO" 17 | 18 | def head(path, &block) 19 | route(HEAD, path, &block) 20 | end 21 | 22 | def get(path, &block) 23 | route(GET, path, &block) 24 | end 25 | 26 | def post(path, &block) 27 | route(POST, path, &block) 28 | end 29 | 30 | def put(path, &block) 31 | route(PUT, path, &block) 32 | end 33 | 34 | def patch(path, &block) 35 | route(PATCH, path, &block) 36 | end 37 | 38 | def delete(path, &block) 39 | route(DELETE, path, &block) 40 | end 41 | 42 | def route(method, path, &block) 43 | @routes ||= {GET => [], POST => [], PUT => [], PATCH => [], DELETE => [], HEAD => []} 44 | 45 | @routes[method] << WebRoute.new(method, path, block) 46 | end 47 | 48 | def match(env) 49 | request_method = env[REQUEST_METHOD] 50 | path_info = ::Rack::Utils.unescape env[PATH_INFO] 51 | 52 | # There are servers which send an empty string when requesting the root. 53 | # These servers should be ashamed of themselves. 54 | path_info = "/" if path_info == "" 55 | 56 | @routes[request_method].each do |route| 57 | params = route.match(request_method, path_info) 58 | if params 59 | env[ROUTE_PARAMS] = params 60 | 61 | return WebAction.new(env, route.block) 62 | end 63 | end 64 | 65 | nil 66 | end 67 | end 68 | 69 | class WebRoute 70 | attr_accessor :request_method, :pattern, :block, :name 71 | 72 | NAMED_SEGMENTS_PATTERN = /\/([^\/]*):([^.:$\/]+)/ 73 | 74 | def initialize(request_method, pattern, block) 75 | @request_method = request_method 76 | @pattern = pattern 77 | @block = block 78 | end 79 | 80 | def matcher 81 | @matcher ||= compile 82 | end 83 | 84 | def compile 85 | if pattern.match?(NAMED_SEGMENTS_PATTERN) 86 | p = pattern.gsub(NAMED_SEGMENTS_PATTERN, '/\1(?<\2>[^$/]+)') 87 | 88 | Regexp.new("\\A#{p}\\Z") 89 | else 90 | pattern 91 | end 92 | end 93 | 94 | def match(request_method, path) 95 | case matcher 96 | when String 97 | {} if path == matcher 98 | else 99 | path_match = path.match(matcher) 100 | path_match&.named_captures&.transform_keys(&:to_sym) 101 | end 102 | end 103 | end 104 | end 105 | -------------------------------------------------------------------------------- /lib/sidekiq/worker_compatibility_alias.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | module Sidekiq 4 | # Sidekiq::Job is a new alias for Sidekiq::Worker as of Sidekiq 6.3.0. 5 | # Use `include Sidekiq::Job` rather than `include Sidekiq::Worker`. 6 | # 7 | # The term "worker" is too generic and overly confusing, used in several 8 | # different contexts meaning different things. Many people call a Sidekiq 9 | # process a "worker". Some people call the thread that executes jobs a 10 | # "worker". This change brings Sidekiq closer to ActiveJob where your job 11 | # classes extend ApplicationJob. 12 | Worker = Job 13 | end 14 | -------------------------------------------------------------------------------- /myapp/.gitattributes: -------------------------------------------------------------------------------- 1 | # See https://git-scm.com/docs/gitattributes for more about git attribute files. 2 | 3 | # Mark the database schema as having been generated. 4 | db/schema.rb linguist-generated 5 | 6 | # Mark any vendored files as having been vendored. 7 | vendor/* linguist-vendored 8 | -------------------------------------------------------------------------------- /myapp/.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files for more about ignoring files. 2 | # 3 | # If you find yourself ignoring temporary files generated by your text editor 4 | # or operating system, you probably want to add a global ignore instead: 5 | # git config --global core.excludesfile '~/.gitignore_global' 6 | 7 | # Ignore bundler config. 8 | /.bundle 9 | 10 | # Ignore the default SQLite database. 11 | /db/*.sqlite3 12 | /db/*.sqlite3-* 13 | 14 | # Ignore all logfiles and tempfiles. 15 | /log/* 16 | /tmp/* 17 | !/log/.keep 18 | !/tmp/.keep 19 | 20 | # Ignore pidfiles, but keep the directory. 21 | /tmp/pids/* 22 | !/tmp/pids/ 23 | !/tmp/pids/.keep 24 | 25 | # Ignore uploaded files in development. 26 | /storage/* 27 | !/storage/.keep 28 | /tmp/storage/* 29 | !/tmp/storage/ 30 | !/tmp/storage/.keep 31 | 32 | /public/assets 33 | 34 | # Ignore master key for decrypting credentials and more. 35 | /config/master.key 36 | -------------------------------------------------------------------------------- /myapp/Gemfile: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | source "https://rubygems.org" 4 | git_source(:github) { |repo| "https://github.com/#{repo}.git" } 5 | 6 | RAILS_VERSION = "~> 7.1.0" 7 | gem "actionmailer", RAILS_VERSION 8 | gem "actionpack", RAILS_VERSION 9 | gem "activejob", RAILS_VERSION 10 | gem "activerecord", RAILS_VERSION 11 | gem "railties", RAILS_VERSION 12 | 13 | gem "puma" 14 | gem "sidekiq", path: ".." 15 | gem "sqlite3" 16 | 17 | gem "after_commit_everywhere" 18 | -------------------------------------------------------------------------------- /myapp/Procfile: -------------------------------------------------------------------------------- 1 | web: PORT=3000 bin/rails server 2 | seed: while true; do bundle exec rake seed_jobs; sleep 240; done 3 | worker: bundle exec sidekiq 4 | -------------------------------------------------------------------------------- /myapp/Rakefile: -------------------------------------------------------------------------------- 1 | # Add your own tasks in files placed in lib/tasks ending in .rake, 2 | # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake. 3 | 4 | require_relative "config/application" 5 | 6 | Rails.application.load_tasks 7 | 8 | task seed_jobs: :environment do 9 | # see classes defined in config/initializers/sidekiq.rb 10 | [FooJob, BarJob, StoreCardJob, OrderJunkJob, SpamUserJob, FastJob, SlowJob].each do |kls| 11 | (kls.name.size * 10).times do 12 | kls.perform_in(rand * 300) 13 | end 14 | end 15 | end 16 | -------------------------------------------------------------------------------- /myapp/app/controllers/application_controller.rb: -------------------------------------------------------------------------------- 1 | class ApplicationController < ActionController::Base 2 | end 3 | -------------------------------------------------------------------------------- /myapp/app/controllers/job_controller.rb: -------------------------------------------------------------------------------- 1 | class JobController < ApplicationController 2 | def index 3 | @count = rand(100) 4 | puts "Adding #{@count} jobs" 5 | @count.times do |x| 6 | HardJob.perform_async("bubba", 0.01, x) 7 | end 8 | end 9 | 10 | def email 11 | UserMailer.delay_for(30.seconds).greetings(Time.now) 12 | render plain: "enqueued" 13 | end 14 | 15 | def bulk 16 | Sidekiq::Client.push_bulk("class" => HardJob, 17 | "args" => [["bob", 1, 1], ["mike", 1, 2]]) 18 | render plain: "enbulked" 19 | end 20 | 21 | def long 22 | 50.times do |x| 23 | HardJob.perform_async("bob", 15, x) 24 | end 25 | render plain: "enqueued" 26 | end 27 | 28 | def crash 29 | HardJob.perform_async("crash", 1, Time.now.to_f) 30 | render plain: "enqueued" 31 | end 32 | 33 | def delayed_post 34 | p = Post.first 35 | if p 36 | p2 = Post.second 37 | else 38 | p = Post.create!(title: "Title!", body: "Body!") 39 | p2 = Post.create!(title: "Other!", body: "Second Body!") 40 | end 41 | p.delay.long_method(p2) 42 | render plain: "enqueued" 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /myapp/app/helpers/application_helper.rb: -------------------------------------------------------------------------------- 1 | module ApplicationHelper 2 | end 3 | -------------------------------------------------------------------------------- /myapp/app/jobs/application_job.rb: -------------------------------------------------------------------------------- 1 | class ApplicationJob < ActiveJob::Base 2 | # Automatically retry jobs that encountered a deadlock 3 | # retry_on ActiveRecord::Deadlocked 4 | 5 | # Most jobs are safe to ignore if the underlying records are no longer available 6 | # discard_on ActiveJob::DeserializationError 7 | end 8 | -------------------------------------------------------------------------------- /myapp/app/jobs/exit_job.rb: -------------------------------------------------------------------------------- 1 | class ExitJob < ApplicationJob 2 | queue_as :default 3 | 4 | def perform(*args) 5 | Sidekiq.logger.warn "Success" 6 | Thread.new do 7 | sleep 0.1 8 | exit(0) 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /myapp/app/jobs/some_job.rb: -------------------------------------------------------------------------------- 1 | class SomeJob < ApplicationJob 2 | queue_as :default 3 | 4 | def perform(*args) 5 | puts "What's up?!?!" 6 | # Do something later 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /myapp/app/lib/myapp/current.rb: -------------------------------------------------------------------------------- 1 | module Myapp 2 | class Current < ActiveSupport::CurrentAttributes 3 | attribute :tenant_id 4 | end 5 | end 6 | -------------------------------------------------------------------------------- /myapp/app/mailers/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/touchasky/sidekiq/dddf20bf0a6decfa6e19b04611fcb3a281d009a3/myapp/app/mailers/.gitkeep -------------------------------------------------------------------------------- /myapp/app/mailers/user_mailer.rb: -------------------------------------------------------------------------------- 1 | class UserMailer < ActionMailer::Base 2 | default from: "sidekiq@example.com" 3 | 4 | def greetings(now) 5 | @now = now 6 | @hostname = `hostname`.strip 7 | mail(to: "mperham@gmail.com", subject: "Ahoy Matey!") 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /myapp/app/models/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/touchasky/sidekiq/dddf20bf0a6decfa6e19b04611fcb3a281d009a3/myapp/app/models/.gitkeep -------------------------------------------------------------------------------- /myapp/app/models/application_record.rb: -------------------------------------------------------------------------------- 1 | class ApplicationRecord < ActiveRecord::Base 2 | primary_abstract_class 3 | end 4 | -------------------------------------------------------------------------------- /myapp/app/models/exiter.rb: -------------------------------------------------------------------------------- 1 | class Exiter 2 | def self.run 3 | Sidekiq.logger.warn "Success" 4 | Thread.new do 5 | sleep 0.1 6 | exit(0) 7 | end 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /myapp/app/models/post.rb: -------------------------------------------------------------------------------- 1 | class Post < ActiveRecord::Base 2 | def long_method(other_post) 3 | puts "Running long method with #{id} and #{other_post.id}" 4 | end 5 | 6 | def self.testing 7 | Sidekiq.logger.info "Test" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /myapp/app/sidekiq/exit_job.rb: -------------------------------------------------------------------------------- 1 | class ExitJob 2 | include Sidekiq::Job 3 | 4 | def perform 5 | logger.warn "Success" 6 | Thread.new do 7 | sleep 0.1 8 | exit(0) 9 | end 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /myapp/app/sidekiq/hard_job.rb: -------------------------------------------------------------------------------- 1 | class HardJob 2 | include Sidekiq::Job 3 | sidekiq_options backtrace: 5 4 | 5 | def perform(name, count, salt) 6 | raise name if name == "crash" 7 | logger.info Time.now 8 | sleep count 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /myapp/app/sidekiq/lazy_job.rb: -------------------------------------------------------------------------------- 1 | class LazyJob 2 | include Sidekiq::Job 3 | 4 | def perform 5 | end 6 | end 7 | -------------------------------------------------------------------------------- /myapp/app/views/job/index.html.erb: -------------------------------------------------------------------------------- 1 | Added <%= @count %> jobs! 2 | -------------------------------------------------------------------------------- /myapp/app/views/layouts/application.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Myapp 5 | 6 | <%= csrf_meta_tags %> 7 | <%= csp_meta_tag %> 8 | 9 | <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> 10 | 11 | 12 | 13 | <%= yield %> 14 | 15 | 16 | -------------------------------------------------------------------------------- /myapp/app/views/user_mailer/greetings.html.erb: -------------------------------------------------------------------------------- 1 |

2 | Hi Mike, it's <%= @now %> and I'm at <%= @hostname %>. 3 |

4 | -------------------------------------------------------------------------------- /myapp/bin/bundle: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) 3 | load Gem.bin_path("bundler", "bundle") 4 | -------------------------------------------------------------------------------- /myapp/bin/rails: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | APP_PATH = File.expand_path("../config/application", __dir__) 3 | require_relative "../config/boot" 4 | require "rails/commands" 5 | -------------------------------------------------------------------------------- /myapp/bin/rake: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require_relative "../config/boot" 3 | require "rake" 4 | Rake.application.run 5 | -------------------------------------------------------------------------------- /myapp/bin/setup: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require "fileutils" 3 | 4 | # path to your application root. 5 | APP_ROOT = File.expand_path("..", __dir__) 6 | 7 | def system!(*args) 8 | system(*args, exception: true) 9 | end 10 | 11 | FileUtils.chdir APP_ROOT do 12 | # This script is a way to set up or update your development environment automatically. 13 | # This script is idempotent, so that you can run it at any time and get an expectable outcome. 14 | # Add necessary setup steps to this file. 15 | 16 | puts "== Installing dependencies ==" 17 | system! "gem install bundler --conservative" 18 | system("bundle check") || system!("bundle install") 19 | 20 | # puts "\n== Copying sample files ==" 21 | # unless File.exist?("config/database.yml") 22 | # FileUtils.cp "config/database.yml.sample", "config/database.yml" 23 | # end 24 | 25 | puts "\n== Preparing database ==" 26 | system! "bin/rails db:prepare" 27 | 28 | puts "\n== Removing old logs and tempfiles ==" 29 | system! "bin/rails log:clear tmp:clear" 30 | 31 | puts "\n== Restarting application server ==" 32 | system! "bin/rails restart" 33 | end 34 | -------------------------------------------------------------------------------- /myapp/config.ru: -------------------------------------------------------------------------------- 1 | # This file is used by Rack-based servers to start the application. 2 | 3 | require_relative "config/environment" 4 | 5 | run Rails.application 6 | Rails.application.load_server 7 | -------------------------------------------------------------------------------- /myapp/config/application.rb: -------------------------------------------------------------------------------- 1 | require_relative "boot" 2 | 3 | require "rails" 4 | # Pick the frameworks you want: 5 | require "active_model/railtie" 6 | require "active_job/railtie" 7 | require "active_record/railtie" 8 | require "action_controller/railtie" 9 | require "action_mailer/railtie" 10 | require "action_view/railtie" 11 | 12 | # Require the gems listed in Gemfile, including any gems 13 | # you've limited to :test, :development, or :production. 14 | Bundler.require(*Rails.groups) 15 | 16 | module Myapp 17 | class Application < Rails::Application 18 | # Initialize configuration defaults for originally generated Rails version. 19 | config.load_defaults 7.1 20 | 21 | # Please, add to the `ignore` list any other `lib` subdirectories that do 22 | # not contain `.rb` files, or that should not be reloaded or eager loaded. 23 | # Common ones are `templates`, `generators`, or `middleware`, for example. 24 | config.autoload_lib(ignore: %w[assets tasks]) 25 | 26 | # Configuration for the application, engines, and railties goes here. 27 | # 28 | # These settings can be overridden in specific environments using the files 29 | # in config/environments, which are processed later. 30 | # 31 | # config.time_zone = "Central Time (US & Canada)" 32 | # config.eager_load_paths << Rails.root.join("extras") 33 | 34 | # Don't generate system test files. 35 | config.generators.system_tests = nil 36 | config.active_job.queue_adapter = :sidekiq 37 | end 38 | end 39 | -------------------------------------------------------------------------------- /myapp/config/boot.rb: -------------------------------------------------------------------------------- 1 | ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__) 2 | 3 | require "bundler/setup" # Set up gems listed in the Gemfile. 4 | -------------------------------------------------------------------------------- /myapp/config/database.yml: -------------------------------------------------------------------------------- 1 | # SQLite. Versions 3.8.0 and up are supported. 2 | # gem install sqlite3 3 | # 4 | # Ensure the SQLite 3 gem is defined in your Gemfile 5 | # gem "sqlite3" 6 | # 7 | default: &default 8 | adapter: sqlite3 9 | pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %> 10 | timeout: 5000 11 | 12 | development: 13 | <<: *default 14 | database: db/development.sqlite3 15 | 16 | # Warning: The database defined as "test" will be erased and 17 | # re-generated from your development database when you run "rake". 18 | # Do not set this db to the same as development or production. 19 | test: 20 | <<: *default 21 | database: db/test.sqlite3 22 | 23 | production: 24 | <<: *default 25 | database: db/production.sqlite3 26 | -------------------------------------------------------------------------------- /myapp/config/environment.rb: -------------------------------------------------------------------------------- 1 | # Load the Rails application. 2 | require_relative "application" 3 | 4 | # Initialize the Rails application. 5 | Rails.application.initialize! 6 | -------------------------------------------------------------------------------- /myapp/config/environments/development.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | Rails.application.configure do 4 | # Settings specified here will take precedence over those in config/application.rb. 5 | 6 | # In the development environment your application's code is reloaded any time 7 | # it changes. This slows down response time but is perfect for development 8 | # since you don't have to restart the web server when you make code changes. 9 | config.enable_reloading = true 10 | 11 | # Do not eager load code on boot. 12 | config.eager_load = false 13 | 14 | # Show full error reports. 15 | config.consider_all_requests_local = true 16 | 17 | # Enable server timing 18 | config.server_timing = true 19 | 20 | # Enable/disable caching. By default caching is disabled. 21 | # Run rails dev:cache to toggle caching. 22 | if Rails.root.join("tmp/caching-dev.txt").exist? 23 | config.action_controller.perform_caching = true 24 | config.action_controller.enable_fragment_cache_logging = true 25 | 26 | config.cache_store = :memory_store 27 | config.public_file_server.headers = { 28 | "Cache-Control" => "public, max-age=#{2.days.to_i}" 29 | } 30 | else 31 | config.action_controller.perform_caching = false 32 | 33 | config.cache_store = :null_store 34 | end 35 | 36 | # Don't care if the mailer can't send. 37 | config.action_mailer.raise_delivery_errors = false 38 | 39 | config.action_mailer.perform_caching = false 40 | 41 | # Print deprecation notices to the Rails logger. 42 | config.active_support.deprecation = :log 43 | 44 | # Raise exceptions for disallowed deprecations. 45 | config.active_support.disallowed_deprecation = :raise 46 | 47 | # Tell Active Support which deprecation messages to disallow. 48 | config.active_support.disallowed_deprecation_warnings = [] 49 | 50 | # Raise an error on page load if there are pending migrations. 51 | config.active_record.migration_error = :page_load 52 | 53 | # Highlight code that triggered database queries in logs. 54 | config.active_record.verbose_query_logs = true 55 | 56 | # Highlight code that enqueued background job in logs. 57 | config.active_job.verbose_enqueue_logs = true 58 | 59 | # Raises error for missing translations. 60 | # config.i18n.raise_on_missing_translations = true 61 | 62 | # Annotate rendered view with file names. 63 | # config.action_view.annotate_rendered_view_with_filenames = true 64 | 65 | # Raise error when a before_action's only/except options reference missing actions 66 | config.action_controller.raise_on_missing_callback_actions = true 67 | end 68 | -------------------------------------------------------------------------------- /myapp/config/environments/test.rb: -------------------------------------------------------------------------------- 1 | require "active_support/core_ext/integer/time" 2 | 3 | # The test environment is used exclusively to run your application's 4 | # test suite. You never need to work with it otherwise. Remember that 5 | # your test database is "scratch space" for the test suite and is wiped 6 | # and recreated between test runs. Don't rely on the data there! 7 | 8 | Rails.application.configure do 9 | # Settings specified here will take precedence over those in config/application.rb. 10 | 11 | # While tests run files are not watched, reloading is not necessary. 12 | config.enable_reloading = false 13 | 14 | # Eager loading loads your entire application. When running a single test locally, 15 | # this is usually not necessary, and can slow down your test suite. However, it's 16 | # recommended that you enable it in continuous integration systems to ensure eager 17 | # loading is working properly before deploying your code. 18 | config.eager_load = ENV["CI"].present? 19 | 20 | # Configure public file server for tests with Cache-Control for performance. 21 | config.public_file_server.enabled = true 22 | config.public_file_server.headers = { 23 | "Cache-Control" => "public, max-age=#{1.hour.to_i}" 24 | } 25 | 26 | # Show full error reports and disable caching. 27 | config.consider_all_requests_local = true 28 | config.action_controller.perform_caching = false 29 | config.cache_store = :null_store 30 | 31 | # Raise exceptions instead of rendering exception templates. 32 | config.action_dispatch.show_exceptions = :rescuable 33 | 34 | # Disable request forgery protection in test environment. 35 | config.action_controller.allow_forgery_protection = false 36 | 37 | config.action_mailer.perform_caching = false 38 | 39 | # Tell Action Mailer not to deliver emails to the real world. 40 | # The :test delivery method accumulates sent emails in the 41 | # ActionMailer::Base.deliveries array. 42 | config.action_mailer.delivery_method = :test 43 | 44 | # Print deprecation notices to the stderr. 45 | config.active_support.deprecation = :stderr 46 | 47 | # Raise exceptions for disallowed deprecations. 48 | config.active_support.disallowed_deprecation = :raise 49 | 50 | # Tell Active Support which deprecation messages to disallow. 51 | config.active_support.disallowed_deprecation_warnings = [] 52 | 53 | # Raises error for missing translations. 54 | # config.i18n.raise_on_missing_translations = true 55 | 56 | # Annotate rendered view with file names. 57 | # config.action_view.annotate_rendered_view_with_filenames = true 58 | 59 | # Raise error when a before_action's only/except options reference missing actions 60 | config.action_controller.raise_on_missing_callback_actions = true 61 | end 62 | -------------------------------------------------------------------------------- /myapp/config/initializers/backtrace_silencers.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # You can add backtrace silencers for libraries that you're using but don't wish to see in your backtraces. 4 | # Rails.backtrace_cleaner.add_silencer { |line| line =~ /my_noisy_library/ } 5 | 6 | # You can also remove all the silencers if you're trying to debug a problem that might stem from framework code. 7 | # Rails.backtrace_cleaner.remove_silencers! 8 | -------------------------------------------------------------------------------- /myapp/config/initializers/cookies_serializer.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Specify a serializer for the signed and encrypted cookie jars. 4 | # Valid options are :json, :marshal, and :hybrid. 5 | Rails.application.config.action_dispatch.cookies_serializer = :json 6 | -------------------------------------------------------------------------------- /myapp/config/initializers/filter_parameter_logging.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Configure parameters to be partially matched (e.g. passw matches password) and filtered from the log file. 4 | # Use this to limit dissemination of sensitive information. 5 | # See the ActiveSupport::ParameterFilter documentation for supported notations and behaviors. 6 | Rails.application.config.filter_parameters += [ 7 | :passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn 8 | ] 9 | -------------------------------------------------------------------------------- /myapp/config/initializers/secret_token.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | # Make sure the secret is at least 30 characters and all random, 6 | # no regular words or you'll be exposed to dictionary attacks. 7 | Myapp::Application.config.secret_token = "bdd335500c81ba1f279f9dd8198d1f334445d0193168ed73c1282502180dca27e3e102ec345e99b2acac6a63f7fe29da69c60cc9e76e8da34fb5d4989db24cd8" 8 | -------------------------------------------------------------------------------- /myapp/config/initializers/session_store.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | Rails.application.config.session_store :cookie_store, key: "_myapp_session" 4 | -------------------------------------------------------------------------------- /myapp/config/initializers/wrap_parameters.rb: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # This file contains settings for ActionController::ParamsWrapper which 4 | # is enabled by default. 5 | 6 | # Enable parameter wrapping for JSON. You can disable this by setting :format to an empty array. 7 | ActiveSupport.on_load(:action_controller) do 8 | wrap_parameters format: [:json] 9 | end 10 | 11 | # To enable root element in JSON for ActiveRecord objects. 12 | # ActiveSupport.on_load(:active_record) do 13 | # self.include_root_in_json = true 14 | # end 15 | -------------------------------------------------------------------------------- /myapp/config/locales/en.yml: -------------------------------------------------------------------------------- 1 | # Files in the config/locales directory are used for internationalization 2 | # and are automatically loaded by Rails. If you want to use locales other 3 | # than English, add the necessary files in this directory. 4 | # 5 | # To use the locales, use `I18n.t`: 6 | # 7 | # I18n.t "hello" 8 | # 9 | # In views, this is aliased to just `t`: 10 | # 11 | # <%= t("hello") %> 12 | # 13 | # To use a different locale, set it with `I18n.locale`: 14 | # 15 | # I18n.locale = :es 16 | # 17 | # This would use the information in config/locales/es.yml. 18 | # 19 | # The following keys must be escaped otherwise they will not be retrieved by 20 | # the default I18n backend: 21 | # 22 | # true, false, on, off, yes, no 23 | # 24 | # Instead, surround them with single quotes. 25 | # 26 | # en: 27 | # "true": "foo" 28 | # 29 | # To learn more, please read the Rails Internationalization guide 30 | # available at https://guides.rubyonrails.org/i18n.html. 31 | 32 | en: 33 | hello: "Hello world" 34 | -------------------------------------------------------------------------------- /myapp/config/puma.rb: -------------------------------------------------------------------------------- 1 | # Puma can serve each request in a thread from an internal thread pool. 2 | # The `threads` method setting takes two numbers: a minimum and maximum. 3 | # Any libraries that use thread pools should be configured to match 4 | # the maximum value specified for Puma. Default is set to 5 threads for minimum 5 | # and maximum; this matches the default thread size of Active Record. 6 | # 7 | max_threads_count = ENV.fetch("RAILS_MAX_THREADS", 5) 8 | min_threads_count = ENV.fetch("RAILS_MIN_THREADS") { max_threads_count } 9 | threads min_threads_count, max_threads_count 10 | 11 | # Specifies the `worker_timeout` threshold that Puma will use to wait before 12 | # terminating a worker in development environments. 13 | # 14 | worker_timeout 3600 if ENV.fetch("RAILS_ENV", "development") == "development" 15 | 16 | # Specifies the `port` that Puma will listen on to receive requests; default is 3000. 17 | # 18 | port ENV.fetch("PORT", 3000) 19 | 20 | # Specifies the `environment` that Puma will run in. 21 | # 22 | environment ENV.fetch("RAILS_ENV") { "development" } 23 | 24 | # Specifies the `pidfile` that Puma will use. 25 | pidfile ENV.fetch("PIDFILE") { "tmp/pids/server.pid" } 26 | 27 | # Specifies the number of `workers` to boot in clustered mode. 28 | # Workers are forked web server processes. If using threads and workers together 29 | # the concurrency of the application would be max `threads` * `workers`. 30 | # Workers do not work on JRuby or Windows (both of which do not support 31 | # processes). 32 | # 33 | workers ENV.fetch("WEB_CONCURRENCY", 2) 34 | 35 | # Use the `preload_app!` method when specifying a `workers` number. 36 | # This directive tells Puma to first boot the application and load code 37 | # before forking the application. This takes advantage of Copy On Write 38 | # process behavior so workers use less memory. 39 | preload_app! 40 | 41 | # Allow puma to be restarted by `bin/rails restart` command. 42 | plugin :tmp_restart 43 | 44 | x = nil 45 | on_worker_boot do 46 | x = Sidekiq.configure_embed do |config| 47 | config.queues = %w[critical default low] 48 | # don't raise this unless you know your app has available CPU time to burn. 49 | # it's easy to overload a Ruby process with too many threads. 50 | config.concurrency = 2 51 | end 52 | x&.run 53 | end 54 | 55 | on_worker_shutdown do 56 | x&.stop 57 | end 58 | -------------------------------------------------------------------------------- /myapp/config/routes.rb: -------------------------------------------------------------------------------- 1 | # turns off browser asset caching so we can test CSS changes quickly 2 | ENV["SIDEKIQ_WEB_TESTING"] = "1" 3 | 4 | require "sidekiq/web" 5 | Sidekiq::Web.app_url = "/" 6 | 7 | Rails.application.routes.draw do 8 | mount Sidekiq::Web => "/sidekiq" 9 | get "job" => "job#index" 10 | get "job/email" => "job#email" 11 | get "job/post" => "job#delayed_post" 12 | get "job/long" => "job#long" 13 | get "job/crash" => "job#crash" 14 | get "job/bulk" => "job#bulk" 15 | end 16 | -------------------------------------------------------------------------------- /myapp/config/secrets.yml: -------------------------------------------------------------------------------- 1 | # Be sure to restart your server when you modify this file. 2 | 3 | # Your secret key is used for verifying the integrity of signed cookies. 4 | # If you change this key, all old signed cookies will become invalid! 5 | 6 | # Make sure the secret is at least 30 characters and all random, 7 | # no regular words or you'll be exposed to dictionary attacks. 8 | # You can use `rake secret` to generate a secure secret key. 9 | 10 | # Make sure the secrets in this file are kept private 11 | # if you're sharing your code publicly. 12 | 13 | development: 14 | secret_key_base: c96477a6cbbc1304f41d7b26d5acb28187a8e8a16308a6d0d0310433e86054fe0bbc6d23a5c9269bd21b1a45650dd0ace354db80b9647bffb1c8bb600a00a1ae 15 | 16 | test: 17 | secret_key_base: ff0824c8b17ce583c8402dbe9968fec3a169dd6a294d4768fdef22cb083a048a2b4bababc5f37ca3a5d3c1b034e13fd703490671cb32db2983c4abb65e67fb09 18 | 19 | # Do not keep production secrets in the repository, 20 | # instead read values from the environment. 21 | production: 22 | secret_key_base: <%= ENV["SECRET_KEY_BASE"] %> 23 | -------------------------------------------------------------------------------- /myapp/config/sidekiq.yml: -------------------------------------------------------------------------------- 1 | --- 2 | :labels: 3 | - some_label 4 | -------------------------------------------------------------------------------- /myapp/db/migrate/20120123214055_create_posts.rb: -------------------------------------------------------------------------------- 1 | class CreatePosts < ActiveRecord::Migration[6.0] 2 | def change 3 | create_table :posts do |t| 4 | t.string :title 5 | t.string :body 6 | 7 | t.timestamps 8 | end 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /myapp/db/schema.rb: -------------------------------------------------------------------------------- 1 | # This file is auto-generated from the current state of the database. Instead 2 | # of editing this file, please use the migrations feature of Active Record to 3 | # incrementally modify your database, and then regenerate this schema definition. 4 | # 5 | # This file is the source Rails uses to define your schema when running `bin/rails 6 | # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to 7 | # be faster and is potentially less error prone than running all of your 8 | # migrations from scratch. Old migrations may fail to apply correctly if those 9 | # migrations use external dependencies or application code. 10 | # 11 | # It's strongly recommended that you check this file into your version control system. 12 | 13 | ActiveRecord::Schema.define(version: 2012_01_23_214055) do 14 | create_table "posts", force: :cascade do |t| 15 | t.string "title" 16 | t.string "body" 17 | t.datetime "created_at", precision: 6, null: false 18 | t.datetime "updated_at", precision: 6, null: false 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /myapp/db/seeds.rb: -------------------------------------------------------------------------------- 1 | # This file should contain all the record creation needed to seed the database with its default values. 2 | # The data can then be loaded with the bin/rails db:seed command (or created alongside the database with db:setup). 3 | # 4 | # Examples: 5 | # 6 | # movies = Movie.create([{ name: "Star Wars" }, { name: "Lord of the Rings" }]) 7 | # Character.create(name: "Luke", movie: movies.first) 8 | -------------------------------------------------------------------------------- /myapp/simple.ru: -------------------------------------------------------------------------------- 1 | # Easiest way to run Sidekiq::Web. 2 | # Run with "bundle exec rackup simple.ru" 3 | 4 | require "sidekiq/web" 5 | 6 | # A Web process always runs as client, no need to configure server 7 | Sidekiq.configure_client do |config| 8 | config.redis = {url: "redis://localhost:6379/0", size: 1} 9 | end 10 | 11 | Sidekiq::Client.push("class" => "HardJob", "args" => []) 12 | 13 | # In a multi-process deployment, all Web UI instances should share 14 | # this secret key so they can all decode the encrypted browser cookies 15 | # and provide a working session. 16 | # Rails does this in /config/initializers/secret_token.rb 17 | secret_key = SecureRandom.hex(32) 18 | use Rack::Session::Cookie, secret: secret_key, same_site: true, max_age: 86400 19 | run Sidekiq::Web 20 | -------------------------------------------------------------------------------- /sidekiq.gemspec: -------------------------------------------------------------------------------- 1 | require_relative "lib/sidekiq/version" 2 | 3 | Gem::Specification.new do |gem| 4 | gem.authors = ["Mike Perham"] 5 | gem.email = ["info@contribsys.com"] 6 | gem.summary = "Simple, efficient background processing for Ruby" 7 | gem.description = "Simple, efficient background processing for Ruby." 8 | gem.homepage = "https://sidekiq.org" 9 | gem.license = "LGPL-3.0" 10 | 11 | gem.executables = ["sidekiq", "sidekiqmon"] 12 | gem.files = %w[sidekiq.gemspec README.md Changes.md LICENSE.txt] + `git ls-files | grep -E '^(bin|lib|web)'`.split("\n") 13 | gem.name = "sidekiq" 14 | gem.version = Sidekiq::VERSION 15 | gem.required_ruby_version = ">= 2.7.0" 16 | 17 | gem.metadata = { 18 | "homepage_uri" => "https://sidekiq.org", 19 | "bug_tracker_uri" => "https://github.com/sidekiq/sidekiq/issues", 20 | "documentation_uri" => "https://github.com/sidekiq/sidekiq/wiki", 21 | "changelog_uri" => "https://github.com/sidekiq/sidekiq/blob/main/Changes.md", 22 | "source_code_uri" => "https://github.com/sidekiq/sidekiq", 23 | "rubygems_mfa_required" => "true" 24 | } 25 | 26 | gem.add_dependency "redis-client", ">= 0.19.0" 27 | gem.add_dependency "connection_pool", ">= 2.3.0" 28 | gem.add_dependency "rack", ">= 2.2.4" 29 | gem.add_dependency "concurrent-ruby", "< 2" 30 | end 31 | -------------------------------------------------------------------------------- /test/cfg/config__FILE__and__dir__.yml: -------------------------------------------------------------------------------- 1 | --- 2 | :require: ./test/fake_env.rb 3 | 4 | :__FILE__: <%= __FILE__ %> 5 | :__dir__: <%= __dir__ %> 6 | -------------------------------------------------------------------------------- /test/cfg/config_capsules.yml: -------------------------------------------------------------------------------- 1 | --- 2 | :verbose: false 3 | :require: ./test/fake_env.rb 4 | :concurrency: 50 5 | :queues: 6 | - [<%="very_"%>often, 2] 7 | - [seldom, 1] 8 | :capsules: 9 | :non_concurrent: 10 | :queues: 11 | - non_concurrent 12 | :concurrency: 1 13 | :binary: 14 | :queues: 15 | - sirius 16 | - sirius_b 17 | :concurrency: 2 18 | -------------------------------------------------------------------------------- /test/cfg/config_empty.yml: -------------------------------------------------------------------------------- 1 | --- 2 | -------------------------------------------------------------------------------- /test/cfg/config_environment.yml: -------------------------------------------------------------------------------- 1 | --- 2 | :concurrency: 50 3 | 4 | staging: 5 | :verbose: false 6 | :require: ./test/fake_env.rb 7 | :concurrency: 50 8 | :queues: 9 | - [<%="very_"%>often, 2] 10 | - [seldom, 1] 11 | -------------------------------------------------------------------------------- /test/cfg/config_queues_without_weights.yml: -------------------------------------------------------------------------------- 1 | --- 2 | :queues: 3 | - [queue_1] 4 | - [queue_2] 5 | -------------------------------------------------------------------------------- /test/cfg/config_string.yml: -------------------------------------------------------------------------------- 1 | --- 2 | verbose: false 3 | require: ./test/fake_env.rb 4 | concurrency: 50 5 | queues: 6 | - [<%="very_"%>often, 2] 7 | - [seldom, 1] 8 | 9 | -------------------------------------------------------------------------------- /test/cfg/config_with_alias.yml: -------------------------------------------------------------------------------- 1 | --- 2 | :production: &production 3 | :verbose: true 4 | :require: ./test/fake_env.rb 5 | :concurrency: 50 6 | :queues: 7 | - [<%="very_"%>often, 2] 8 | - [seldom, 1] 9 | 10 | :staging: 11 | <<: *production 12 | :verbose: false -------------------------------------------------------------------------------- /test/cfg/config_with_internal_options.yml: -------------------------------------------------------------------------------- 1 | --- 2 | :verbose: false 3 | :timeout: 10 4 | :require: ./test/fake_env.rb 5 | :concurrency: 50 6 | :tag: tag 7 | :queues: 8 | - [often] 9 | - [seldom] 10 | 11 | :strict: false 12 | -------------------------------------------------------------------------------- /test/config.yml: -------------------------------------------------------------------------------- 1 | --- 2 | :verbose: false 3 | :require: ./test/fake_env.rb 4 | :concurrency: 50 5 | :queues: 6 | - [<%="very_"%>often, 2] 7 | - [seldom, 1] 8 | -------------------------------------------------------------------------------- /test/config_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "helper" 4 | 5 | describe Sidekiq::Config do 6 | before do 7 | @config = reset! 8 | end 9 | 10 | it "provides a default size" do 11 | @config.redis = {} 12 | assert_equal 10, @config.redis_pool.size 13 | end 14 | 15 | it "allows custom sizing" do 16 | @config.redis = {size: 3} 17 | assert_equal 3, @config.redis_pool.size 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /test/dead_set_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "helper" 4 | require "sidekiq/api" 5 | 6 | describe "DeadSet" do 7 | def dead_set 8 | Sidekiq::DeadSet.new 9 | end 10 | 11 | it 'should put passed serialized job to the "dead" sorted set' do 12 | serialized_job = Sidekiq.dump_json(jid: "123123", class: "SomeJob", args: []) 13 | dead_set.kill(serialized_job) 14 | 15 | assert_equal dead_set.find_job("123123").value, serialized_job 16 | end 17 | 18 | it "should remove dead jobs older than Sidekiq::DeadSet.timeout" do 19 | old, Sidekiq::Config::DEFAULTS[:dead_timeout_in_seconds] = Sidekiq::Config::DEFAULTS[:dead_timeout_in_seconds], 10 20 | Time.stub(:now, Time.now - 11) do 21 | dead_set.kill(Sidekiq.dump_json(jid: "000103", class: "MyJob3", args: [])) # the oldest 22 | end 23 | Time.stub(:now, Time.now - 9) do 24 | dead_set.kill(Sidekiq.dump_json(jid: "000102", class: "MyJob2", args: [])) 25 | end 26 | dead_set.kill(Sidekiq.dump_json(jid: "000101", class: "MyJob1", args: [])) 27 | 28 | assert_nil dead_set.find_job("000103") 29 | assert dead_set.find_job("000102") 30 | assert dead_set.find_job("000101") 31 | ensure 32 | Sidekiq::Config::DEFAULTS[:dead_timeout_in_seconds] = old 33 | end 34 | 35 | it "should remove all but last Sidekiq::DeadSet.max_jobs-1 jobs" do 36 | old, Sidekiq::Config::DEFAULTS[:dead_max_jobs] = Sidekiq::Config::DEFAULTS[:dead_max_jobs], 3 37 | dead_set.kill(Sidekiq.dump_json(jid: "000101", class: "MyJob1", args: [])) 38 | dead_set.kill(Sidekiq.dump_json(jid: "000102", class: "MyJob2", args: [])) 39 | dead_set.kill(Sidekiq.dump_json(jid: "000103", class: "MyJob3", args: [])) 40 | 41 | assert_nil dead_set.find_job("000101") 42 | assert dead_set.find_job("000102") 43 | assert dead_set.find_job("000103") 44 | ensure 45 | Sidekiq::Config::DEFAULTS[:dead_max_jobs] = old 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /test/dummy/config/application.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "rails" 4 | require "active_model/railtie" 5 | require "active_job/railtie" 6 | require "active_record/railtie" 7 | require "action_controller/railtie" 8 | require "action_mailer/railtie" 9 | require "action_view/railtie" 10 | require "rails/test_unit/railtie" 11 | 12 | module Dummy 13 | class Application < Rails::Application 14 | config.root = File.expand_path("../..", __FILE__) 15 | config.eager_load = false 16 | config.load_defaults "7.0" 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /test/dummy/config/database.yml: -------------------------------------------------------------------------------- 1 | development: 2 | adapter: sqlite3 3 | database: ":memory:" 4 | pool: 5 5 | timeout: 5000 6 | 7 | test: 8 | adapter: sqlite3 9 | database: ":memory:" 10 | pool: 5 11 | timeout: 5000 12 | -------------------------------------------------------------------------------- /test/dummy/config/environment.rb: -------------------------------------------------------------------------------- 1 | require_relative "application" 2 | 3 | Rails.application.initialize! 4 | -------------------------------------------------------------------------------- /test/dummy/config/sidekiq.yml: -------------------------------------------------------------------------------- 1 | --- 2 | :require: ./test/fake_env.rb 3 | :concurrency: 25 4 | -------------------------------------------------------------------------------- /test/dummy/tmp/.keep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/touchasky/sidekiq/dddf20bf0a6decfa6e19b04611fcb3a281d009a3/test/dummy/tmp/.keep -------------------------------------------------------------------------------- /test/fake_env.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | -------------------------------------------------------------------------------- /test/fetch_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "helper" 4 | require "sidekiq/fetch" 5 | require "sidekiq/capsule" 6 | require "sidekiq/api" 7 | 8 | describe Sidekiq::BasicFetch do 9 | before do 10 | @config = reset! 11 | @cap = @config.default_capsule 12 | @config.redis do |conn| 13 | conn.rpush("queue:basic", "msg") 14 | end 15 | end 16 | 17 | it "retrieves" do 18 | @cap.queues = ["basic", "bar,3"] 19 | fetch = Sidekiq::BasicFetch.new(@cap) 20 | 21 | uow = fetch.retrieve_work 22 | refute_nil uow 23 | assert_equal "basic", uow.queue_name 24 | assert_equal "msg", uow.job 25 | q = Sidekiq::Queue.new("basic") 26 | assert_equal 0, q.size 27 | uow.requeue 28 | assert_equal 1, q.size 29 | assert_nil uow.acknowledge 30 | end 31 | 32 | it "retrieves with strict ordering" do 33 | @cap.queues = ["basic", "bar"] 34 | fetch = Sidekiq::BasicFetch.new(@cap) 35 | cmd = fetch.queues_cmd 36 | assert_equal cmd, ["queue:basic", "queue:bar"] 37 | end 38 | 39 | it "bulk requeues" do 40 | @config.redis do |conn| 41 | conn.rpush("queue:foo", ["bob", "bar"]) 42 | conn.rpush("queue:bar", "widget") 43 | end 44 | 45 | q1 = Sidekiq::Queue.new("foo") 46 | q2 = Sidekiq::Queue.new("bar") 47 | assert_equal 2, q1.size 48 | assert_equal 1, q2.size 49 | 50 | @cap.queues = ["foo", "bar"] 51 | fetch = Sidekiq::BasicFetch.new(@cap) 52 | works = 3.times.map { fetch.retrieve_work } 53 | assert_equal 0, q1.size 54 | assert_equal 0, q2.size 55 | 56 | fetch.bulk_requeue(works) 57 | assert_equal 2, q1.size 58 | assert_equal 1, q2.size 59 | end 60 | 61 | it "sleeps when no queues are active" do 62 | @cap.queues = [] 63 | fetch = Sidekiq::BasicFetch.new(@cap) 64 | mock = Minitest::Mock.new 65 | mock.expect(:call, nil, [Sidekiq::BasicFetch::TIMEOUT]) 66 | fetch.stub(:sleep, mock) { assert_nil fetch.retrieve_work } 67 | mock.verify 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /test/filtering_test.rb: -------------------------------------------------------------------------------- 1 | require_relative "helper" 2 | require "sidekiq/web" 3 | require "rack/test" 4 | 5 | class FilterJob 6 | include Sidekiq::Job 7 | 8 | def perform(a, b) 9 | a + b 10 | end 11 | end 12 | 13 | describe "filtering" do 14 | include Rack::Test::Methods 15 | 16 | before do 17 | @config = reset! 18 | app.middlewares.clear 19 | end 20 | 21 | def app 22 | Sidekiq::Web 23 | end 24 | 25 | it "finds jobs matching substring" do 26 | jid1 = FilterJob.perform_in(5, "bob", "tammy") 27 | jid2 = FilterJob.perform_in(5, "mike", "jim") 28 | 29 | get "/scheduled" 30 | assert_equal 200, last_response.status 31 | assert_match(/#{jid1}/, last_response.body) 32 | assert_match(/#{jid2}/, last_response.body) 33 | 34 | post "/filter/scheduled", substr: "tammy" 35 | assert_equal 200, last_response.status 36 | assert_match(/#{jid1}/, last_response.body) 37 | refute_match(/#{jid2}/, last_response.body) 38 | 39 | post "/filter/scheduled", substr: "" 40 | assert_equal 302, last_response.status 41 | get "/filter/scheduled" 42 | assert_equal 302, last_response.status 43 | get "/filter/retries" 44 | assert_equal 302, last_response.status 45 | get "/filter/dead" 46 | assert_equal 302, last_response.status 47 | end 48 | end 49 | -------------------------------------------------------------------------------- /test/fixtures/en.yml: -------------------------------------------------------------------------------- 1 | en: 2 | translated_text: 'Changed text from add locals' 3 | -------------------------------------------------------------------------------- /test/helper.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require "bundler/setup" 4 | Bundler.require(:default, :test) 5 | 6 | require "minitest/pride" 7 | require "maxitest/autorun" 8 | require "maxitest/threads" 9 | 10 | $TESTING = true 11 | # disable minitest/parallel threads 12 | ENV["MT_CPU"] = "0" 13 | ENV["N"] = "0" 14 | # Disable any stupid backtrace cleansers 15 | ENV["BACKTRACE"] = "1" 16 | 17 | if ENV["COVERAGE"] 18 | require "simplecov" 19 | SimpleCov.start do 20 | enable_coverage :branch 21 | add_filter "/test/" 22 | add_filter "/myapp/" 23 | minimum_coverage 90 24 | end 25 | end 26 | 27 | ENV["REDIS_URL"] ||= "redis://localhost/15" 28 | NULL_LOGGER = Logger.new(IO::NULL) 29 | 30 | def reset! 31 | # tidy up any open but unreferenced Redis connections so we don't run out of file handles 32 | if Sidekiq.default_configuration.instance_variable_defined?(:@redis) 33 | existing_pool = Sidekiq.default_configuration.instance_variable_get(:@redis) 34 | existing_pool&.shutdown(&:close) 35 | end 36 | 37 | RedisClient.new(url: ENV["REDIS_URL"]).call("flushall") 38 | cfg = Sidekiq::Config.new 39 | cfg[:backtrace_cleaner] = Sidekiq::Config::DEFAULTS[:backtrace_cleaner] 40 | cfg.logger = NULL_LOGGER 41 | cfg.logger.level = Logger::WARN 42 | Sidekiq.instance_variable_set :@config, cfg 43 | cfg 44 | end 45 | 46 | def capture_logging(cfg, lvl = Logger::INFO) 47 | old = cfg.logger 48 | begin 49 | out = StringIO.new 50 | logger = ::Logger.new(out) 51 | logger.level = lvl 52 | cfg.logger = logger 53 | yield logger 54 | out.string 55 | ensure 56 | cfg.logger = old 57 | end 58 | end 59 | 60 | Signal.trap("TTIN") do 61 | Thread.list.each do |thread| 62 | puts "Thread TID-#{(thread.object_id ^ ::Process.pid).to_s(36)} #{thread.name}" 63 | if thread.backtrace 64 | puts thread.backtrace.join("\n") 65 | else 66 | puts "" 67 | end 68 | end 69 | end 70 | -------------------------------------------------------------------------------- /test/job_generator_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "helper" 4 | require_relative "dummy/config/environment" 5 | require "rails/generators/test_case" 6 | require "generators/sidekiq/job_generator" 7 | 8 | class JobGeneratorTest < Rails::Generators::TestCase 9 | tests Sidekiq::Generators::JobGenerator 10 | destination File.expand_path("../../tmp", __FILE__) 11 | setup :prepare_destination 12 | 13 | def before_setup 14 | Rails.logger.level = Logger::WARN 15 | super 16 | end 17 | 18 | test "all files are properly created" do 19 | run_generator ["foo"] 20 | assert_file "app/sidekiq/foo_job.rb" 21 | assert_file "test/sidekiq/foo_job_test.rb" 22 | end 23 | 24 | test "gracefully handles extra job suffix" do 25 | run_generator ["foo_job"] 26 | assert_no_file "app/sidekiq/foo_job_job.rb" 27 | assert_no_file "test/sidekiq/foo_job_job_test.rb" 28 | 29 | assert_file "app/sidekiq/foo_job.rb" 30 | assert_file "test/sidekiq/foo_job_test.rb" 31 | end 32 | 33 | test "respects rails config test_framework option" do 34 | Rails.application.config.generators do |g| 35 | g.test_framework false 36 | end 37 | 38 | run_generator ["foo"] 39 | 40 | assert_file "app/sidekiq/foo_job.rb" 41 | assert_no_file "test/sidekiq/foo_job_test.rb" 42 | ensure 43 | Rails.application.config.generators do |g| 44 | g.test_framework :test_case 45 | end 46 | end 47 | 48 | test "respects rails config test_framework option for rspec" do 49 | Rails.application.config.generators do |g| 50 | g.test_framework :rspec 51 | end 52 | 53 | run_generator ["foo"] 54 | 55 | assert_file "app/sidekiq/foo_job.rb" 56 | assert_file "spec/sidekiq/foo_job_spec.rb" 57 | ensure 58 | Rails.application.config.generators do |g| 59 | g.test_framework :test_case 60 | end 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /test/launcher_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "helper" 4 | require "sidekiq/launcher" 5 | 6 | describe Sidekiq::Launcher do 7 | before do 8 | @config = reset! 9 | @config.default_capsule.concurrency = 3 10 | @config[:tag] = "myapp" 11 | end 12 | 13 | describe "memory collection" do 14 | it "works in any test environment" do 15 | kb = Sidekiq::Launcher::MEMORY_GRABBER.call($$) 16 | refute_nil kb 17 | assert kb > 0 18 | end 19 | end 20 | 21 | it "starts and stops" do 22 | l = Sidekiq::Launcher.new(@config) 23 | l.run(async_beat: false) 24 | l.stop 25 | end 26 | 27 | describe "heartbeat" do 28 | before do 29 | @launcher = Sidekiq::Launcher.new(@config) 30 | @id = @launcher.identity 31 | 32 | Sidekiq::Processor::WORK_STATE.set("a", {"b" => 1}) 33 | 34 | @proctitle = $0 35 | end 36 | 37 | after do 38 | Sidekiq::Processor::WORK_STATE.clear 39 | $0 = @proctitle 40 | end 41 | 42 | it "stores process info in redis" do 43 | @launcher.beat 44 | 45 | assert_equal "sidekiq #{Sidekiq::VERSION} myapp [1 of 3 busy]", $0 46 | workers, rtt = @config.redis { |c| c.hmget(@id, "busy", "rtt_us") } 47 | 48 | assert_equal "1", workers 49 | refute_nil rtt 50 | assert_in_delta 1000, rtt.to_i, 1000 51 | 52 | expires = @config.redis { |c| c.pttl(@id) } 53 | assert_in_delta 60000, expires, 500 54 | end 55 | 56 | it "fires start heartbeat event only once" do 57 | cnt = 0 58 | 59 | @config.on(:heartbeat) do 60 | cnt += 1 61 | end 62 | assert_equal 0, cnt 63 | @launcher.heartbeat 64 | assert_equal 1, cnt 65 | @launcher.heartbeat 66 | assert_equal 1, cnt 67 | end 68 | 69 | it "quiets" do 70 | @launcher.quiet 71 | @launcher.beat 72 | 73 | assert_equal "sidekiq #{Sidekiq::VERSION} myapp [1 of 3 busy] stopping", $0 74 | 75 | @launcher.beat 76 | info = @config.redis { |c| c.hmget(@id, "busy") } 77 | assert_equal ["1"], info 78 | 79 | expires = @config.redis { |c| c.pttl(@id) } 80 | assert_in_delta 60000, expires, 50 81 | end 82 | 83 | it "allows arbitrary proctitle extensions" do 84 | Sidekiq::Launcher::PROCTITLES << proc { "xyz" } 85 | @launcher.beat 86 | Sidekiq::Launcher::PROCTITLES.pop 87 | assert_equal "sidekiq #{Sidekiq::VERSION} myapp [1 of 3 busy] xyz", $0 88 | end 89 | end 90 | end 91 | -------------------------------------------------------------------------------- /test/manager_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "helper" 4 | require "sidekiq/manager" 5 | 6 | describe Sidekiq::Manager do 7 | before do 8 | @config = reset! 9 | @cap = @config.default_capsule 10 | end 11 | 12 | def new_manager 13 | Sidekiq::Manager.new(@cap) 14 | end 15 | 16 | it "creates N processor instances" do 17 | mgr = new_manager 18 | assert_equal @cap.concurrency, mgr.workers.size 19 | end 20 | 21 | it "shuts down the system" do 22 | mgr = new_manager 23 | mgr.start 24 | mgr.stop(::Process.clock_gettime(::Process::CLOCK_MONOTONIC)) 25 | end 26 | 27 | it "throws away dead processors" do 28 | mgr = new_manager 29 | init_size = mgr.workers.size 30 | processor = mgr.workers.first 31 | mgr.quiet 32 | mgr.processor_result(processor, "ignored") 33 | 34 | assert_equal init_size - 1, mgr.workers.size 35 | refute mgr.workers.include?(processor) 36 | end 37 | end 38 | -------------------------------------------------------------------------------- /test/rails_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "helper" 4 | require "active_job" 5 | require "sidekiq/rails" 6 | require "sidekiq/api" 7 | 8 | describe "ActiveJob" do 9 | before do 10 | @config = reset! 11 | # need to force this since we aren't booting a Rails app 12 | ActiveJob::Base.queue_adapter = :sidekiq 13 | ActiveJob::Base.logger = nil 14 | ActiveJob::Base.send(:include, ::Sidekiq::Job::Options) unless ActiveJob::Base.respond_to?(:sidekiq_options) 15 | @config[:backtrace_cleaner] = ->(backtrace) { Rails.backtrace_cleaner.clean(backtrace) } 16 | end 17 | 18 | it "does not allow Sidekiq::Job in AJ::Base classes" do 19 | ex = assert_raises ArgumentError do 20 | Class.new(ActiveJob::Base) do 21 | include Sidekiq::Job 22 | end 23 | end 24 | assert_includes ex.message, "Sidekiq::Job cannot be included" 25 | end 26 | 27 | it "loads Sidekiq::Job::Options in AJ::Base classes" do 28 | aj = Class.new(ActiveJob::Base) do 29 | queue_as :bar 30 | sidekiq_options retry: 4, queue: "foo", backtrace: 5 31 | sidekiq_retry_in { |count, _exception| count * 10 } 32 | sidekiq_retries_exhausted do |msg, _exception| 33 | @config.logger.warn "Failed #{msg["class"]} with #{msg["args"]}: #{msg["error_message"]}" 34 | end 35 | end 36 | 37 | assert_equal 4, aj.get_sidekiq_options["retry"] 38 | 39 | # When using ActiveJobs, you cannot set the queue with sidekiq_options, you must use 40 | # queue_as or set(queue: ...). This is to avoid duplicate ways of doing the same thing. 41 | instance = aj.perform_later(1, 2, 3) 42 | q = Sidekiq::Queue.new("foo") 43 | assert_equal 0, q.size 44 | q = Sidekiq::Queue.new("bar") 45 | assert_equal 1, q.size 46 | assert_equal 24, instance.provider_job_id.size 47 | 48 | job = q.first 49 | assert_equal 4, job["retry"] 50 | assert_equal 5, job["backtrace"] 51 | # AJ's queue_as should take precedence over Sidekiq's queue option 52 | assert_equal "bar", job["queue"] 53 | end 54 | end 55 | -------------------------------------------------------------------------------- /test/scheduling_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "helper" 4 | require "sidekiq/api" 5 | require "active_support/core_ext/integer/time" 6 | 7 | class SomeScheduledJob 8 | include Sidekiq::Job 9 | sidekiq_options queue: :custom_queue 10 | def perform(x) 11 | end 12 | end 13 | 14 | # Assume we can pass any class as time to perform_in 15 | class TimeDuck 16 | def to_f 17 | 42.0 18 | end 19 | end 20 | 21 | describe "job scheduling" do 22 | before do 23 | reset! 24 | end 25 | describe "middleware" do 26 | it "schedules jobs" do 27 | ss = Sidekiq::ScheduledSet.new 28 | ss.clear 29 | 30 | assert_equal 0, ss.size 31 | 32 | assert SomeScheduledJob.perform_in(600, "mike") 33 | assert_equal 1, ss.size 34 | 35 | assert SomeScheduledJob.perform_in(1.month, "mike") 36 | assert_equal 2, ss.size 37 | 38 | assert SomeScheduledJob.perform_in(5.days.from_now, "mike") 39 | assert_equal 3, ss.size 40 | 41 | q = Sidekiq::Queue.new("custom_queue") 42 | qs = q.size 43 | assert SomeScheduledJob.perform_in(-300, "mike") 44 | assert_equal 3, ss.size 45 | assert_equal qs + 1, q.size 46 | 47 | assert Sidekiq::Client.push_bulk("class" => SomeScheduledJob, "args" => [["mike"], ["mike"]], "at" => Time.now.to_f + 100) 48 | assert_equal 5, ss.size 49 | 50 | assert SomeScheduledJob.perform_in(TimeDuck.new, "samwise") 51 | assert_equal 6, ss.size 52 | end 53 | 54 | it "removes the enqueued_at field when scheduling" do 55 | ss = Sidekiq::ScheduledSet.new 56 | ss.clear 57 | 58 | assert SomeScheduledJob.perform_in(1.month, "mike") 59 | job = ss.first 60 | assert job["created_at"] 61 | refute job["enqueued_at"] 62 | end 63 | 64 | it "removes the enqueued_at field when scheduling in bulk" do 65 | ss = Sidekiq::ScheduledSet.new 66 | ss.clear 67 | 68 | assert Sidekiq::Client.push_bulk("class" => SomeScheduledJob, "args" => [["mike"], ["mike"]], "at" => Time.now.to_f + 100) 69 | job = ss.first 70 | assert job["created_at"] 71 | refute job["enqueued_at"] 72 | end 73 | end 74 | end 75 | -------------------------------------------------------------------------------- /test/sharding_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "helper" 4 | require "sidekiq" 5 | require "sidekiq/api" 6 | 7 | class ShardJob 8 | include Sidekiq::Job 9 | end 10 | 11 | class ShardMiddleware 12 | include Sidekiq::ClientMiddleware 13 | def call(wrkr, job, q, pool) 14 | # set a flag so we can inspect which shard is active 15 | redis { |c| c.set("flag", job["jid"]) } 16 | fl = pool.with { |c| c.get("flag") } 17 | raise "Pool and redis are out of sync!" if fl != job["jid"] 18 | yield 19 | end 20 | end 21 | 22 | describe "Sharding" do 23 | before do 24 | @config = reset! 25 | @sh1 = Sidekiq::RedisConnection.create(size: 1, db: 6) 26 | @sh2 = Sidekiq::RedisConnection.create(size: 1, db: 5) 27 | end 28 | 29 | after do 30 | @sh1.shutdown(&:close) 31 | @sh2.shutdown(&:close) 32 | end 33 | 34 | def flags 35 | [Sidekiq.redis_pool, @sh1, @sh2].map do |pool| 36 | pool.with { |c| c.get("flag") } 37 | end 38 | end 39 | 40 | describe "client" do 41 | it "redirects the middleware pool to the current shard" do 42 | @config.client_middleware.add ShardMiddleware 43 | 44 | jid1 = nil 45 | Sidekiq::Client.via(@sh1) do 46 | jid1 = ShardJob.perform_async 47 | assert_equal [jid1, jid1, nil], flags 48 | end 49 | assert_equal [nil, jid1, nil], flags 50 | 51 | jid2 = nil 52 | Sidekiq::Client.via(@sh2) do 53 | jid2 = ShardJob.perform_async 54 | assert_equal [jid2, jid1, jid2], flags 55 | end 56 | assert_equal [nil, jid1, jid2], flags 57 | end 58 | 59 | it "routes jobs to the proper shard" do 60 | q = Sidekiq::Queue.new 61 | ss = Sidekiq::ScheduledSet.new 62 | assert_equal 0, q.size 63 | assert_equal 0, ss.size 64 | 65 | # redirect jobs with magic block 66 | Sidekiq::Client.via(@sh1) do 67 | assert_equal 0, q.size 68 | assert_equal 0, ss.size 69 | ShardJob.perform_async 70 | ShardJob.perform_in(3) 71 | assert_equal 1, q.size 72 | assert_equal 1, ss.size 73 | end 74 | 75 | Sidekiq::Client.via(@sh2) do 76 | assert_equal 0, ss.size 77 | assert_equal 0, q.size 78 | end 79 | 80 | # redirect jobs explicitly with pool attribute 81 | ShardJob.set(pool: @sh2).perform_async 82 | ShardJob.set(pool: @sh2).perform_in(4) 83 | Sidekiq::Client.via(@sh2) do 84 | assert_equal 1, q.size 85 | assert_equal 1, ss.size 86 | end 87 | 88 | assert_equal 0, ss.size 89 | assert_equal 0, q.size 90 | end 91 | end 92 | end 93 | -------------------------------------------------------------------------------- /test/systemd_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "helper" 4 | require "sidekiq/sd_notify" 5 | require "sidekiq/systemd" 6 | 7 | describe "Systemd" do 8 | before do 9 | ::Dir::Tmpname.create("sidekiq_socket") do |sockaddr| 10 | @sockaddr = sockaddr 11 | @socket = Socket.new(:UNIX, :DGRAM, 0) 12 | socket_ai = Addrinfo.unix(sockaddr) 13 | @socket.bind(socket_ai) 14 | ENV["NOTIFY_SOCKET"] = sockaddr 15 | end 16 | end 17 | 18 | after do 19 | @socket&.close 20 | File.unlink(@sockaddr) if @sockaddr 21 | @socket = nil 22 | @sockaddr = nil 23 | end 24 | 25 | def socket_message 26 | @socket.recvfrom(10)[0] 27 | end 28 | 29 | it "notifies" do 30 | count = Sidekiq::SdNotify.ready 31 | assert_equal(socket_message, "READY=1") 32 | assert_equal(ENV["NOTIFY_SOCKET"], @sockaddr) 33 | assert_equal(count, 7) 34 | 35 | count = Sidekiq::SdNotify.stopping 36 | assert_equal(socket_message, "STOPPING=1") 37 | assert_equal(ENV["NOTIFY_SOCKET"], @sockaddr) 38 | assert_equal(count, 10) 39 | 40 | refute Sidekiq::SdNotify.watchdog? 41 | end 42 | end 43 | -------------------------------------------------------------------------------- /test/testing_inline_test.rb: -------------------------------------------------------------------------------- 1 | # frozen_string_literal: true 2 | 3 | require_relative "helper" 4 | 5 | class InlineError < RuntimeError; end 6 | 7 | class ParameterIsNotString < RuntimeError; end 8 | 9 | class InlineJob 10 | include Sidekiq::Job 11 | def perform(pass) 12 | raise ArgumentError, "no jid" unless jid 13 | raise InlineError unless pass 14 | end 15 | end 16 | 17 | class InlineJobWithTimeParam 18 | include Sidekiq::Job 19 | def perform(time) 20 | raise ParameterIsNotString unless time.is_a?(String) || time.is_a?(Numeric) 21 | end 22 | end 23 | 24 | describe "Sidekiq::Testing.inline" do 25 | before do 26 | reset! 27 | require "sidekiq/testing/inline" 28 | Sidekiq::Testing.inline! 29 | end 30 | 31 | after do 32 | Sidekiq::Testing.disable! 33 | end 34 | 35 | it "stubs the async call when in testing mode" do 36 | assert InlineJob.perform_async(true) 37 | 38 | assert_raises InlineError do 39 | InlineJob.perform_async(false) 40 | end 41 | end 42 | 43 | it "stubs the enqueue call when in testing mode" do 44 | assert Sidekiq::Client.enqueue(InlineJob, true) 45 | 46 | assert_raises InlineError do 47 | Sidekiq::Client.enqueue(InlineJob, false) 48 | end 49 | end 50 | 51 | it "stubs the push_bulk call when in testing mode" do 52 | assert Sidekiq::Client.push_bulk({"class" => InlineJob, "args" => [[true], [true]]}) 53 | 54 | assert_raises InlineError do 55 | Sidekiq::Client.push_bulk({"class" => InlineJob, "args" => [[true], [false]]}) 56 | end 57 | end 58 | 59 | it "should relay parameters through json" do 60 | assert Sidekiq::Client.enqueue(InlineJobWithTimeParam, Time.now.to_f) 61 | end 62 | end 63 | -------------------------------------------------------------------------------- /web/assets/images/apple-touch-icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/touchasky/sidekiq/dddf20bf0a6decfa6e19b04611fcb3a281d009a3/web/assets/images/apple-touch-icon.png -------------------------------------------------------------------------------- /web/assets/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/touchasky/sidekiq/dddf20bf0a6decfa6e19b04611fcb3a281d009a3/web/assets/images/favicon.ico -------------------------------------------------------------------------------- /web/assets/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/touchasky/sidekiq/dddf20bf0a6decfa6e19b04611fcb3a281d009a3/web/assets/images/logo.png -------------------------------------------------------------------------------- /web/assets/images/status.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/touchasky/sidekiq/dddf20bf0a6decfa6e19b04611fcb3a281d009a3/web/assets/images/status.png -------------------------------------------------------------------------------- /web/assets/javascripts/base-charts.js: -------------------------------------------------------------------------------- 1 | if (window.matchMedia("(prefers-color-scheme: dark)").matches) { 2 | Chart.defaults.borderColor = "#333"; 3 | Chart.defaults.color = "#aaa"; 4 | } 5 | 6 | class Colors { 7 | constructor() { 8 | this.assignments = {}; 9 | this.success = "#006f68"; 10 | this.failure = "#af0014"; 11 | this.fallback = "#999"; 12 | this.primary = "#537bc4"; 13 | this.available = [ 14 | // Colors taken from https://www.chartjs.org/docs/latest/samples/utils.html 15 | "#537bc4", 16 | "#4dc9f6", 17 | "#f67019", 18 | "#f53794", 19 | "#acc236", 20 | "#166a8f", 21 | "#00a950", 22 | "#58595b", 23 | "#8549ba", 24 | "#991b1b", 25 | ]; 26 | } 27 | 28 | checkOut(assignee) { 29 | const color = 30 | this.assignments[assignee] || this.available.shift() || this.fallback; 31 | this.assignments[assignee] = color; 32 | return color; 33 | } 34 | 35 | checkIn(assignee) { 36 | const color = this.assignments[assignee]; 37 | delete this.assignments[assignee]; 38 | 39 | if (color && color != this.fallback) { 40 | this.available.unshift(color); 41 | } 42 | } 43 | } 44 | 45 | class BaseChart { 46 | constructor(el, options) { 47 | this.el = el; 48 | this.options = options; 49 | this.colors = new Colors(); 50 | } 51 | 52 | init() { 53 | this.chart = new Chart(this.el, { 54 | type: this.options.chartType, 55 | data: { labels: this.options.labels, datasets: this.datasets }, 56 | options: this.chartOptions, 57 | }); 58 | } 59 | 60 | update() { 61 | this.chart.options = this.chartOptions; 62 | this.chart.update(); 63 | } 64 | 65 | get chartOptions() { 66 | let chartOptions = { 67 | interaction: { 68 | mode: "nearest", 69 | axis: "x", 70 | intersect: false, 71 | }, 72 | scales: { 73 | x: { 74 | ticks: { 75 | autoSkipPadding: 10, 76 | }, 77 | }, 78 | }, 79 | plugins: { 80 | legend: { 81 | display: false, 82 | }, 83 | annotation: { 84 | annotations: {}, 85 | }, 86 | tooltip: { 87 | animation: false, 88 | }, 89 | }, 90 | }; 91 | 92 | if (this.options.marks) { 93 | this.options.marks.forEach(([bucket, label], i) => { 94 | chartOptions.plugins.annotation.annotations[`deploy-${i}`] = { 95 | type: "line", 96 | xMin: bucket, 97 | xMax: bucket, 98 | borderColor: "rgba(220, 38, 38, 0.4)", 99 | borderWidth: 2, 100 | }; 101 | }); 102 | } 103 | 104 | return chartOptions; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /web/assets/javascripts/dashboard.js: -------------------------------------------------------------------------------- 1 | Sidekiq = {}; 2 | 3 | var updateStatsSummary = function(data) { 4 | document.getElementById("txtProcessed").innerText = data.processed; 5 | document.getElementById("txtFailed").innerText = data.failed; 6 | document.getElementById("txtBusy").innerText = data.busy; 7 | document.getElementById("txtScheduled").innerText = data.scheduled; 8 | document.getElementById("txtRetries").innerText = data.retries; 9 | document.getElementById("txtEnqueued").innerText = data.enqueued; 10 | document.getElementById("txtDead").innerText = data.dead; 11 | } 12 | 13 | var updateRedisStats = function(data) { 14 | document.getElementById('redis_version').innerText = data.redis_version; 15 | document.getElementById('uptime_in_days').innerText = data.uptime_in_days; 16 | document.getElementById('connected_clients').innerText = data.connected_clients; 17 | document.getElementById('used_memory_human').innerText = data.used_memory_human; 18 | document.getElementById('used_memory_peak_human').innerText = data.used_memory_peak_human; 19 | } 20 | 21 | var updateFooterUTCTime = function(time) { 22 | document.getElementById('serverUtcTime').innerText = time; 23 | } 24 | 25 | var pulseBeacon = function() { 26 | document.getElementById('beacon').classList.add('pulse'); 27 | window.setTimeout(() => { document.getElementById('beacon').classList.remove('pulse'); }, 1000); 28 | } 29 | 30 | var setSliderLabel = function(val) { 31 | document.getElementById('sldr-text').innerText = Math.round(parseFloat(val) / 1000) + ' sec'; 32 | } 33 | 34 | var ready = (callback) => { 35 | if (document.readyState != "loading") callback(); 36 | else document.addEventListener("DOMContentLoaded", callback); 37 | } 38 | 39 | ready(() => { 40 | var sldr = document.getElementById('sldr'); 41 | if (typeof localStorage.sidekiqTimeInterval !== 'undefined') { 42 | sldr.value = localStorage.sidekiqTimeInterval; 43 | setSliderLabel(localStorage.sidekiqTimeInterval); 44 | } 45 | 46 | sldr.addEventListener("change", event => { 47 | localStorage.sidekiqTimeInterval = sldr.value; 48 | setSliderLabel(sldr.value); 49 | sldr.dispatchEvent( 50 | new CustomEvent("interval:update", { bubbles: true, detail: sldr.value }) 51 | ); 52 | }); 53 | 54 | sldr.addEventListener("mousemove", event => { 55 | setSliderLabel(sldr.value); 56 | }); 57 | }); 58 | -------------------------------------------------------------------------------- /web/locales/ar.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | ar: 3 | Actions: إجراءات 4 | AddToQueue: إضافة إلى الرتل 5 | AreYouSure: هل انت متأكد؟ 6 | AreYouSureDeleteJob: هل أنت متأكد من حذف الوظيفة؟ 7 | AreYouSureDeleteQueue: هل أنت متأكد من حذف الرتل %{queue}؟ 8 | Arguments: مدخلات 9 | BackToApp: العودة إلى التطبيق 10 | Busy: مشغول 11 | Class: نوع 12 | Connections: اتصالات 13 | CreatedAt: أنشئت في 14 | CurrentMessagesInQueue: الرسائل الحالية في الرتل %{queue} 15 | Dashboard: لوحة التحكم 16 | Dead: ميتة 17 | DeadJobs: وظائف ميتة 18 | Delete: حذف 19 | DeleteAll: حذف الكل 20 | Enqueued: في الرتل 21 | Error: خطأ 22 | ErrorBacktrace: تتبع الخطأ 23 | ErrorClass: نوع الخطأ 24 | ErrorMessage: رسالة الخطأ 25 | Extras: إضافات 26 | Failed: فشل 27 | Failures: فشل 28 | GoBack: إلى الخلف 29 | History: تاريخ 30 | Job: وظيفة 31 | Jobs: وظائف 32 | Kill: إبطال 33 | KillAll: إبطال الكل 34 | LastRetry: إعادة المحاولة الأخيرة 35 | Latency: زمن الانتظار 36 | LivePoll: استعلام مباشر 37 | MemoryUsage: استخدام الذاكرة 38 | Name: الاسم 39 | Namespace: مساحة الاسم 40 | NextRetry: إعادة المحاولة القادمة 41 | NoDeadJobsFound: لاتوجد وظائف ميتة 42 | NoRetriesFound: لاتوجد أي إعادة محاولة 43 | NoScheduledFound: لايوجد وظائف مجدولة 44 | NotYetEnqueued: لم تدخل الرتل بعد 45 | OneMonth: شهر 46 | OneWeek: أسبوع 47 | OriginallyFailed: فشل أصلا 48 | Pause: إيقاف مؤقت 49 | Paused: موقفة مؤقتاً 50 | PeakMemoryUsage: ذروة استخدام الذاكرة 51 | Plugins: الإضافات 52 | PollingInterval: الفاصل الزمني بين الاستعلامات 53 | Process: عملية 54 | Processed: تمت المعالجة 55 | Processes: عمليات 56 | Queue: رتل 57 | Queues: أرتال 58 | Quiet: هدوء 59 | QuietAll: هدوء الكل 60 | Realtime: الزمن الفعلي 61 | Retries: إعادة محاولة 62 | RetryAll: إعادة المحاولة للكل 63 | RetryCount: عدد مرات إعادة المحاولة 64 | RetryNow: إعادة المحاولة الآن 65 | Scheduled: مجدول 66 | ScheduledJobs: وظائف مجدولة 67 | ShowAll: عرض الكل 68 | SixMonths: ستة أشهر 69 | Size: حجم 70 | Started: بدأت 71 | Status: حالة 72 | Stop: إيقاف 73 | StopAll: إيقاف الكل 74 | StopPolling: إيقاف الاستعلامات 75 | TextDirection: 'rtl' 76 | Thread: نيسب 77 | Threads: نياسب 78 | ThreeMonths: ثلاثة أشهر 79 | Time: وقت 80 | Unpause: متابعة 81 | Uptime: زمن العمل 82 | Utilization: الاستخدام 83 | Version: إصدار 84 | When: متى 85 | Worker: عامل 86 | active: نشيط 87 | idle: خامل 88 | -------------------------------------------------------------------------------- /web/locales/cs.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | cs: 3 | Actions: Akce 4 | AddToQueue: Přidat do fronty 5 | AreYouSure: Jste si jisti? 6 | AreYouSureDeleteJob: Jste si jisti, že chcete odstranit tento úkol? 7 | AreYouSureDeleteQueue: Jste si jisti, že chcete odstranit frontu %{queue}? 8 | Arguments: Argumenty 9 | Busy: Zaneprázdněné 10 | Class: Třída 11 | Connections: Připojení 12 | CreatedAt: Vytvořeno 13 | CurrentMessagesInQueue: Aktuální úkoly ve frontě %{queue} 14 | Dashboard: Kontrolní panel 15 | Dead: Mrtvé 16 | DeadJobs: Mrtvé úkoly 17 | Delete: Odstranit 18 | DeleteAll: Odstranit vše 19 | Enqueued: Zařazené 20 | Error: Chyba 21 | ErrorBacktrace: Chybový výstup 22 | ErrorClass: Třída chyby 23 | ErrorMessage: Chybová zpráva 24 | Extras: Doplňky 25 | Failed: Nezdařené 26 | Failures: Selhání 27 | GoBack: ← Zpět 28 | History: Historie 29 | Job: Úkol 30 | Jobs: Úkoly 31 | Kill: Zabít 32 | LastRetry: Poslední opakování 33 | LivePoll: Průběžně aktualizovat 34 | MemoryUsage: Využití paměti 35 | Namespace: Jmenný prostor 36 | NextRetry: Další opakování 37 | NoDeadJobsFound: Nebyly nalezeny žádné mrtvé úkoly 38 | NoRetriesFound: Nebyla nalezena žádná opakování 39 | NoScheduledFound: Nebyly nalezeny žádné naplánované úkoly 40 | NotYetEnqueued: Ještě nezařazeno 41 | OneMonth: 1 měsíc 42 | OneWeek: 1 týden 43 | OriginallyFailed: Původně se nezdařilo 44 | Paused: Pozastavené 45 | PeakMemoryUsage: Nejvyšší využití paměti 46 | Plugins: Doplňky 47 | PollingInterval: Interval obnovení 48 | Processed: Zpracované 49 | Processes: Procesy 50 | Queue: Fronta 51 | Queues: Fronty 52 | Quiet: Ztišit 53 | QuietAll: Ztišit vše 54 | Realtime: V reálném čase 55 | Retries: Opakování 56 | RetryAll: Opakovat vše 57 | RetryCount: Počet opakování 58 | RetryNow: Opakovat teď 59 | Scheduled: Naplánované 60 | ScheduledJobs: Naplánované úkoly 61 | ShowAll: Ukázat všechny 62 | SixMonths: 6 měsíců 63 | Size: Velikost 64 | Started: Začal 65 | Status: Stav 66 | Stop: Zastavit 67 | StopAll: Zastavit vše 68 | StopPolling: Zastavit průběžnou aktualizaci 69 | Thread: Vlákno 70 | Threads: Vlákna 71 | ThreeMonths: 3 měsíce 72 | Time: Čas 73 | Uptime: Uptime (dny) 74 | Version: Verze 75 | When: Kdy 76 | Worker: Worker 77 | active: aktivní 78 | idle: nečinný 79 | -------------------------------------------------------------------------------- /web/locales/da.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | da: 3 | Actions: Handlinger 4 | AddToQueue: Tilføj til kø 5 | AreYouSure: Er du sikker? 6 | AreYouSureDeleteJob: Er du sikker på at du vil slette dette job? 7 | AreYouSureDeleteQueue: Er du sikker på at du vil slette %{queue} køen? 8 | Arguments: Argumenter 9 | AvgExecutionTime: Gennemsnitlig eksekveringstid 10 | Busy: Travl 11 | Class: Klasse 12 | Connections: Forbindelser 13 | CurrentMessagesInQueue: Nuværende beskeder i %{queue} 14 | Dashboard: Instrumentbræt 15 | Dead: Død 16 | DeadJobs: Døde jobs 17 | Delete: Slet 18 | DeleteAll: Slet alle 19 | Enqueued: I kø 20 | Error: Fejl 21 | ErrorBacktrace: Fejl backtrace 22 | ErrorClass: Fejlklasse 23 | ErrorMessage: Fejlbesked 24 | Extras: Ekstra 25 | Failed: Fejlet 26 | Failure: Fejl 27 | Failures: Fejl 28 | GoBack: ← Tilbage 29 | History: Historik 30 | Job: Job 31 | Jobs: Jobs 32 | Latency: Forsinkelse 33 | LastRetry: Sidste forsøg 34 | LivePoll: Live Poll 35 | MemoryUsage: RAM forbrug 36 | Name: Navn 37 | Namespace: Namespace 38 | NextRetry: Næste forsøg 39 | NoDeadJobsFound: Ingen døde jobs fundet 40 | NoJobMetricsFound: Ingen nylig job-metrics blev fundet 41 | NoRetriesFound: Ingen gen-forsøg var fundet 42 | NoScheduledFound: Ingen jobs i kø fundet 43 | OneMonth: 1 måned 44 | OneWeek: 1 uge 45 | OriginallyFailed: Oprindeligt fejlet 46 | PeakMemoryUsage: Peak RAM forbrug 47 | Processed: Processeret 48 | Processes: Processer 49 | Queue: Kø 50 | Queues: Køer 51 | Realtime: Realtid 52 | Retries: Forsøg 53 | RetryAll: Forsøg alle 54 | RetryCount: Antal forsøg 55 | RetryNow: Prøv igen nu 56 | Scheduled: Planlagt 57 | ScheduledJobs: Jobs i kø 58 | ShowAll: Vis alle 59 | SixMonths: 6 måneder 60 | Size: Størrelse 61 | Started: Startet 62 | Status: Status 63 | StopPolling: Stop Polling 64 | Success: Succes 65 | Thread: Tråd 66 | Threads: Tråde 67 | ThreeMonths: 3 måneder 68 | Time: Tid 69 | TotalExecutionTime: Total eksekveringstid 70 | Uptime: Oppetid (dage) 71 | Version: Version 72 | When: Når 73 | Worker: Arbejder 74 | active: aktiv 75 | idle: idle 76 | -------------------------------------------------------------------------------- /web/locales/de.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | de: 3 | Actions: Aktionen 4 | AddToQueue: In Warteschlange einreihen 5 | AreYouSure: Bist du sicher? 6 | AreYouSureDeleteJob: Möchtest du diesen Job wirklich löschen? 7 | AreYouSureDeleteQueue: Möchtest du %{queue} wirklich löschen? 8 | Arguments: Argumente 9 | BackToApp: Zurück zur Anwendung 10 | Busy: Beschäftigt 11 | Class: Klasse 12 | Connections: Verbindungen 13 | CreatedAt: Erstellt 14 | CurrentMessagesInQueue: Aktuelle Nachrichten in %{queue} 15 | Dashboard: Dashboard 16 | Dead: Tot 17 | DeadJobs: Gestorbene Jobs 18 | Delete: Löschen 19 | DeleteAll: Alle löschen 20 | Enqueued: In der Warteschlange 21 | Error: Fehler 22 | ErrorBacktrace: Fehlerbericht 23 | ErrorClass: Fehlerklasse 24 | ErrorMessage: Fehlernachricht 25 | Extras: Extras 26 | Failed: Fehlgeschlagen 27 | Failures: Ausfälle 28 | GoBack: ← Zurück 29 | History: Verlauf 30 | Job: Job 31 | Jobs: Jobs 32 | Kill: Vernichten 33 | KillAll: Alle vernichten 34 | LastRetry: Letzter Versuch 35 | Latency: Latenz 36 | LivePoll: Echtzeitabfrage 37 | MemoryUsage: RAM-Nutzung 38 | Namespace: Namensraum 39 | NextRetry: Nächster Versuch 40 | NoDeadJobsFound: Keine toten Jobs gefunden 41 | NoRetriesFound: Keine erneuten Versuche gefunden 42 | NoScheduledFound: Keine geplanten Jobs gefunden 43 | NotYetEnqueued: Noch nicht in der Warteschlange 44 | OneMonth: 1 Monat 45 | OneWeek: 1 Woche 46 | OriginallyFailed: Ursprünglich fehlgeschlagen 47 | Paused: Pausiert 48 | PeakMemoryUsage: Maximale RAM-Nutzung 49 | Plugins: Erweiterungen 50 | PollingInterval: Abfrageintervall 51 | Processed: Verarbeitet 52 | Processes: Prozesse 53 | Queue: Warteschlange 54 | Queues: Warteschlangen 55 | Quiet: Leise 56 | QuietAll: Alle leise 57 | Realtime: Echtzeit 58 | Retries: Versuche 59 | RetryAll: Alle erneut versuchen 60 | RetryCount: Anzahl der Versuche 61 | RetryNow: Jetzt erneut versuchen 62 | Scheduled: Geplant 63 | ScheduledJobs: Jobs in der Warteschlange 64 | ShowAll: Alle anzeigen 65 | SixMonths: 6 Monate 66 | Size: Größe 67 | Started: Gestartet 68 | Status: Status 69 | Stop: Stopp 70 | StopAll: Alle stoppen 71 | StopPolling: Abfrage stoppen 72 | Thread: Thread 73 | Threads: Threads 74 | ThreeMonths: 3 Monate 75 | Time: Zeit 76 | Uptime: Laufzeit 77 | Version: Version 78 | When: Wann 79 | Worker: Arbeiter 80 | active: aktiv 81 | idle: untätig 82 | -------------------------------------------------------------------------------- /web/locales/el.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | el: # <---- change this to your locale code 3 | Dashboard: Πίνακας Ελέγχου 4 | Status: Κατάσταση 5 | Time: Χρόνος 6 | Namespace: Namespace 7 | Realtime: Τρέχουσα Κατάσταση 8 | History: Ιστορικό 9 | Busy: Υπό επεξεργασία 10 | Utilization: Σε χρήση 11 | Processed: Επεξεργάστηκαν 12 | Failed: Απέτυχαν 13 | Scheduled: Προγραμματισμένα 14 | Retries: Επαναλήψεις 15 | Enqueued: Μπήκαν στην στοίβα 16 | Worker: Εργάτης 17 | LivePoll: Τρέχουσα Κατάσταση 18 | StopPolling: Διακοπή Τρέχουσας Κατάστασης 19 | Queue: Στοίβα 20 | Class: Κλάση 21 | Job: Εργασία 22 | Arguments: Ορίσματα 23 | Extras: Extras 24 | Started: Ξεκίνησε 25 | ShowAll: Εμφάνιση Όλων 26 | Enqueued: Μπήκαν στην στοίβα 27 | AddToQueue: Προσθήκη στην στοίβα 28 | AreYouSureDeleteJob: Θέλετε να διαγράψετε αυτή την εργασία; 29 | AreYouSureDeleteQueue: Θέλετε να διαγράψετε την στοίβα %{queue}; Αυτό θα διαγράψει όλες τις εργασίες εντός της στοίβας, θα εμφανιστεί ξανά εάν προωθήσετε περισσότερες εργασίες σε αυτήν στο μέλλον. 30 | Queues: Στοίβες 31 | Size: Μέγεθος 32 | Actions: Ενέργειες 33 | NextRetry: Επόμενη Προσπάθεια 34 | RetryCount: Αριθμός Προσπαθειών 35 | RetryNow: Επανάληψη Τώρα 36 | # Kill: Kill 37 | LastRetry: Τελευταία Προσπάθεια 38 | OriginallyFailed: Αρχικές Αποτυχίες 39 | AreYouSure: Είστε σίγουρος; 40 | DeleteAll: Διαγραφή Όλων 41 | RetryAll: Επανάληψη Όλων 42 | # KillAll: Kill All 43 | NoRetriesFound: Δεν βρέθηκαν εργασίες προς επαναλήψη 44 | ErrorBacktrace: Backtrace Σφάλματος 45 | GoBack: ← Πίσω 46 | NoScheduledFound: Δεν βρέθηκαν προγραμματισμένες εργασίες 47 | When: Πότε 48 | ScheduledJobs: Προγραμματισμένες Εργασίες 49 | idle: αδρανές 50 | active: ενεργό 51 | Version: Έκδοση 52 | Connections: Συνδέσεις 53 | MemoryUsage: Χρήση Μνήμης 54 | PeakMemoryUsage: Μέγιστη Χρήση Μνήμης 55 | Uptime: Ημέρες Λειτουργίας 56 | OneWeek: 1 εβδομάδα 57 | OneMonth: 1 μήνας 58 | ThreeMonths: 3 μήνες 59 | SixMonths: 6 μήνες 60 | Failures: Αποτυχίες 61 | DeadJobs: Αδρανείς Εργασίες 62 | NoDeadJobsFound: Δεν βρέθηκαν αδρανείς εργασίες 63 | Dead: Αδρανείς 64 | Process: Διεργασία 65 | Processes: Διεργασίες 66 | Name: Όνομα 67 | Thread: Νήμα 68 | Threads: Νήματα 69 | Jobs: Εργασίες 70 | Paused: Σε παύση 71 | Stop: Διακοπή 72 | Quiet: Σίγαση 73 | StopAll: Διακοπή Όλων 74 | QuietAll: Σίγαση Όλων 75 | PollingInterval: Συχνότητα Ανανέωσης 76 | Plugins: Πρόσθετα 77 | NotYetEnqueued: Δεν προστέθηκε στην στοίβα ακόμη 78 | CreatedAt: Δημιουργήθηκε στις 79 | BackToApp: Πίσω στην Εφαρμογή 80 | Latency: Καθυστέρηση 81 | Pause: Παύση 82 | Unpause: Κατάργηση Παύσης 83 | Metrics: Μετρήσεις 84 | NoDataFound: Δεν βρέθηκαν δεδομένα 85 | TotalExecutionTime: Συνολικός Χρόνος Εκτέλεσης 86 | AvgExecutionTime: Μέσος Χρόνος Εκτέλεσης 87 | # Context: Context 88 | -------------------------------------------------------------------------------- /web/locales/es.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | es: 3 | Actions: Acciones 4 | AddToQueue: Añadir a la cola 5 | AreYouSure: ¿Estás seguro? 6 | AreYouSureDeleteJob: ¿Estás seguro de eliminar este trabajo? 7 | AreYouSureDeleteQueue: ¿Estás seguro de eliminar la cola %{queue}? 8 | Arguments: Argumentos 9 | BackToApp: Volver a la Aplicación 10 | Busy: Ocupado 11 | Class: Clase 12 | Connections: Conexiones 13 | CreatedAt: Creado en 14 | CurrentMessagesInQueue: Mensajes actualmente en %{queue} 15 | Dashboard: Panel de Control 16 | Dead: Muerto 17 | DeadJobs: Trabajos muertos 18 | Delete: Eliminar 19 | DeleteAll: Borrar Todo 20 | Enqueued: En Cola 21 | Error: Error 22 | ErrorBacktrace: Trazado del Error 23 | ErrorClass: Clase del Error 24 | ErrorMessage: Mensaje de Error 25 | Extras: Extras 26 | Failed: Fallidas 27 | Failures: Fallas 28 | GoBack: ← Regresar 29 | History: Historial 30 | Job: Trabajo 31 | Jobs: Trabajos 32 | Kill: Matar 33 | KillAll: Matar Todo 34 | LastRetry: Último Reintento 35 | Latency: Latencia 36 | LivePoll: Sondeo en Vivo 37 | MemoryUsage: Uso de Memoria 38 | Name: Nombre 39 | Namespace: Espacio de Nombre 40 | NextRetry: Siguiente Intento 41 | NoDeadJobsFound: No hay trabajos muertos 42 | NoRetriesFound: No se encontraron reintentos 43 | NoScheduledFound: No se encontraron trabajos pendientes 44 | NotYetEnqueued: Aún no en cola 45 | OneMonth: 1 mes 46 | OneWeek: 1 semana 47 | OriginallyFailed: Falló Originalmente 48 | Pause: Pausar 49 | Paused: Pausado 50 | PeakMemoryUsage: Máximo Uso de Memoria 51 | Plugins: Plugins 52 | PollingInterval: Intervalo de Sondeo 53 | Process: Proceso 54 | Processed: Procesadas 55 | Processes: Procesos 56 | Queue: Cola 57 | Queues: Colas 58 | Quiet: Silenciar 59 | QuietAll: Silenciar Todo 60 | Realtime: Tiempo Real 61 | Retries: Reintentos 62 | RetryAll: Reintentar Todo 63 | RetryCount: Numero de Reintentos 64 | RetryNow: Reintentar Ahora 65 | Scheduled: Programadas 66 | ScheduledJobs: Trabajos programados 67 | ShowAll: Mostrar Todo 68 | SixMonths: 6 meses 69 | Size: Tamaño 70 | Started: Hora de Inicio 71 | Status: Estatus 72 | Stop: Detener 73 | StopAll: Detener Todo 74 | StopPolling: Detener Sondeo 75 | Thread: Hilo 76 | Threads: Hilos 77 | ThreeMonths: 3 meses 78 | Time: Tiempo 79 | Unpause: Reanudar 80 | Uptime: Tiempo de Funcionamiento (días) 81 | Utilization: Utilización 82 | Version: Versión 83 | When: Cuando 84 | Worker: Trabajador 85 | active: activo 86 | idle: inactivo 87 | -------------------------------------------------------------------------------- /web/locales/fa.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | fa: 3 | Actions: اعمال 4 | AddToQueue: افزودن به صف 5 | AreYouSure: آیا مطمعن هستید? 6 | AreYouSureDeleteJob: آیا شما مطمعن هستید از حذف این کار ؟ 7 | AreYouSureDeleteQueue: ایا شما مطمعنید از حذف %{queue} ? 8 | Arguments: آرگومنت 9 | BackToApp: برگشت به برنامه 10 | Busy: مشغول 11 | Class: کلاس 12 | Connections: ارتباطات 13 | CreatedAt: ساخته شده در 14 | CurrentMessagesInQueue: کار فعلی در %{queue} 15 | Dashboard: داشبورد 16 | Dead: مرده 17 | DeadJobs: کار مرده 18 | Delete: حذف 19 | DeleteAll: حذف همه 20 | Enqueued: صف بندی نشدند 21 | Error: خطا 22 | ErrorBacktrace: خطای معکوس 23 | ErrorClass: خطا کلاس 24 | ErrorMessage: پیغام خطا 25 | Extras: اضافی 26 | Failed: ناموفق 27 | Failures: شکست ها 28 | GoBack: ← برگشت 29 | History: تاریخچه 30 | Job: کار 31 | Jobs: کار ها 32 | Kill: کشتن 33 | LastRetry: آخرین تلاش 34 | LivePoll: Live Poll 35 | MemoryUsage: حافظه استفاده شده 36 | Namespace: فضای نام 37 | NextRetry: بار دیگر تلاش کنید 38 | NoDeadJobsFound: کار مرده ای یافت نشد 39 | NoRetriesFound: هیچ تلاش پیدا نشد 40 | NoScheduledFound: هیچ کار برنامه ریزی شده ای یافت نشد 41 | NotYetEnqueued: بدون صف بندی 42 | OneMonth: ۱ ماه 43 | OneWeek: ۱ هفته 44 | OriginallyFailed: Originally Failed 45 | Paused: مکث 46 | PeakMemoryUsage: اوج حافظه استفاده شده 47 | Plugins: پلاگین ها 48 | PollingInterval: Polling interval 49 | Processed: پردازش شده 50 | Processes: پردازش ها 51 | Queue: صف 52 | Queues: صف ها 53 | Quiet: خروج 54 | QuietAll: خروج همه 55 | Realtime: زنده 56 | Retries: تکرار 57 | RetryAll: تلاش مجدد برای همه 58 | RetryCount: تعداد تلاش ها 59 | RetryNow: تلاش مجدد 60 | Scheduled: زمان بندی 61 | ScheduledJobs: کار برنامه ریزی شده 62 | ShowAll: نمایش همه 63 | SixMonths: ۶ ماه 64 | Size: سایز 65 | Started: شروع شده 66 | Status: اعلان 67 | Stop: توقف 68 | StopAll: توقف همه 69 | StopPolling: Stop Polling 70 | TextDirection: 'rtl' 71 | Thread: رشته 72 | Threads: رشته ها 73 | ThreeMonths: ۳ ماه 74 | Time: رمان 75 | Uptime: آپ تایم (روز) 76 | Version: ورژن 77 | When: وقتی که 78 | Worker: کارگزار 79 | active: فعال 80 | idle: بیهودی 81 | -------------------------------------------------------------------------------- /web/locales/he.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | he: 3 | Actions: פעולות 4 | AddToQueue: הוסף לתור 5 | AreYouSure: אתם בטוחים? 6 | AreYouSureDeleteJob: האם אתם בטוחים שברצונכם למחוק את העבודה הזאת? 7 | AreYouSureDeleteQueue: האם אתם בטוחים שברצונכם למחוק את התור %{queue}? 8 | Arguments: ארגומנטים 9 | BackToApp: חזרה לאפליקציה 10 | Busy: עסוקים 11 | Class: מחלקה 12 | Connections: חיבורים 13 | CreatedAt: נוצר ב 14 | CurrentMessagesInQueue: עבודות נוכחיות בתור %{queue} 15 | Dashboard: לוח מחוונים 16 | Dead: מתים 17 | DeadJobs: עבודות מתות 18 | Delete: מחק 19 | DeleteAll: מחק הכל 20 | Enqueued: בתור 21 | Error: שגיאה 22 | ErrorBacktrace: מעקב לאחור של השגיאה 23 | ErrorClass: סוג השגיאה 24 | ErrorMessage: הודעת השגיאה 25 | Extras: תוספות 26 | Failed: נכשלו 27 | Failures: כשלונות 28 | GoBack: ← אחורה 29 | History: היסטוריה 30 | Job: עבודה 31 | Jobs: עבודות 32 | Kill: הרוג 33 | LastRetry: ניסיון חוזר אחרון 34 | LivePoll: תשאול חי 35 | MemoryUsage: שימוש בזיכרון 36 | Namespace: מרחב שם 37 | NextRetry: ניסיון חוזר הבא 38 | NoDeadJobsFound: לא נמצאו עבודות מתות 39 | NoRetriesFound: לא נמצאו נסיונות חוזרים 40 | NoScheduledFound: לא נמצאו עבודות מתוכננות 41 | NotYetEnqueued: עוד לא בתור 42 | OneMonth: חודש 1 43 | OneWeek: שבוע 1 44 | OriginallyFailed: נכשל בניסיון הראשון 45 | Paused: הופסקו 46 | PeakMemoryUsage: שיא השימוש בזיכרון 47 | Plugins: תוספים 48 | PollingInterval: מרווח זמן בין תשאולים 49 | Processed: עובדו 50 | Processes: תהליכים 51 | Queue: תור 52 | Queues: תורים 53 | Quiet: שקט 54 | QuietAll: השקט את כולם 55 | Realtime: זמן אמת 56 | Retries: נסיונות חוזרים 57 | RetryAll: נסה שוב את הכל 58 | RetryCount: מספר נסיונות חוזרים 59 | RetryNow: נסה שוב עכשיו 60 | Scheduled: מתוכננים 61 | ScheduledJobs: עבודות מתוכננות 62 | ShowAll: הצג את הכל 63 | SixMonths: 6 חדשים 64 | Size: אורך 65 | Started: הותחלו 66 | Status: מצב 67 | Stop: עצור 68 | StopAll: עצור הכל 69 | StopPolling: עצור תשאול 70 | TextDirection: 'rtl' 71 | Thread: חוט 72 | Threads: חוטים 73 | ThreeMonths: 3 חדשים 74 | Time: שעה 75 | Uptime: זמן פעילות (ימים) 76 | Version: גירסה 77 | When: מתי 78 | Worker: עובד 79 | active: פעיל 80 | idle: במנוחה 81 | -------------------------------------------------------------------------------- /web/locales/hi.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | hi: 3 | Actions: कार्रवाई 4 | AddToQueue: कतार मे जोड़ें 5 | AreYouSure: क्या आपको यकीन है? 6 | AreYouSureDeleteJob: क्या आप इस कार्य को हटाना चाहते है? 7 | AreYouSureDeleteQueue: क्या आप %{queue} कतार को हटाना चाहते है? 8 | Arguments: अर्गुमेन्ट्स् 9 | Busy: व्यस्थ 10 | Class: क्लास 11 | Connections: कनेक्श्न 12 | CurrentMessagesInQueue: %{queue} कतार मे वर्तमान कार्य 13 | Dashboard: डैशबोर्ड 14 | Dead: निष्प्राण 15 | DeadJobs: निष्प्राण कार्य 16 | Delete: हटाओ 17 | DeleteAll: सब हटाओ 18 | Enqueued: कतारबद्ध 19 | Error: एरर 20 | ErrorBacktrace: एरर बैकट्रेस 21 | ErrorClass: एरर क्लास 22 | ErrorMessage: एरर संदेश 23 | Extras: अतिरिक्त 24 | Failed: असफल 25 | Failures: असफलता 26 | GoBack: ← पीछे 27 | History: वृत्तान्त 28 | Job: कार्य 29 | Jobs: कार्य 30 | Kill: नष्ट करे 31 | LastRetry: अंतिम पुन:प्रयास 32 | LivePoll: लाईव सर्वेक्षण 33 | MemoryUsage: मेमरी उपयोग 34 | Namespace: नामस्थान 35 | NextRetry: अगला पुन:प्रयास 36 | NoDeadJobsFound: कोई निष्प्राण कार्य नही पाए गए 37 | NoRetriesFound: कोई पुनर्प्रयास नही पाए गए 38 | NoScheduledFound: कोई परिगणित कार्य नही पाए गए 39 | OneMonth: १ महीना 40 | OneWeek: १ सप्ताह 41 | OriginallyFailed: पहिले से विफल 42 | Paused: थमे हुए 43 | PeakMemoryUsage: अधिकतम मेमरी उपयोग 44 | PollingInterval: सर्वेक्षण अंतराल 45 | Processed: कार्रवाई कृत 46 | Processes: प्रोसेसेस् 47 | Queue: कतार 48 | Queues: कतारे 49 | Quiet: शांत करो 50 | QuietAll: सब शांत करो 51 | Realtime: रिअल टाईम 52 | Retries: पुनर्प्रयास 53 | RetryAll: सब पुन:प्रयास करे 54 | RetryCount: पुन:प्रयास संख्या 55 | RetryNow: पुन:प्रयास करे 56 | Scheduled: परिगणित 57 | ScheduledJobs: परिगणित कार्य 58 | ShowAll: सब दिखाएं 59 | SixMonths: ६ महीने 60 | Size: आकार 61 | Started: शुरु हुआ 62 | Status: स्थिती 63 | Stop: रोको 64 | StopAll: सब रोको 65 | StopPolling: सर्वेक्षण रोको 66 | Thread: थ्रेड 67 | Threads: थ्रेड्स् 68 | ThreeMonths: ३ महीने 69 | Time: समय 70 | Uptime: उपरिकाल (दिवस) 71 | Version: वर्जन 72 | When: कब 73 | Worker: वर्कर 74 | active: सक्रिय 75 | idle: निष्क्रिय 76 | -------------------------------------------------------------------------------- /web/locales/it.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | it: 3 | Actions: Azioni 4 | AddToQueue: Aggiungi alla coda 5 | AreYouSure: Sei sicuro? 6 | AreYouSureDeleteJob: Sei sicuro di voler cancellare questo lavoro? 7 | AreYouSureDeleteQueue: Sei sicuro di voler cancellare la coda %{queue}? 8 | Arguments: Argomenti 9 | Busy: Occupato 10 | Class: Classe 11 | Connections: Connessioni 12 | CurrentMessagesInQueue: Messaggi in %{queue} 13 | Dashboard: Dashboard 14 | Dead: Arrestato 15 | DeadJobs: Lavori arrestati 16 | Delete: Cancella 17 | DeleteAll: Cancella tutti 18 | Enqueued: In coda 19 | Error: Errore 20 | ErrorBacktrace: Backtrace dell'errore 21 | ErrorClass: Classe dell'errore 22 | ErrorMessage: Messaggio di errore 23 | Extras: Extra 24 | Failed: Fallito 25 | Failures: Fallimenti 26 | GoBack: ← Indietro 27 | History: Storia 28 | Job: Lavoro 29 | Jobs: Lavori 30 | Kill: Uccidere 31 | LastRetry: Ultimo tentativo 32 | LivePoll: Live poll 33 | MemoryUsage: Memoria utilizzata 34 | Namespace: Namespace 35 | NextRetry: Prossimo tentativo 36 | NoDeadJobsFound: Non ci sono lavori arrestati 37 | NoRetriesFound: Non sono stati trovati nuovi tentativi 38 | NoScheduledFound: Non ci sono lavori pianificati 39 | OneMonth: 1 mese 40 | OneWeek: 1 settimana 41 | OriginallyFailed: Primo fallimento 42 | PeakMemoryUsage: Memoria utilizzata (max.) 43 | Processed: Processato 44 | Processes: Processi 45 | Queue: Coda 46 | Queues: Code 47 | Realtime: Tempo reale 48 | Retries: Nuovi tentativi 49 | RetryAll: Riprova tutti 50 | RetryCount: Totale tentativi 51 | RetryNow: Riprova 52 | Scheduled: Pianificato 53 | ScheduledJobs: Lavori pianificati 54 | ShowAll: Mostra tutti 55 | SixMonths: 6 mesi 56 | Size: Dimensione 57 | Started: Iniziato 58 | Status: Stato 59 | StopPolling: Ferma il polling 60 | Thread: Thread 61 | Threads: Thread 62 | ThreeMonths: 3 mesi 63 | Time: Ora 64 | Uptime: Uptime (giorni) 65 | Version: Versione 66 | When: Quando 67 | Worker: Lavoratore 68 | active: attivo 69 | idle: inattivo 70 | -------------------------------------------------------------------------------- /web/locales/ja.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | ja: 3 | Actions: アクション 4 | AddToQueue: キューに追加 5 | AreYouSure: よろしいですか? 6 | AreYouSureDeleteJob: このジョブを削除しますか? 7 | AreYouSureDeleteQueue: この %{queue} キューを削除しますか? 8 | Arguments: 引数 9 | BackToApp: アプリに戻る 10 | Busy: 実行中 11 | Class: クラス 12 | Connections: 接続 13 | CreatedAt: 作成日時 14 | CurrentMessagesInQueue: %{queue}に メッセージがあります 15 | Dashboard: ダッシュボード 16 | Dead: デッド 17 | DeadJobs: デッドジョブ 18 | Delete: 削除 19 | DeleteAll: 全て削除 20 | Deploy: デプロイ 21 | Enqueued: 待機状態 22 | Error: エラー 23 | ErrorBacktrace: エラーバックトレース 24 | ErrorClass: エラークラス 25 | ErrorMessage: エラーメッセージ 26 | ExecutionTime: 実行時間 27 | Extras: エクストラ 28 | Failed: 失敗 29 | Failures: 失敗 30 | Failure: 失敗 31 | GoBack: ← 戻る 32 | History: 履歴 33 | Job: ジョブ 34 | Jobs: ジョブ 35 | Kill: 強制終了 36 | KillAll: 全て強制終了 37 | LastRetry: 再試行履歴 38 | Latency: レイテンシ 39 | LivePoll: ポーリング開始 40 | MemoryUsage: メモリー使用量 41 | Name: 名前 42 | Namespace: ネームスペース 43 | NextRetry: 再試行 44 | NoDeadJobsFound: デッドジョブはありません 45 | NoRetriesFound: 再試行するジョブはありません 46 | NoScheduledFound: 予定されたジョブはありません 47 | NotYetEnqueued: キューに入っていません 48 | OneMonth: 1 ヶ月 49 | OneWeek: 1 週 50 | OriginallyFailed: 失敗 51 | Pause: 一時停止 52 | Paused: 一時停止中 53 | PeakMemoryUsage: 最大メモリー使用量 54 | Plugins: プラグイン 55 | PollingInterval: ポーリング間隔 56 | Process: プロセス 57 | Processed: 完了 58 | Processes: プロセス 59 | Queue: キュー 60 | Queues: キュー 61 | Quiet: 処理終了 62 | QuietAll: すべて処理終了 63 | Realtime: リアルタイム 64 | Retries: 再試行 65 | RetryAll: 全て再試行 66 | RetryCount: 再試行 67 | RetryNow: 今すぐ再試行 68 | Scheduled: 予定 69 | ScheduledJobs: 予定されたジョブ 70 | Seconds: 秒 71 | ShowAll: 全て見せる 72 | SixMonths: 6 ヶ月 73 | Size: サイズ 74 | Started: 開始 75 | Status: 状態 76 | Stop: 停止 77 | StopAll: すべて停止 78 | StopPolling: ポーリング停止 79 | Success: 成功 80 | Thread: スレッド 81 | Threads: スレッド 82 | ThreeMonths: 3 ヶ月 83 | Time: 時間 84 | Unpause: 一時停止を解除 85 | Metrics: メトリクス 86 | NoDataFound: データが見つかりませんでした 87 | TotalExecutionTime: 合計実行時間 88 | AvgExecutionTime: 平均実行時間 89 | Context: コンテキスト 90 | Bucket: バケット 91 | NoJobMetricsFound: 直近のジョブメトリクスが見つかりませんでした 92 | -------------------------------------------------------------------------------- /web/locales/ko.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | ko: 3 | Actions: 동작 4 | AddToQueue: 큐 추가 5 | AreYouSure: 정말입니까? 6 | AreYouSureDeleteJob: 이 작업을 삭제하시겠습니까? 7 | AreYouSureDeleteQueue: 이 %{queue} 큐를 삭제하시겠습니까? 8 | Arguments: 인자 9 | Batches: 배치 10 | Busy: 작동 11 | Class: 클래스 12 | Connections: 커넥션 13 | CurrentMessagesInQueue: %{queue}에 대기 중인 메시지 14 | Dashboard: 대시보드 15 | Dead: 죽음 16 | DeadJobs: 죽은 작업 17 | Delete: 삭제 18 | DeleteAll: 모두 삭제 19 | Enqueued: 대기 중 20 | Error: 에러 21 | ErrorBacktrace: 에러 Backtrace 22 | ErrorClass: 에러 클래스 23 | ErrorMessage: 에러 메시지 24 | Failed: 실패 25 | Failures: 실패 26 | GoBack: ← 뒤로 27 | History: 히스토리 28 | Job: 작업 29 | Jobs: 작업 30 | LastRetry: 최근 재시도 31 | LivePoll: 폴링 시작 32 | MemoryUsage: 메모리 사용량 33 | Namespace: 네임스페이스 34 | NextRetry: 다음 재시도 35 | NoDeadJobsFound: 죽은 작업이 없습니다 36 | NoRetriesFound: 재시도 내역이 없습니다 37 | NoScheduledFound: 예약된 작업이 없습니다 38 | OneMonth: 1 달 39 | OneWeek: 1 주 40 | OriginallyFailed: 실패 41 | PeakMemoryUsage: 최대 메모리 사용량 42 | Processed: 처리완료 43 | Processes: 프로세스 44 | Queue: 큐 45 | Queues: 큐 46 | Realtime: 실시간 47 | Retries: 재시도 48 | RetryAll: 모두 재시도 49 | RetryCount: 재시도 횟수 50 | RetryNow: 지금 재시도 51 | Scheduled: 예약 52 | ScheduledJobs: 예약된 작업 53 | ShowAll: 모두 보기 54 | SixMonths: 6 달 55 | Size: 크기 56 | Started: 시작 57 | Status: 상태 58 | StopPolling: 폴링 중단 59 | Thread: 스레드 60 | Threads: 스레드 61 | ThreeMonths: 3 달 62 | Time: 시간 63 | Uptime: 업타임 (일) 64 | Version: 버전 65 | When: 언제 66 | Worker: 워커 67 | active: 동작 중 68 | idle: 대기 중 69 | -------------------------------------------------------------------------------- /web/locales/lt.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | lt: 3 | Actions: Veiksmai 4 | AddToQueue: Pridėti į eilę 5 | AreYouSure: Ar jūs įsitikinę? 6 | AreYouSureDeleteJob: Ar tikrai norite pašalinti šį darbą? 7 | AreYouSureDeleteQueue: Ar tikrai norite pašalinti šią eilę %{queue}? 8 | Arguments: Parametrai 9 | BackToApp: Atgal į Aplikaciją 10 | Busy: Užimti 11 | Class: Klasė 12 | Connections: Ryšiai 13 | CreatedAt: Sukurta 14 | CurrentMessagesInQueue: Esami darbai eilėje %{queue} 15 | Dashboard: Valdymo skydas 16 | Dead: Negyvi 17 | DeadJobs: Negyvi Darbai 18 | Delete: Pašalinti 19 | DeleteAll: Pašalinti Visus 20 | Enqueued: Eilėje 21 | Error: Klaida 22 | ErrorBacktrace: Klaidos Pėdsakai 23 | ErrorClass: Klaidos Klasė 24 | ErrorMessage: Klaidos Žinutė 25 | Extras: Papildomi 26 | Failed: Nepavykę 27 | Failures: Nesėkmingi vykdymai 28 | GoBack: ← Atgal 29 | History: Istorija 30 | Job: Darbas 31 | Jobs: Darbai 32 | Kill: Priverstinai Nutraukti 33 | KillAll: Priverstinai Nutraukti Visus 34 | LastRetry: Paskutinis Kartojimas 35 | Latency: Vėlavimas 36 | LivePoll: Užklausti gyvai 37 | MemoryUsage: Atminties Vartojimas 38 | Namespace: Vardų erdvė 39 | NextRetry: Sekantis Kartojimas 40 | NoDeadJobsFound: Negyvų darbų nerasta 41 | NoRetriesFound: Nerasta kartojimų 42 | NoScheduledFound: Planuojamų darbų nerasta 43 | NotYetEnqueued: Dar neįtraukti į eilę 44 | OneMonth: 1 mėnuo 45 | OneWeek: 1 savaitė 46 | OriginallyFailed: Iš pradžių Nepavykę 47 | Pause: Pristabdyti 48 | Paused: Pristabdytas 49 | PeakMemoryUsage: Atminties Vartojimo Pikas 50 | Plugins: Įskiepiai 51 | PollingInterval: Užklausimų intervalas 52 | Processed: Įvykdyti 53 | Processes: Procesai 54 | Queue: Eilė 55 | Queues: Eilės 56 | Quiet: Nutildyti 57 | QuietAll: Nutildyti Visus 58 | Realtime: Realiu laiku 59 | Retries: Kartojami 60 | RetryAll: Kartoti Visus 61 | RetryCount: Kartojimų Skaičius 62 | RetryNow: Kartoti Dabar 63 | Scheduled: Suplanuoti 64 | ScheduledJobs: Planuojami Darbai 65 | ShowAll: Rodyti Visus 66 | SixMonths: 6 mėnesiai 67 | Size: Dydis 68 | Started: Pradėti 69 | Status: Būsena 70 | Stop: Sustabdyti 71 | StopAll: Sustabdyti Visus 72 | StopPolling: Stabdyti užklausas 73 | Thread: Gija 74 | Threads: Gijos 75 | ThreeMonths: 3 mėnesiai 76 | Time: Laikas 77 | Unpause: Pratęsti 78 | Uptime: Gyvavimo laikas (dienomis) 79 | Version: Versija 80 | When: Kada 81 | Worker: Darbuotojas 82 | active: aktyvus 83 | idle: neveiksnus 84 | -------------------------------------------------------------------------------- /web/locales/nb.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | nb: 3 | Actions: Handlinger 4 | AddToQueue: Legg til i kø 5 | AreYouSure: Er du sikker? 6 | AreYouSureDeleteJob: Er du sikker på at du vil slette denne jobben? 7 | AreYouSureDeleteQueue: Er du sikker på at du vil slette køen %{queue}? 8 | Arguments: Argumenter 9 | Busy: Opptatt 10 | Class: Klasse 11 | Connections: Tilkoblinger 12 | CurrentMessagesInQueue: Nåværende melding i %{queue} 13 | Dashboard: Oversikt 14 | Dead: Død 15 | DeadJobs: Døde jobber 16 | Delete: Slett 17 | DeleteAll: Slett alle 18 | Enqueued: I kø 19 | Error: Feil 20 | ErrorBacktrace: Feilbakgrunn 21 | ErrorClass: Feilklasse 22 | ErrorMessage: Feilmelding 23 | Extras: Ekstra 24 | Failed: Mislykket 25 | Failures: Feil 26 | GoBack: ← Tilbake 27 | History: Historikk 28 | Job: Jobb 29 | Jobs: Jobber 30 | Kill: Kill 31 | LastRetry: Forrige forsøk 32 | LivePoll: Automatisk oppdatering 33 | MemoryUsage: Minneforbruk 34 | Namespace: Navnerom 35 | NextRetry: Neste forsøk 36 | NoDeadJobsFound: Ingen døde jobber funnet 37 | NoRetriesFound: Ingen forsøk funnet 38 | NoScheduledFound: Ingen planlagte jobber funnet 39 | NotYetEnqueued: Ikke køet enda 40 | OneMonth: 1 måned 41 | OneWeek: 1 uke 42 | OriginallyFailed: Feilet opprinnelig 43 | Paused: Pauset 44 | PeakMemoryUsage: Høyeste minneforbruk 45 | Plugins: Innstikk 46 | PollingInterval: Oppdateringsintervall 47 | Processed: Prosessert 48 | Processes: Prosesser 49 | Queue: Kø 50 | Queues: Køer 51 | Quiet: Demp 52 | QuietAll: Demp alle 53 | Realtime: Sanntid 54 | Retries: Forsøk 55 | RetryAll: Forsøk alle på nytt 56 | RetryCount: Antall forsøk 57 | RetryNow: Forsøk igjen nå 58 | Scheduled: Planlagt 59 | ScheduledJobs: Planlagte jobber 60 | ShowAll: Vis alle 61 | SixMonths: 6 måneder 62 | Size: Størrelse 63 | Started: Startet 64 | Status: Status 65 | Stop: Stopp 66 | StopAll: Stopp alle 67 | StopPolling: Stopp automatisk oppdatering 68 | Thread: Tråd 69 | Threads: Tråder 70 | ThreeMonths: 3 måneder 71 | Time: Tid 72 | Uptime: Oppetid (dager) 73 | Version: Versjon 74 | When: Når 75 | Worker: Arbeider 76 | active: aktiv 77 | idle: uvirksom 78 | -------------------------------------------------------------------------------- /web/locales/nl.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | nl: 3 | Actions: Acties 4 | AddToQueue: Toevoegen aan wachtrij 5 | AreYouSure: Weet u het zeker? 6 | AreYouSureDeleteJob: Weet u zeker dat u deze taak wilt verwijderen? 7 | AreYouSureDeleteQueue: Weet u zeker dat u wachtrij %{queue} wilt verwijderen? 8 | Arguments: Argumenten 9 | Busy: Bezet 10 | Class: Klasse 11 | Connections: Verbindingen 12 | CurrentMessagesInQueue: Aantal berichten in %{queue} 13 | Dashboard: Dashboard 14 | Dead: Overleden 15 | DeadJobs: Overleden taken 16 | Delete: Verwijderen 17 | DeleteAll: Alle verwijderen 18 | Enqueued: In de wachtrij 19 | Error: Fout 20 | ErrorBacktrace: Fout Backtrace 21 | ErrorClass: Fout Klasse 22 | ErrorMessage: Foutmelding 23 | Extras: Extra's 24 | Failed: Mislukt 25 | Failures: Mislukt 26 | GoBack: ← Terug 27 | History: Geschiedenis 28 | Job: Taak 29 | Jobs: Taken 30 | LastRetry: Laatste poging 31 | LivePoll: Live bijwerken 32 | MemoryUsage: Geheugengebruik 33 | Namespace: Namespace 34 | NextRetry: Volgende opnieuw proberen 35 | NoDeadJobsFound: Geen overleden taken gevonden 36 | NoRetriesFound: Geen opnieuw te proberen taken gevonden 37 | NoScheduledFound: Geen geplande taken gevonden 38 | OneMonth: 1 maand 39 | OneWeek: 1 week 40 | OriginallyFailed: Oorspronkelijk mislukt 41 | PeakMemoryUsage: Piek geheugengebruik 42 | Processed: Verwerkt 43 | Processes: Processen 44 | Queue: Wachtrij 45 | Queues: Wachtrijen 46 | Realtime: Real-time 47 | Retries: Opnieuw proberen 48 | RetryAll: Alle opnieuw proberen 49 | RetryCount: Aantal opnieuw geprobeerd 50 | RetryNow: Nu opnieuw proberen 51 | Scheduled: Gepland 52 | ScheduledJobs: Geplande taken 53 | ShowAll: Toon alle 54 | SixMonths: 6 maanden 55 | Size: Grootte 56 | Started: Gestart 57 | Status: Status 58 | StopPolling: Stop live bijwerken 59 | Thread: Thread 60 | Threads: Threads 61 | ThreeMonths: 3 maanden 62 | Time: Tijd 63 | Uptime: Looptijd (dagen) 64 | Version: Versie 65 | When: Wanneer 66 | Worker: Werker 67 | active: actief 68 | idle: inactief 69 | -------------------------------------------------------------------------------- /web/locales/pl.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | pl: 3 | Actions: Akcje 4 | AddToQueue: dodaj do kolejki 5 | AreYouSure: Na pewno? 6 | AreYouSureDeleteJob: Czy na pewno usunąć to zadanie? 7 | AreYouSureDeleteQueue: Czy na pewno usunąć kolejkę %{queue}? 8 | Arguments: Argumenty 9 | Busy: Zajęte 10 | Class: Klasa 11 | Connections: Połączenia 12 | CurrentMessagesInQueue: Aktualne wiadomości w kolejce %{queue} 13 | Dashboard: Kokpit 14 | Delete: Usuń 15 | DeleteAll: Usuń wszystko 16 | Enqueued: Zakolejkowane 17 | Error: Błąd 18 | ErrorBacktrace: Wyjście błędu 19 | ErrorClass: Klasa błędu 20 | ErrorMessage: Wiadomosć błędu 21 | Failed: Nieudane 22 | GoBack: ← Wróć 23 | History: Historia 24 | Job: Zadanie 25 | LastRetry: Ostatnie ponowienie 26 | LivePoll: Wczytuj na żywo 27 | MemoryUsage: Wykorzystanie pamięci 28 | Namespace: Przestrzeń nazw 29 | NextRetry: Następne ponowienie 30 | NoRetriesFound: Brak zadań do ponowienia 31 | NoScheduledFound: Brak zaplanowanych zadań 32 | OneMonth: 1 miesiąc 33 | OneWeek: 1 tydzień 34 | OriginallyFailed: Ostatnio nieudane 35 | PeakMemoryUsage: Największe wykorzystanie pamięci 36 | Processed: Ukończone 37 | Queue: Kolejka 38 | Queues: Kolejki 39 | Realtime: Czas rzeczywisty 40 | Retries: Do ponowienia 41 | RetryAll: Powtórz wszystko 42 | RetryCount: Ilość ponowień 43 | RetryNow: Ponów teraz 44 | Scheduled: Zaplanowane 45 | ScheduledJobs: Zaplanowane zadania 46 | ShowAll: Pokaż wszystko 47 | SixMonths: 6 miesięcy 48 | Size: Rozmiar 49 | Started: Rozpoczęte 50 | Status: Status 51 | StopPolling: Zatrzymaj wczytywanie na żywo 52 | ThreeMonths: 3 miesiące 53 | Time: Czas 54 | Uptime: Uptime (dni) 55 | Version: Wersja 56 | When: Kiedy 57 | Worker: Worker 58 | active: aktywne 59 | idle: bezczynne 60 | -------------------------------------------------------------------------------- /web/locales/pt.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | pt: 3 | Actions: Acções 4 | AddToQueue: Adicionar à fila 5 | AreYouSure: Tem a certeza? 6 | AreYouSureDeleteJob: Tem a certeza que deseja eliminar esta tarefa? 7 | AreYouSureDeleteQueue: Tem a certeza que deseja eliminar a fila %{queue}? 8 | Arguments: Argumentos 9 | Busy: Ocupado 10 | Class: Classe 11 | Connections: Conexões 12 | CurrentMessagesInQueue: Mensagens na fila %{queue} 13 | Dashboard: Dashboard 14 | Dead: Morto 15 | DeadJobs: Tarefas mortas 16 | Delete: Apagar 17 | DeleteAll: Eliminar todos 18 | Enqueued: Em espera 19 | Error: Erro 20 | ErrorBacktrace: Backtrace do Erro 21 | ErrorClass: Classe de Erro 22 | ErrorMessage: Mensagem de erro 23 | Failed: Falhados 24 | Failures: Falhas 25 | GoBack: ← Voltar 26 | History: Histórico 27 | Job: Tarefa 28 | Jobs: Tarefas 29 | LastRetry: Última Tentativa 30 | LivePoll: Live Poll 31 | MemoryUsage: Utilização de Memória 32 | Namespace: Namespace 33 | NextRetry: Próxima Tentativa 34 | NoDeadJobsFound: Não foram encontradas tarefas mortas 35 | NoRetriesFound: Não foram encontradas tentativas 36 | NoScheduledFound: Não foram encontradas tarefas agendadas 37 | OneMonth: 1 mês 38 | OneWeek: 1 semana 39 | OriginallyFailed: Falhou inicialmente 40 | PeakMemoryUsage: Pico de utilização de memória 41 | Processed: Processados 42 | Processes: Processos 43 | Queue: Fila 44 | Queues: Filas 45 | Realtime: Tempo real 46 | Retries: Tentativas 47 | RetryAll: Tentar tudo novamente 48 | RetryCount: Tentativas efectuadas 49 | RetryNow: Tentar novamente 50 | Scheduled: Agendados 51 | ScheduledJobs: Tarefas agendadas 52 | ShowAll: Mostrar todos 53 | SixMonths: 6 meses 54 | Size: Tamanho 55 | Started: Iniciados 56 | Status: Estado 57 | StopPolling: Desactivar Live Poll 58 | Thread: Thread 59 | Threads: Threads 60 | ThreeMonths: 3 meses 61 | Time: Tempo 62 | Uptime: Uptime (em dias) 63 | Version: Versão 64 | When: Quando 65 | Worker: Worker 66 | active: activo 67 | idle: livre 68 | -------------------------------------------------------------------------------- /web/locales/ru.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | ru: 3 | Actions: Действия 4 | AddToQueue: Добавить в очередь 5 | AreYouSure: Вы уверены? 6 | AreYouSureDeleteJob: Вы уверены, что хотите удалить эту задачу? 7 | AreYouSureDeleteQueue: Вы уверены, что хотите удалить очередь %{queue}? 8 | Arguments: Аргументы 9 | BackToApp: Назад 10 | Busy: Занят 11 | Class: Класс 12 | Connections: Соединения 13 | CreatedAt: Создан 14 | CurrentMessagesInQueue: Текущие задачи в очереди %{queue} 15 | Dashboard: Панель управления 16 | Dead: Убито 17 | DeadJobs: Убитые задачи 18 | Delete: Удалить 19 | DeleteAll: Удалить все 20 | Enqueued: В очереди 21 | Error: Ошибка 22 | ErrorBacktrace: Трассировка ошибки 23 | ErrorClass: Класс ошибки 24 | ErrorMessage: Сообщение об ошибке 25 | Extras: Дополнительно 26 | Failed: Провалено 27 | Failures: Провалы 28 | GoBack: ← Назад 29 | History: История 30 | Job: Задача 31 | Jobs: Задачи 32 | Kill: Убиваем 33 | KillAll: Убить всё 34 | LastRetry: Последняя попытка 35 | Latency: Задержка 36 | LivePoll: Постоянный опрос 37 | MemoryUsage: Использование памяти 38 | Namespace: Пространство имен 39 | NextRetry: Следующая попытка 40 | NoDeadJobsFound: Нет убитых задач 41 | NoRetriesFound: Нет попыток 42 | NoScheduledFound: Нет запланированных задач 43 | NotYetEnqueued: Пока не в очереди 44 | OneMonth: 1 месяц 45 | OneWeek: 1 неделя 46 | OriginallyFailed: Первый провал 47 | Pause: Пауза 48 | Paused: Приостановлено 49 | PeakMemoryUsage: Максимальный расход памяти 50 | Plugins: Плагины 51 | PollingInterval: Интервал опроса 52 | Processed: Обработано 53 | Processes: Процессы 54 | Queue: Очередь 55 | Queues: Очереди 56 | Quiet: Отдыхать 57 | QuietAll: Отдыхать всем 58 | Realtime: Сейчас 59 | Retries: Попытки 60 | RetryAll: Повторить все 61 | RetryCount: Кол-во попыток 62 | RetryNow: Повторить сейчас 63 | Scheduled: Запланировано 64 | ScheduledJobs: Запланированные задачи 65 | ShowAll: Показать все 66 | SixMonths: 6 месяцев 67 | Size: Размер 68 | Started: Запущено 69 | Status: Статус 70 | Stop: Остановить 71 | StopAll: Остановить все 72 | StopPolling: Остановить опрос 73 | Thread: Поток 74 | Threads: Потоки 75 | ThreeMonths: 3 месяца 76 | Time: Время 77 | Unpause: Возобновить 78 | Uptime: Дня(ей) бесперебойной работы 79 | Version: Версия 80 | When: Когда 81 | Worker: Обработчик 82 | active: активен 83 | idle: отдыхает 84 | -------------------------------------------------------------------------------- /web/locales/sv.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | sv: 3 | Actions: Åtgärder 4 | AddToQueue: Lägg till i kö 5 | AreYouSure: Är du säker? 6 | AreYouSureDeleteJob: Är du säker på att du vill ta bort detta jobb? 7 | AreYouSureDeleteQueue: Är du säker på att du vill ta bort kön %{queue}? 8 | Arguments: Argument 9 | Busy: Upptagen 10 | Class: Klass 11 | Connections: Anslutningar 12 | CurrentMessagesInQueue: Jobb i %{queue} 13 | Dashboard: Panel 14 | Dead: Död 15 | DeadJobs: Döda jobb 16 | Delete: Ta bort 17 | DeleteAll: Ta bort alla 18 | Enqueued: Köad 19 | Error: Fel 20 | ErrorBacktrace: Backtrace för fel 21 | ErrorClass: Felklass 22 | ErrorMessage: Felmeddelande 23 | Extras: Extra 24 | Failed: Misslyckad 25 | Failures: Failures 26 | GoBack: ← Bakåt 27 | History: Historik 28 | Job: Jobb 29 | Jobs: Jobb 30 | LastRetry: Senaste försök 31 | LivePoll: Live poll 32 | MemoryUsage: Minnesanvändning 33 | Namespace: Namnrymd 34 | NextRetry: Nästa försök 35 | NoDeadJobsFound: Inga döda jobb hittades 36 | NoRetriesFound: Inga försök hittades 37 | NoScheduledFound: Inga schemalagda jobb hittades 38 | OneMonth: 1 månad 39 | OneWeek: 1 vecka 40 | OriginallyFailed: Misslyckades ursprungligen 41 | PeakMemoryUsage: Minnesanvändning (peak) 42 | Processed: Processerad 43 | Processes: Processer 44 | Queue: Kö 45 | Queues: Köer 46 | Realtime: Realtid 47 | Retries: Försök 48 | RetryAll: Försök alla igen 49 | RetryCount: Antal försök 50 | RetryNow: Försök nu 51 | Scheduled: Schemalagd 52 | ScheduledJobs: Schemalagda jobb 53 | ShowAll: Visa alla 54 | SixMonths: 6 månader 55 | Size: Storlek 56 | Started: Startad 57 | Status: Status 58 | StopPolling: Stoppa polling 59 | Thread: Tråd 60 | Threads: Trådar 61 | ThreeMonths: 3 månader 62 | Time: Tid 63 | Uptime: Upptid (dagar) 64 | Version: Version 65 | When: När 66 | Worker: Worker 67 | active: aktiv 68 | idle: avvaktande 69 | -------------------------------------------------------------------------------- /web/locales/ta.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | ta: 3 | Actions: செயல்கள் 4 | AddToQueue: வரிசையில் சேர் 5 | AreYouSure: நீங்கள் உறுதியாக இருக்கிறீர்களா? 6 | AreYouSureDeleteJob: நீ இந்த வேலையை நீக்க வேண்டும் என்று உறுதியாக இருக்கிறீர்களா? 7 | AreYouSureDeleteQueue: நீங்கள் %{queue} வரிசையில் நீக்க வேண்டும் என்பதில் உறுதியாக இருக்கிறீர்களா? 8 | Arguments: வாதங்கள், 9 | Busy: பணிமிகுதி 10 | Class: வகுப்பு 11 | Connections: இணைப்புகள் 12 | CurrentMessagesInQueue: தற்போதைய வேலைகள் %{queue} 13 | Dashboard: டாஷ்போர்டு 14 | Dead: இறந்துபோன 15 | DeadJobs: டெட் வேலைகள் 16 | Delete: நீக்கு 17 | DeleteAll: அனைத்து நீக்கு 18 | Enqueued: வரிசைப்படுத்தப்பட்டவை 19 | Error: பிழை 20 | ErrorBacktrace: பிழை பின்தேடுலை 21 | ErrorClass: பிழை வகுப்பு 22 | ErrorMessage: பிழை செய்தி 23 | Extras: உபரி 24 | Failed: தோல்வி 25 | Failures: தோல்விகள் 26 | GoBack: பின்புறம் 27 | History: வரலாறு 28 | Job: வேலை 29 | Jobs: வேலை வாய்ப்புகள் 30 | Kill: கொல் 31 | LastRetry: கடைசியாக, மீண்டும் முயற்சிக்கவும் 32 | LivePoll: நேரடி கணிப்பு 33 | MemoryUsage: நினைவக பயன்பாடு 34 | Namespace: பெயர்வெளி 35 | NextRetry: அடுத்த, மீண்டும் முயற்சிக்கவும் 36 | NoDeadJobsFound: இறந்த வேலை எதுவும் இல்லை 37 | NoRetriesFound: இல்லை மீண்டும் காணப்படவில்லை 38 | NoScheduledFound: திட்டமிட்ட வேலைகள் காணப்படவில்லை 39 | OneMonth: 1 மாதம் 40 | OneWeek: 1 வாரம் 41 | OriginallyFailed: முதலில் தோல்வி 42 | Paused: தற்காலிக பணிநிறுத்தம் 43 | PeakMemoryUsage: உச்ச நினைவக பயன்பாடு 44 | PollingInterval: வாக்குப்பதிவு இடைவெளி 45 | Processed: நிறையுற்றது 46 | Processes: செயல்முறைகள் 47 | Queue: வரிசை 48 | Queues: வரிசை 49 | Quiet: அமைதியான 50 | QuietAll: அமைதியான அனைத்து 51 | Realtime: நேரலை 52 | Retries: மீண்டும் முயற்சிக்க, 53 | RetryAll: அனைத்து, மீண்டும் முயற்சிக்கவும் 54 | RetryCount: கணிப்பீடு, மீண்டும் முயற்சிக்கவும் 55 | RetryNow: இப்போது மீண்டும் முயற்சி செய்க 56 | Scheduled: திட்டமிடப்பட்ட 57 | ScheduledJobs: திட்டமிட்ட வேலைகள் 58 | ShowAll: அனைத்து காட்டு 59 | SixMonths: 6 மாதங்கள் 60 | Size: அளவு 61 | Started: தொடங்குதல் 62 | Status: நிலைமை 63 | Stop: நிறுத்து 64 | StopAll: நிறுத்து அனைத்து 65 | StopPolling: நிறுத்து வாக்குப்பதிவு 66 | Thread: நூல் 67 | Threads: நூல்கள் 68 | ThreeMonths: 3 மாதங்கள் 69 | Time: நேரம் 70 | Uptime: இயக்க நேரம் (நாட்கள்) 71 | Version: பதிப்பு 72 | When: எப்பொழுது? 73 | Worker: பணியாளர் 74 | active: செயலில் 75 | idle: முடங்கு நேரம் 76 | -------------------------------------------------------------------------------- /web/locales/uk.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | uk: 3 | Actions: Дії 4 | AddToQueue: Додати до черги 5 | AreYouSure: Ви впевнені? 6 | AreYouSureDeleteJob: Ви впевнені у тому, що хочете видалити задачу? 7 | AreYouSureDeleteQueue: Ви впевнені у тому, що хочете видалити чергу %{queue}? 8 | Arguments: Аргументи 9 | Busy: Зайнятих 10 | Class: Клас 11 | Connections: З'єднань 12 | CurrentMessagesInQueue: Поточні задачі у черзі %{queue} 13 | Dashboard: Панель керування 14 | Dead: Вбитих 15 | DeadJobs: Вбиті задачі 16 | Delete: Видалити 17 | DeleteAll: Видалити усі 18 | Enqueued: У черзі 19 | Error: Помилка 20 | ErrorBacktrace: Трасування помилки 21 | ErrorClass: Клас помилки 22 | ErrorMessage: Повідомлення про помилку 23 | Extras: Додатково 24 | Failed: Невдалих 25 | Failures: Невдачі 26 | GoBack: ← Назад 27 | History: Історія 28 | Job: Задача 29 | Jobs: Задачі 30 | Kill: Вбиваємо 31 | LastRetry: Остання спроба 32 | LivePoll: Постійне опитування 33 | MemoryUsage: Використання пам'яті 34 | Namespace: Простір імен 35 | NextRetry: Наступна спроба 36 | NoDeadJobsFound: Вбитих задач не знайдено 37 | NoRetriesFound: Спроб не знайдено 38 | NoScheduledFound: Запланованих задач не знайдено 39 | NotYetEnqueued: Ще не в черзі 40 | OneMonth: 1 місяць 41 | OneWeek: 1 тиждень 42 | OriginallyFailed: Перша невдала спроба 43 | Paused: Призупинено 44 | PeakMemoryUsage: Максимальне використання пам'яті 45 | Plugins: Плагіни 46 | PollingInterval: Інтервал опитування 47 | Processed: Опрацьовано 48 | Processes: Процеси 49 | Queue: Черга 50 | Queues: Черги 51 | Quiet: Призупинити 52 | QuietAll: Призупинити усі 53 | Realtime: Зараз 54 | Retries: Спроби 55 | RetryAll: Повторити усі 56 | RetryCount: Кількість спроб 57 | RetryNow: Повторити зараз 58 | Scheduled: Заплановано 59 | ScheduledJobs: Заплановані задачі 60 | ShowAll: Відобразити усі 61 | SixMonths: 6 місяців 62 | Size: Розмір 63 | Started: Запущено 64 | Status: Статус 65 | Stop: Зупинити 66 | StopAll: Зупинити усі 67 | StopPolling: Зупинити опитування 68 | Thread: Потік 69 | Threads: Потоки 70 | ThreeMonths: 3 місяці 71 | Time: Час 72 | Uptime: Днів безперебійної роботи 73 | Version: Версія 74 | When: Коли 75 | Worker: Обробник 76 | active: активний 77 | idle: незайнятий 78 | -------------------------------------------------------------------------------- /web/locales/ur.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | ur: 3 | Actions: ﻋﻮاﻣﻞ 4 | AddToQueue: ﻗﻄﺎﺭ ميں شامل کريں 5 | AreYouSure: کيا یقین ؟ 6 | AreYouSureDeleteJob: کيا آپ یقین جاب حتم کرنا چاھتے ہيں ؟ 7 | AreYouSureDeleteQueue: کيا آپ یقین قطار حتم کرنا چاھتے ہيں ؟ 8 | Arguments: دلائل 9 | BackToApp: ﻭاپﺱ صفحۂ اﻭﻝ پر 10 | Busy: مصروف 11 | Class: کلاس 12 | Connections: کنکشنز 13 | CreatedAt: ﺗﺎﺭﻳﺢ آﻏﺎﺯ 14 | CurrentMessagesInQueue: قطار ميں موجود تمام پيغامات %{queue} 15 | Dashboard: صفحۂ اول 16 | Dead: ختم شدہ 17 | DeadJobs: ختم شدہ جاب 18 | Delete: ﺣﺬﻑ 19 | DeleteAll: ﺗﻤﺎﻡ ﺣﺬﻑ کر ديں 20 | Enqueued: قطار ميں شامل 21 | Error: مسئلہ 22 | ErrorBacktrace: مسئلہ کی کی تحقیقات کريں 23 | ErrorClass: مسئلہ کی کلاس 24 | ErrorMessage: مسئلہ کی وجہ 25 | Extras: اﺻﺎﻑی 26 | Failed: ﻧﺎکاﻡ ﺷﺪﮦ 27 | Failures: ناکامیاں 28 | GoBack: واپس جايں 29 | History: ﺗﺎﺭﻳﺦ 30 | Job: جاب 31 | Jobs: جابز 32 | Kill: ختم کرديں 33 | LastRetry: گزشتہ کوشش 34 | LivePoll: ﺑﺮاﮦ ﺭاﺳﺖ 35 | MemoryUsage: یاداشت کا استعمال 36 | Namespace: Namespace 37 | NextRetry: اگلی کﻭﺷﻴﺶ 38 | NoDeadJobsFound: کویٔ ختم شدہ جاب نہيی ملی 39 | NoRetriesFound: کویٔ ﺩﻭﺑﺎﺭﮦ کﻭﺷﻴﺶ نھيں ملی 40 | NoScheduledFound: کویٔ ﻁےﺷﺪﮦچيز نہیں ملی 41 | NotYetEnqueued: ﻗﺘﺎﺭميں شامل نھيں 42 | OneMonth: ایک مہینہ 43 | OneWeek: ایک ہفتہ 44 | OriginallyFailed: ابتادائ ناکامی 45 | Paused: موقوف 46 | PeakMemoryUsage: سب سے زيادہ یاداشت کا استعمال 47 | Plugins: پلگ انز 48 | PollingInterval: ﺑﺮاﮦ ﺭاﺳﺖ کا ﺩﻭﺭاﻧﻴﮧ 49 | Processed: مکمل شدہ 50 | Processes: ﻋﻤﻠﻴﺎﺕ 51 | Queue: قطار 52 | Queues: قطاريں 53 | Quiet: ﺣﺘﻢ کﺭﻭ 54 | QuietAll: ﺗﻤﺎﻡ ﺣﺘﻢ کﺭﻭ 55 | Realtime: ﺑﺮاﮦ ﺭاﺳﺖ 56 | Retries: ﺩﻭﺑﺎﺭﮦ کﻭﺷﻴﺶ 57 | RetryAll: ﺗﻤﺎﻡ کی ﺩﻭﺑﺎﺭﮦ کﻭﺷﻴﺶ کﺭيں 58 | RetryCount: دوبارہ کوشش کا مکمل شمار 59 | RetryNow: ابھی دوبارہ کوشش 60 | Scheduled: ﻁےﺷﺪﮦ 61 | ScheduledJobs: ﻁےﺷﺪﮦجاب 62 | ShowAll: سارے دکھاو 63 | SixMonths: چھ ماہ 64 | Size: ﺣﺠﻢ 65 | Started: شروع 66 | Status: اسٹیٹس 67 | Stop: بند کرو 68 | StopAll: ﺗﻤﺎﻡ ﺑﻨﺪ کﺭﻭ 69 | StopPolling: ﺑﺮاﮦ ﺭاﺳﺖ روکيے 70 | TextDirection: 'rtl' 71 | Thread: موضوع 72 | Threads: موضوع 73 | ThreeMonths: تین ماہ 74 | Time: ﻭﻗﺖ 75 | Uptime: اپ ٹائم 76 | Version: ورژن 77 | When: ﺏک 78 | Worker: ورکر 79 | active: فعال 80 | idle: بیکار 81 | -------------------------------------------------------------------------------- /web/locales/vi.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | vi: 3 | Actions: Những hành động 4 | AddToQueue: Thêm vào hàng đợi 5 | AreYouSure: Bạn chắc chứ? 6 | AreYouSureDeleteJob: Bạn có chắc là muốn xóa tác vụ này? 7 | AreYouSureDeleteQueue: Bạn có chắc là muốn xóa %{queue} này? 8 | Arguments: Tham số 9 | BackToApp: Trở về ứng dụng 10 | Busy: Bận rộn 11 | Class: Lớp 12 | Connections: Các kết nối 13 | CreatedAt: Được tạo vào lúc 14 | CurrentMessagesInQueue: Số lượng công việc trong %{queue} 15 | Dashboard: Bảng điều khiển 16 | Dead: Chết 17 | DeadJobs: Những tác vụ đã chết 18 | Delete: Xóa 19 | DeleteAll: Xóa hết 20 | Enqueued: Đã xếp hàng đợi 21 | Error: Lỗi 22 | ErrorBacktrace: Dấu vết của lỗi 23 | ErrorClass: Lớp lỗi 24 | ErrorMessage: Tin nhắn lỗi 25 | Extras: Thêm 26 | Failed: Đã thất bại 27 | Failures: Các thất bại 28 | GoBack: ← Trở lại 29 | History: Lịch sử 30 | Job: Tác vụ 31 | Jobs: Các tác vụ 32 | Kill: Giết 33 | KillAll: Giết hết 34 | LastRetry: Lần thử cuối 35 | Latency: Độ trễ 36 | LivePoll: Thăm dò trực tiếp 37 | MemoryUsage: Lượng bộ nhớ sử dụng 38 | Namespace: Không gian tên 39 | NextRetry: Lần thử lại tiếp theo 40 | NoDeadJobsFound: Không có tác vụ đã chết nào được tìm thấy 41 | NoRetriesFound: Không có lần thử nào được tìm thấy 42 | NoScheduledFound: Không có tác vụ đã lên lịch nào được tìm thấy 43 | NotYetEnqueued: Chưa được bỏ vào hàng đợi 44 | OneMonth: 1 tháng 45 | OneWeek: 1 tuần 46 | OriginallyFailed: Đã thất bại từ đầu 47 | Pause: Tạm dừng 48 | Paused: Đã tạm dừng 49 | PeakMemoryUsage: Lượng bộ nhớ sử dụng đỉnh điểm 50 | Plugins: Hệ thống đính kèm 51 | PollingInterval: Khoảng thời gian giữa các lần thăm dò 52 | Processed: Đã xử lí 53 | Processes: Tiến trình xử lí 54 | Queue: Hàng đợi 55 | Queues: Các hàng đợi 56 | Quiet: Im lặng 57 | QuietAll: Làm cho tất cả im lặng 58 | Realtime: Thời gian thực 59 | Retries: Số lần thử 60 | RetryAll: Thử lại tất cả 61 | RetryCount: Số lần thử lại 62 | RetryNow: Thử lại ngay bây giờ 63 | Scheduled: Đã lên lịch 64 | ScheduledJobs: Những Tác Vụ Được Hẹn 65 | ShowAll: Hiện tất cả 66 | SixMonths: 6 tháng 67 | Size: Kích thước 68 | Started: Đã bắt đầu 69 | Status: Trạng thái 70 | Stop: Dừng Lại 71 | StopAll: Dừng lại tất cả 72 | StopPolling: Ngừng thăm dò 73 | Thread: Luồng xử lí 74 | Threads: Những luồng xử lí 75 | ThreeMonths: 3 tháng 76 | Time: Thời gian 77 | Unpause: Hủy tạm dừng 78 | Uptime: Thời gian hệ thống đã online (days) 79 | Version: Phiên bản 80 | When: Khi nào 81 | Worker: Máy xử lí 82 | active: Đang hoạt động 83 | idle: Đang chờ 84 | -------------------------------------------------------------------------------- /web/locales/zh-cn.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | zh-cn: # <---- change this to your locale code 3 | Dashboard: 信息板 4 | Status: 状态 5 | Time: 时间 6 | Namespace: 命名空间 7 | Realtime: 实时 8 | History: 历史记录 9 | Busy: 执行中 10 | Utilization: 利用率 11 | Processed: 已处理 12 | Failed: 已失败 13 | Scheduled: 已计划 14 | Retries: 重试 15 | Enqueued: 已进入队列 16 | Worker: 工人 17 | LivePoll: 实时轮询 18 | StopPolling: 停止轮询 19 | Queue: 队列 20 | Class: 类别 21 | Job: 任务 22 | Arguments: 参数 23 | Extras: 额外的 24 | Started: 已开始 25 | ShowAll: 显示全部 26 | CurrentMessagesInQueue: 目前在%{queue}的任务 27 | Delete: 删除 28 | AddToQueue: 添加至队列 29 | AreYouSureDeleteJob: 你确定要删除这个任务么? 30 | AreYouSureDeleteQueue: 你确定要删除%{queue}这个队列? 31 | Queues: 队列 32 | Size: 容量 33 | Actions: 动作 34 | NextRetry: 下次重试 35 | RetryCount: 重试次数 36 | RetryNow: 现在重试 37 | Kill: 终止 38 | LastRetry: 上次重试 39 | OriginallyFailed: 首次失败 40 | AreYouSure: 你确定? 41 | DeleteAll: 全部删除 42 | RetryAll: 全部重试 43 | KillAll: 全部终止 44 | NoRetriesFound: 没有发现可重试 45 | Error: 错误 46 | ErrorClass: 错误类别 47 | ErrorMessage: 错误消息 48 | ErrorBacktrace: 错误细节 49 | GoBack: ← 返回 50 | NoScheduledFound: 没有发现计划任务 51 | When: 当 52 | ScheduledJobs: 计划任务 53 | idle: 闲置 54 | active: 活动中 55 | Version: 版本 56 | Connections: 连接 57 | MemoryUsage: 内存占用 58 | PeakMemoryUsage: 内存占用峰值 59 | Uptime: 上线时间 (天数) 60 | OneWeek: 一周 61 | OneMonth: 一个月 62 | ThreeMonths: 三个月 63 | SixMonths: 六个月 64 | Failures: 失败 65 | DeadJobs: 已停滞任务 66 | NoDeadJobsFound: 没有发现任何已停滞的任务 67 | Dead: 已停滞 68 | Process: 进程 69 | Processes: 进程 70 | Name: 名称 71 | Thread: 线程 72 | Threads: 线程 73 | Jobs: 任务 74 | Paused: 已暂停 75 | Stop: 强制暂停 76 | Quiet: 暂停 77 | StopAll: 全部强制暂停 78 | QuietAll: 全部暂停 79 | PollingInterval: 轮询周期 80 | Plugins: 插件 81 | NotYetEnqueued: 尚未进入队列 82 | CreatedAt: 建立时间 83 | BackToApp: 回首頁 84 | Latency: 延迟 85 | Pause: 暂停 86 | Unpause: 取消暂停 87 | Metrics: 指标 88 | NoDataFound: 无数据 89 | TotalExecutionTime: 总执行时间 90 | AvgExecutionTime: 平均执行时间 91 | Context: 上下文 92 | Bucket: 桶 93 | NoJobMetricsFound: 无任务相关指标数据 94 | Success: 成功 95 | Failure: 失败 96 | -------------------------------------------------------------------------------- /web/locales/zh-tw.yml: -------------------------------------------------------------------------------- 1 | # elements like %{queue} are variables and should not be translated 2 | zh-tw: # <---- change this to your locale code 3 | Dashboard: 資訊主頁 4 | Status: 狀態 5 | Time: 時間 6 | Namespace: 命名空間 7 | Realtime: 即時 8 | History: 歷史資料 9 | Busy: 忙碌 10 | Utilization: 使用率 11 | Processed: 已處理 12 | Failed: 已失敗 13 | Scheduled: 已排程 14 | Retries: 重試 15 | Enqueued: 已佇列 16 | Worker: 工人 17 | LivePoll: 即時輪詢 18 | StopPolling: 停止輪詢 19 | Queue: 佇列 20 | Class: 類別 21 | Job: 工作 22 | Arguments: 參數 23 | Extras: 額外的 24 | Started: 已開始 25 | ShowAll: 顯示全部 26 | CurrentMessagesInQueue: 目前在%{queue}的工作 27 | Delete: 刪除 28 | AddToQueue: 增加至佇列 29 | AreYouSureDeleteJob: 確定要刪除這個工作嗎? 30 | AreYouSureDeleteQueue: 確定要刪除%{queue}佇列?這會刪除佇列裡的所有工作,佇列將會在有新工作時重新出現。 31 | Queues: 佇列 32 | Size: 容量 33 | Actions: 動作 34 | NextRetry: 下次重試 35 | RetryCount: 重試次數 36 | RetryNow: 馬上重試 37 | Kill: 取消 38 | LastRetry: 最後一次重試 39 | OriginallyFailed: 原本已失敗 40 | AreYouSure: 你確定? 41 | DeleteAll: 全部刪除 42 | RetryAll: 全部重試 43 | KillAll: 全部取消 44 | NoRetriesFound: 找無可重試的工作 45 | Error: 錯誤 46 | ErrorBacktrace: 錯誤的回調追踨 47 | ErrorClass: 錯誤類別 48 | ErrorMessage: 錯誤訊息 49 | ErrorBacktrace: 詳細錯誤訊息 50 | GoBack: ← 返回 51 | NoScheduledFound: 找無已排程的工作 52 | When: 當 53 | ScheduledJobs: 已排程的工作 54 | idle: 閒置 55 | active: 活動中 56 | Version: 版本 57 | Connections: 連線 58 | MemoryUsage: 記憶體使用量 59 | PeakMemoryUsage: 尖峰記憶體使用量 60 | Uptime: 上線時間 (天數) 61 | OneWeek: 一週 62 | OneMonth: 一個月 63 | ThreeMonths: 三個月 64 | SixMonths: 六個月 65 | Failures: 失敗 66 | GoBack: ← 返回 67 | History: 歷史資料 68 | Job: 工作 69 | Jobs: 工作 70 | LastRetry: 最後一次重試 71 | LivePoll: 即時輪詢 72 | MemoryUsage: 記憶體使用量 73 | Namespace: 命名空間 74 | NextRetry: 下次重試 75 | NoDeadJobsFound: 沒有發現任何停滯的工作 76 | Dead: 停滯 77 | Process: 程序 78 | Processes: 處理中 79 | Name: 名稱 80 | Thread: 執行緒 81 | Threads: 執行緒 82 | Jobs: 工作 83 | Paused: 已暫停 84 | Stop: 強制暫停 85 | Quiet: 暫停 86 | StopAll: 全部強制暫停 87 | QuietAll: 全部暫停 88 | PollingInterval: 輪詢週期 89 | Plugins: 套件 90 | NotYetEnqueued: 尚未進入佇列 91 | CreatedAt: 建立時間 92 | BackToApp: 回首頁 93 | Latency: 延時 94 | Pause: 暫停 95 | Unpause: 取消暫停 96 | Metrics: 計量 97 | NoDataFound: 找無資料 98 | TotalExecutionTime: 總執行時間 99 | AvgExecutionTime: 平均執行時間 100 | Context: 上下文 101 | Bucket: 桶 102 | NoJobMetricsFound: 找無工作相關計量資料 103 | -------------------------------------------------------------------------------- /web/views/_footer.erb: -------------------------------------------------------------------------------- 1 | 36 | -------------------------------------------------------------------------------- /web/views/_metrics_period_select.erb: -------------------------------------------------------------------------------- 1 |
2 | 12 |
13 | -------------------------------------------------------------------------------- /web/views/_nav.erb: -------------------------------------------------------------------------------- 1 | 53 | -------------------------------------------------------------------------------- /web/views/_paging.erb: -------------------------------------------------------------------------------- 1 |
2 | <% if @total_size > @count %> 3 | 24 | <% end %> 25 |
26 | -------------------------------------------------------------------------------- /web/views/_poll_link.erb: -------------------------------------------------------------------------------- 1 | <% if pollable? %> 2 | <%= t('LivePoll') %> 3 | <%= t('StopPolling') %> 4 | <% end %> 5 | -------------------------------------------------------------------------------- /web/views/_status.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%= t(current_status) %> 4 | 5 | -------------------------------------------------------------------------------- /web/views/_summary.erb: -------------------------------------------------------------------------------- 1 | 41 | -------------------------------------------------------------------------------- /web/views/dead.erb: -------------------------------------------------------------------------------- 1 | <%= erb :_job_info, locals: { job: @dead, type: :dead } %> 2 | 3 |

<%= t('Error') %>

4 |
5 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | <% if @dead.error_backtrace %> 18 | 19 | 20 | 23 | 24 | <% end %> 25 | 26 |
<%= t('ErrorClass') %> 10 | <%= @dead['error_class'] %> 11 |
<%= t('ErrorMessage') %><%= h(@dead['error_message']) %>
<%= t('ErrorBacktrace') %> 21 | <%= @dead.error_backtrace.join("
") %>
22 |
27 |
28 | 29 |
30 | <%= csrf_tag %> 31 | <%= t('GoBack') %> 32 | 33 | 34 |
35 | -------------------------------------------------------------------------------- /web/views/filtering.erb: -------------------------------------------------------------------------------- 1 |
2 |
3 | <%= csrf_tag %> 4 | 5 | 6 |
7 |
8 | -------------------------------------------------------------------------------- /web/views/layout.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | <%= environment_title_prefix %><%= Sidekiq::NAME %> 5 | 6 | 7 | 8 | 9 | <% if rtl? %> 10 | 11 | <% end %> 12 | 13 | 14 | 15 | <% if rtl? %> 16 | 17 | <% end %> 18 | 19 | 20 | 21 | 22 | 23 | <%= display_custom_head %> 24 | 25 | 26 | <%= erb :_nav %> 27 |
28 |
29 |
30 |
31 | <%= erb :_summary %> 32 |
33 | 34 |
35 | <%= yield %> 36 |
37 |
38 |
39 |
40 | <%= erb :_footer %> 41 | 42 | 43 | -------------------------------------------------------------------------------- /web/views/metrics_for_job.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | <% 6 | job_result = @query_result.job_results[@name] 7 | hist_totals = job_result.hist.values.first.zip(*job_result.hist.values[1..-1]).map(&:sum).reverse 8 | bucket_labels = Sidekiq::Metrics::Histogram::LABELS 9 | bucket_intervals = Sidekiq::Metrics::Histogram::BUCKET_INTERVALS 10 | %> 11 | 12 | <% if job_result.totals["s"] > 0 %> 13 |
14 |
15 |

16 | <%= t('Metrics') %> / 17 | <%= h @name %> 18 |

19 | 20 | ? 21 |
22 | 23 | <%= erb :_metrics_period_select, locals: { periods: @periods, period: @period, path: "#{root_path}metrics/#{@name}" } %> 24 |
25 | 26 | 27 | <%= to_json({ 28 | series: hist_totals, 29 | labels: bucket_labels, 30 | xLabel: t('ExecutionTime'), 31 | yLabel: t('Jobs'), 32 | units: t('Jobs').downcase, 33 | }) %> 34 | 35 | 36 | 37 | <%= to_json({ 38 | hist: job_result.hist, 39 | marks: @query_result.marks.map { |m| [m.bucket, m.label] }, 40 | labels: @query_result.buckets, 41 | histIntervals: bucket_intervals, 42 | yLabel: t('ExecutionTime'), 43 | markLabel: t('Deploy'), 44 | yUnits: t('Seconds').downcase, 45 | zUnits: t('Jobs').downcase, 46 | }) %> 47 | 48 | 49 | 50 | <% else %> 51 |

52 | <%= t('Metrics') %> / 53 | <%= h @name %> 54 |

55 | 56 |
<%= t('NoJobMetricsFound') %>
57 | <% end %> 58 | 59 | 60 | -------------------------------------------------------------------------------- /web/views/queue.erb: -------------------------------------------------------------------------------- 1 |
2 |

<%= t('CurrentMessagesInQueue', :queue => h(@name)) %> 3 | <% if @queue.paused? %> 4 | <%= t('Paused') %> 5 | <% end %> 6 | <%= number_with_delimiter(@total_size) %> 7 |

8 | <%= erb :_paging, locals: { url: "#{root_path}queues/#{CGI.escape(@name)}" } %> 9 |
10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | <% @jobs.each_with_index do |job, index| %> 21 | 22 | <% if params[:direction] == 'asc' %> 23 | 24 | <% else %> 25 | 26 | <% end %> 27 | 31 | 41 | 44 | 51 | 52 | <% end %> 53 |
# <%= sort_direction_label %><%= t('Job') %><%= t('Arguments') %><%= t('Context') %>
<%= @count * (@current_page - 1) + index + 1 %><%= @total_size - (@count * (@current_page - 1) + index) %> 28 | <%= h(job.display_class) %> 29 | <%= display_tags(job, nil) %> 30 | 32 | <% a = job.display_args %> 33 | <% if a.inspect.size > 100 %> 34 | <%= h(a.inspect[0..100]) + "... " %> 35 | 36 |
<%= display_args(a) %>
37 | <% else %> 38 | <%= display_args(job.display_args) %> 39 | <% end %> 40 |
42 | <%= h(job["cattr"].inspect) if job["cattr"]&.any? %> 43 | 45 |
46 | <%= csrf_tag %> 47 | 48 | 49 |
50 |
54 |
55 | <%= erb :_paging, locals: { url: "#{root_path}queues/#{CGI.escape(@name)}" } %> 56 | -------------------------------------------------------------------------------- /web/views/queues.erb: -------------------------------------------------------------------------------- 1 |
2 |

<%= t('Queues') %>

3 |
4 | 5 |
6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | <% @queues.each do |queue| %> 14 | 15 | 21 | 22 | 27 | 41 | 42 | <% end %> 43 |
<%= t('Queue') %><%= t('Size') %><%= t('Latency') %><%= t('Actions') %>
16 | <%= h queue.name %> 17 | <% if queue.paused? %> 18 | <%= t('Paused') %> 19 | <% end %> 20 | <%= number_with_delimiter(queue.size) %> 23 | <% queue_latency = queue.latency %> 24 | <%= (queue_latency < 60) ? '' : " (#{relative_time(Time.at(Time.now.to_f - queue_latency))})" %> 25 | <%= number_with_delimiter(queue_latency, precision: 2) %> 26 | 28 |
29 | <%= csrf_tag %> 30 | 31 | 32 | <% if Sidekiq.pro? %> 33 | <% if queue.paused? %> 34 | 35 | <% else %> 36 | 37 | <% end %> 38 | <% end %> 39 |
40 |
44 |
45 | -------------------------------------------------------------------------------- /web/views/retry.erb: -------------------------------------------------------------------------------- 1 | <%= erb :_job_info, locals: { job: @retry, type: :retry } %> 2 | 3 |

<%= t('Error') %>

4 |
5 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 17 | <% if @retry.error_backtrace %> 18 | 19 | 20 | 23 | 24 | <% end %> 25 | 26 |
<%= t('ErrorClass') %> 10 | <%= h @retry['error_class'] %> 11 |
<%= t('ErrorMessage') %><%= h(@retry['error_message']) %>
<%= t('ErrorBacktrace') %> 21 | <%= @retry.error_backtrace.join("
") %>
22 |
27 |
28 | 29 |
30 | <%= csrf_tag %> 31 | <%= t('GoBack') %> 32 | 33 | 34 |
35 | -------------------------------------------------------------------------------- /web/views/scheduled.erb: -------------------------------------------------------------------------------- 1 |
2 |

<%= t('ScheduledJobs') %>

3 | <% if @scheduled.size > 0 && @total_size > @count %> 4 | <%= erb :_paging, locals: { url: "#{root_path}scheduled" } %> 5 | <% end %> 6 | <%= filtering('scheduled') %> 7 |
8 | 9 | <% if @scheduled.size > 0 %> 10 |
11 | <%= csrf_tag %> 12 |
13 | 14 | 15 | 16 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | <% @scheduled.each do |entry| %> 28 | 29 | 34 | 37 | 40 | 44 | 47 | 48 | <% end %> 49 |
17 | 20 | <%= t('When') %><%= t('Queue') %><%= t('Job') %><%= t('Arguments') %>
30 | 33 | 35 | <%= relative_time(entry.at) %> 36 | 38 | <%= entry.queue %> 39 | 41 | <%= entry.display_class %> 42 | <%= display_tags(entry, "scheduled") %> 43 | 45 |
<%= display_args(entry.display_args) %>
46 |
50 |
51 | 52 | 53 |
54 | <% else %> 55 |
<%= t('NoScheduledFound') %>
56 | <% end %> 57 | -------------------------------------------------------------------------------- /web/views/scheduled_job_info.erb: -------------------------------------------------------------------------------- 1 | <%= erb :_job_info, locals: { job: @job, type: :scheduled } %> 2 | 3 |
4 | <%= csrf_tag %> 5 | <%= t('GoBack') %> 6 | 7 | 8 |
9 | --------------------------------------------------------------------------------