Project

cuetip

0.0
Low commit activity in last 3 years
An ActiveRecord job queueing system
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Runtime

>= 0
>= 1.3, < 2.0
 Project Readme

Cuetip

Cuetip is a fast & reliable job queueing engine for applications that already use ActiveRecord. In its most simple form, workers will poll the database for jobs and execute them.

Installation

gem 'cuetip', '~> 1.0'

Once you have installed the gem, you'll need to copy over the migrations required to create the tables Cuetip needs to work.

$ bundle exec rake cuetip:install:migrations
$ bundle exec rake db:migrate

Configuration

There is some configuration which is required. In a Rails application, in: config/initializers/cuetip.rb.

Cuetip.configure do |config|

  # The interval between polling
  config.polling_interval = 10.seconds

  # Set a logger where all Cuetip related log messages will be sent to. By default, they will go to STDOUT.
  config.logger = Klogger.new(:cuetip, destination: Rails.root.join('log', 'cuetip.log'))

  # Configure a block to execute whenever an exception is encountered in a job. You might
  # use this for reporting to an exception reporting service. It is optional.
  config.on(:exception) do |exception, job|
    Raven.capture_exception(exception, :extra => {:job => job.id})
  end

end

and in: config/cuetip.rb

require_relative 'environment'

Jobs

To create a job to be executed by Cuetip, you need to make a class which inherits from Cuetip::Job. This class should implement (at a minimum) a perform method that will be executed when the job is queued. For example:

class ExampleJob < Cuetip::Job

  def perform
    # Do some long running work here.
  end

end

If you're working in a Rails application, you can place your jobs in a app/jobs directory.

When you want to queue a job for execution you can do so as follows. When you call queue it will return a Cuetip::QueuedJob object which is an ActiveRecord model for the backend job that has been queued.

job = ExampleJob.queue
job.id          # => The ID of the newly queued job.
job.status      # => Returns the status of the job
job.exception   # => If the job raised an exception, the exeception details will be available here.

Parameters

You can pass parameters to your job when queueing it. These must be something that can be serialised into JSON for persistence into the database. To access parameters within your job you can call the params method which will return a Hashie::Mash which allows you to access them in a flexible manner (i.e. params[:key] or params.key).

To send these parameters to the job, you can do so by passing a hash to the queue method as so:

ExampleJob.queue(:example => 'Some Example Param')

Errors & Exception

Any exception that occurs while your job is being processed will be logged with the job and can be looked up at any point in the future.

Retrying failed jobs

By default, jobs will not retry on exception. You can configure how many times to retry a job on failure by setting the retry_count when queueing the job.

ExampleJob.queue do |job|
  job.retry_count = 5                 # The number of times this job should be tried before giving up
  job.retry_interval = 30.seconds     # The length of time between retries
end

If a job is queued with retries enabled and you want to abort the current and any future executions, you can raise an error. The job status will be set to Aborted.

def perform
  raise Cuetip::AbortJob, "The reason for aborting the job"
end

Queues

By default, there is a single queue that will process jobs. Unless otherwise told, all jobs will happen on the the default queue. You can choose a queue to run a job on either by specifying it when queued or on the job itself.

# Define the queue every execution of a specific job
class ExampleJob < Cuetip::Job
  self.queue = 'otherqueue'
end

# Define the queue for a single queueing of a job
ExampleJob.queue do |job|
  job.queue = 'otherqueue'
end

Delays

If you wish to execute a job later in time, you can configure this when queueing the job. The job will be removed from the queue automatically at this time and

ExampleJob.queue do |job|
  job.run_after = 10.minutes.from_now
end

Maximum Execution Time

You can set a maximum time that a job will be executed for before it is terminated by the worker. You can do this on job class itself or set when the job is queued.

# Define the maximum execution time for every execution of a job type
class ExampleJob < Cuetip::Job
  self.maximum_execution_time = 1.hour
end

# Define the maximum execution time for a specific job
ExampleJob.queue do |job|
  job.maximum_execution_time = 12.minutes
end

TTL

You can specify a TTL on jobs which means that they won't be executed if they aren't run within a certain period from when they were queued.

# Define the TTL for every execution of a job type
class ExampleJob < Cuetip::Job
  self.ttl = 10.minutes
end

# Define the TTL for a specific job
ExampleJob.queue do |job|
  job.ttl = 10.seconds
end

Workers

To run a Cuetip worker you can use the cuptip executable that is provided. You should pass it a configuration file that will be required when it starts. This will need to require your application's environment.

$ bundle exec cuetip -c config/cuetip.rb

You can run as many workers as you wish however the more that you run the more polling queries will be sent to your database.

Testing

In order to unit test a Cuetip::Job's instance methods (such as #perform), it first needs to be instanciated passing in an instance of Cuetip::Models::Job. This is best done with a tesing double:

RSpec

subject(:job) { JobClass.new(job_model) }

let(:job_model) { instance_double('Cuetip::Models::Job') }

describe '#perform' do
  it 'does something' do
    job.perform

    # add expectaions here
  end
end