Skip to content

vinted/chained_job

Repository files navigation

ChainedJob

The library provides ability to use chained background jobs.

Installation

Add this line to your application's Gemfile:

gem 'chained_job'

And then execute:

$ bundle install

Or install the gem yourself:

$ gem install chained_job

How it works

chained_job stores background job arguments array in Redis and starts processing them in parallel by number of workers provided.

Job re-enqueues itself until there are no more stored arguments in Redis for that specific job.

Configuration

require 'logger'
require 'redis_config'

ChainedJob.configure do |config|
  # Default value is 1_000
  config.arguments_batch_size = 2_000

  # Default value is 7 days
  config.arguments_queue_expiration = 3 * 24 * 60 * 60 # 3 days

  # Error will be raised while running job if redis is not setup
  config.redis = Svc.redis # redis-client
  config.logger = ::Logger.new(STDOUT)
end

Custom Hooks

There are three types of hooks: around_start_chains, around_chain_process and around_array_of_job_arguments as lambda functions. Both of the hooks gets options hash.

For around_start_chains callback options hash contains four keys:

{
  job_class: CheckUsersActivityJob,
  array_of_job_arguments: [1, 2 ,3],
  parallelism: 2,
  args: [{"job_argument" => "value"}],
}

For around_chain_process:

{
  job_class: CheckUsersActivityJob,
  worker_id: 2,
  args: [{"job_argument" => "value"}],
}

For around_array_of_job_arguments:

{
  job_class: CheckUsersActivityJob,
  args: [{"job_argument" => "value"}],
}

You can configure callbacks:

ChainedJob.configure do |config|
  config.around_start_chains = ->(options, &block) do
    time = Benchmark.ms { block.call }

    puts "It took #{time} to start the chains for #{options[:job_class]} job"
  end
end

Usage

Example of creating new background ActiveJob:

# frozen_string_literal: true

class CheckUsersActivityJob < ActiveJob::Base
  include ChainedJob::Middleware

  def parallelism
    2
  end

  def array_of_job_arguments
    User.last(100).ids
  end

  def process(user_id)
    user = User.find_by(id: user_id)

    return unless user

    UserActivities::Check.run(user)
  end
end

On Failure (retry queue)

In this case, if one of your chained workers fails to process some ids - it will go into the retry queue and restarts as you would expect. However important to note that args picked from Redis are no longer available, and hence those ids won't be processed anymore.

In case you want that during exception your arguments would be pushed back to Redis, you can use

# frozen_string_literal: true

class CheckUsersActivityJob < ActiveJob::Base
  include ChainedJob::Middleware

  def handle_retry?
    true
  end
end

Development

For running tests use bundle exec rake test. To check linter errors use rubocop: bundle exec rubocop

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/vinted/chained_job.

About

No description, website, or topics provided.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages