Skip to content

judoscale/judoscale-ruby

Repository files navigation

Judoscale

Build Status: judoscale-ruby Build Status: judoscale-rails Build Status: judoscale-sidekiq Build Status: judoscale-solid_queue Build Status: judoscale-delayed_job Build Status: judoscale-good_job Build Status: judoscale-que Build Status: judoscale-shoryuken

These gems works together with the Judoscale Heroku add-on to scale your web and worker dynos automatically. They gather a minimal set of metrics for each request and job queue, and periodically posts this data asynchronously to the Judoscale API.

Requirements

Installation

To connect your app with Judoscale, add these lines to your application's Gemfile and run bundle install:

gem "judoscale-rails"
# Uncomment the gem for your job backend:
# gem "judoscale-sidekiq"
# gem "judoscale-solid_queue"
# gem "judoscale-resque"
# gem "judoscale-delayed_job"
# gem "judoscale-good_job"
# gem "judoscale-que"
# gem "judoscale-shoryuken"

If you're using a background job queue, make sure you include the corresponding judoscale-* gem as well.

The adapters report queue metrics to Judoscale every 10 seconds. The reporter will not run in development, or any other environment missing the JUDOSCALE_URL environment variable. (This environment variable is set for you automatically when provisioning the add-on.)

Installation for Non-Rails Rack apps

If you're using another Rack-based framework (such as Sinatra), you should use judoscale-rack instead of judoscale-rails:

gem "judoscale-rack"

The gem provides a request middleware, but you'll need to insert that middleware into your app.

Bundler.require
use Judoscale::RequestMiddleware

The middleware will start the async reporter when it processes the first request.

Worker adapters

Judoscale will autoscale your worker dynos! The following job backends are supported: Sidekiq, Solid Queue, Resque, Delayed Job, Good Job, Que, and Shoryuken. Be sure to install the gem specific to your job backend:

gem "judoscale-sidekiq"
gem "judoscale-solid_queue"
gem "judoscale-resque"
gem "judoscale-delayed_job"
gem "judoscale-good_job"
gem "judoscale-que"
gem "judoscale-shoryuken"

For most apps, no additional configuration is needed. See the configuration section below for all available options.

Note that if you aren't using Rails, you'll need to start the reporter manually. See below.

Specific worker backend notes

Resque

If you're using resque-scheduler and their standalone executable approach, add a require "judoscale-resque" to your executable, or require your entire Rails application. This ensures the Judoscale extension that stores latency for each job gets properly loaded within the scheduler process, otherwise metrics may not be reported appropriately from the scheduler.

Worker-only apps

If your app doesn't have a web process, you don't have to include the "judoscale-rails" gem. If you omit it, you'll need to start the reporter manually:

require "judoscale/reporter"
Judoscale::Reporter.start

You should do this after you've configured your job backend (such as Sidekiq.configure_server).

What data is collected?

The reporter runs in its own thread so your web requests and background jobs are not impacted. The following data is submitted periodically to the Judoscale API:

  • Ruby version
  • Rails version
  • Job library version (for Sidekiq, etc.)
  • Judoscale gem versions
  • Dyno name (example: web.1)
  • PID
  • Collection of queue time metrics (time and milliseconds) for web
  • Collection of queue time and/or queue depth metrics, and busy metrics (if enabled), for workers (see below)

Judoscale aggregates and stores this information to power the autoscaler algorithm and dashboard visualizations.

What data is collected for each worker adapter?

adapter queue time queue depth busy (if enabled)
judoscale-sidekiq
judoscale-solid_queue
judoscale-resque
judoscale-delayed_job
judoscale-good_job
judoscale-que
judoscale-shoryuken

Migrating from rails_autoscale_agent

The migration from rails_autoscale_agent to judoscale-rails (+ your job framework gem) is typically a single step: replace the gem "rails_autoscale_agent" in your Gemfile with gem "judoscale-rails" and the appropriate judoscale-* package for your back-end job framework (sidekiq, resque, delayed_job, good_job, or que) or see the Installation section above for further specifics. If you previously had any custom configuration for the rails_autoscale_agent, please note that we now use a configure block as shown below.

Looking for the old rails_autoscale_agent docs? They're available on this branch.

Optional Configuration

All autoscaling configurations are handled in the Judoscale web UI, but there a few ways you can change the behavior of the adapters. Most apps won't need to change any of the adapter configurations, in which case an initializer is not required.

The sample code below uses "sidekiq" for worker adapter configuration, but the options are available for each worker adapter. Replace "sidekiq" with your job backend to use those config options.

# config/initializers/judoscale.rb
Judoscale.configure do |config|
  # Provide a custom logger.
  # Default: (Rails logger, if available, or a basic Logger to STDOUT)
  # config.logger = MyLogger.new

  # Change the log_level for debugging or to quiet the logs.
  # See more in the "logging" section of the README.
  # Default: (defer to underlying logger)
  # config.log_level = :debug

  # Interval between each metrics report to the Judoscale API.
  # Default: 10 seconds
  # config.report_interval_seconds = 5

  # Worker metrics will only report up to 20 queues by default. If you have more than 20 queues,
  # you'll need to configure this setting for the specific worker adapter or reduce your number of queues.
  # Default: 20 queues
  # config.sidekiq.max_queues = 30

  # Specify a list of queues to collect metrics from. This overrides the default behavior which
  # automatically detects the queues. If specified, anything not explicitly listed will be excluded.
  # When setting the list of queues, `queue_filter` is ignored, but `max_queues` is still respected.
  # Note: judoscale-shoryuken will only report all queues across all available processes if the list
  # of queues is specified, otherwise just the shoryuken processes can report their known queues.
  # Default: (queues detected automatically)
  # config.sidekiq.queues = %w[low default high]

  # Filter queues to collect metrics from with a custom proc.
  # Return a falsy value (`nil`/`false`) to exclude the queue, any other value will include it.
  # Default: (queues that look like a UUID are rejected)
  # config.sidekiq.queue_filter = ->(queue_name) { /custom/.match?(queue_name) }

  # Enables reporting for active (busy) workers so that downscaling can be
  # suppressed.
  # See https://judoscale.com/docs/long-running-jobs/.
  # Note: judoscale-shoryuken does not support reporting busy jobs.
  # Default: false
  # config.sidekiq.track_busy_jobs = true

  # Disable reporting for this worker adapter.
  # Default: true
  # config.sidekiq.enabled = !ENV.key?("DISABLE_JUDOSCALE_SIDEKIQ_REPORTING")
end

Logging

judoscale-rails will use the Rails logger by default. Otherwise everything will log to STDOUT.

If you wish to use a different logger, you can set it on the configuration object:

# config/initializers/judoscale.rb
Judoscale.configure do |config|
  config.logger = MyLogger.new
end

The underlying logger controls the log level by default. In case of Rails apps, that's going to be defined by the log_level config in each Rails environment. So, if your app is set to log at INFO level, you will only see Judoscale INFO logs as well. Please note that this gem has very chatty debug logs, so if your app is set to DEBUG you will also see a lot of logging from Judoscale. Our debug logs look like this:

[Judoscale] [DEBUG] Some debug log message

If you find the gem too chatty with that setup, you can quiet it down with a more strict log level that only affects Judoscale logging:

# config/initializers/judoscale.rb
Judoscale.configure do |config|
  config.log_level = :info
end

Alternatively, set the JUDOSCALE_LOG_LEVEL environment variable on your Heroku app:

heroku config:set JUDOSCALE_LOG_LEVEL=info

If that's still too chatty for you, you can restrict it further:

# config/initializers/judoscale.rb
Judoscale.configure do |config|
  config.log_level = :warn
end

Troubleshooting

Once installed, you should see something like this in your development log:

[Judoscale] Reporter not started: JUDOSCALE_URL is not set

On the Heroku app where you've installed the add-on, run heroku logs -t | grep Judoscale, and you should see something like this:

[Judoscale] Reporter starting, will report every 10 seconds

If you don't see either of these, try running bundle again and restarting your Rails application.

You can see more detailed (debug) logging by setting JUDOSCALE_LOG_LEVEL on your Heroku app:

heroku config:set JUDOSCALE_LOG_LEVEL=debug

Reach out to [email protected] if you run into any other problems.

Development

Run bin/test to run all the tests across all the libraries, or inside each judoscale-* library, run bundle exec rake test. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install each gem onto your local machine, run bundle exec rake install.

To release a new version:

  1. Use Conventional Commits, and release branches will be created automatically via Release Please. This updates the changelog and the version of judoscale-ruby.
  2. Merge the release branch, and GitHub Actions will run bin/release to publish all gems to Rubygems.

Note: We keep all gem versions in sync to provide a better developer experience for our users.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/judoscale/judoscale-ruby.

License

The gem is available as open source under the terms of the MIT License.