Concussion

Sucker Punch is an awesome gem which allows in-process background jobs. If you want to run jobs at a particular time, however, there is a downside. Jobs are only held in memory, so restarting the process will kill any pending jobs.

Most web apps will be using some kind of data store however, so Concussion allows them to be persisted.

WARNING

Concussion is currently untested code. It has not been used in production and has no automated test suite. Use at your own risk. I cannot be held responsible for any loss of data, sanity or clients that may result from use of this code.

The interface may also change radically in the following versions.

Currently only Redis can be used as a data store.

The gem has been published mainly as a placeholder.

You have been warned.

Installation

Add this line to your application's Gemfile:

gem 'concussion'

And then execute:

$ bundle

Or install it yourself as:

$ gem install concussion

Usage

Concussion won't do much on its own. It needs to connect to a persistent storage, and for that it needs an adapter. For now it comes bundled with a Redis adapter, but that will be extracted into its own gem in due course.

The adapter is a class with a simple interface, described in the redis adapter class comments.

To use Concussion in a Rails project, add an initializer containing something along the lines of the following code:

# after_initialize is used to allow Redis to initialise first
Rails.application.config.after_initialize do
  namespace = "concussion-persistence"
  redis = Redis.new(:host => "localhost", :port => 6379)
  Concussion.store = Concussion::RedisAdapter.new(redis: redis, namespace: namespace)
  Concussion.init
end

Any jobs which are set to run while the server is offline will run immediately on the initializer being run. For this reason the initializer must be wrapped in an 'after_initialize' block to ensure all other components of the application are ready for use.

You can use the namespace to target a particular server. If you have a two server set-up, for example, the following initializer will ensure that jobs are only run by the server that created them:

require "socket"

Rails.application.config.after_initialize do

  namespace = "concussion-#{Socket.gethostname}"
  redis = Redis.new(:host => "localhost", :port => 6379)
  Concussion.store = Concussion::RedisAdapter.new(redis: redis, namespace: namespace)
  Concussion.init
end

By adding the host name to the namespace, jobs are linked to the particular server.

When defining a job, use the following form:

class DoSomethingJob
  include SuckerPunch::Job
  prepend Concussion::Persist

  def perform(opts = {})
    MyThingDoer.new(opts).do_thing
  end

end

And call it with:

run_at = Time.now + 5.hours
DoSomethingJob.new.async.later run_at, opts

All done.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/chemica/concussion. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

Or something. These words were automatically added to this gem, but they are good words so they can stay.

License

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