README.markdown in tennis-jobs-0.3.1 vs README.markdown in tennis-jobs-0.4.0
- old
+ new
@@ -1,207 +1,76 @@
-This small library is intended to help creating asynchronous jobs
-using Ruby and RabbitMQ via the Sneakers gem.
+This is a celluloid based background jobs library heavily inspired by [Sidekiq][sidekiq].
+The difference is that it allows you to change the backend, Redis, to other ones like RabitMQ.
+You can start with something _à la_ [sucker_punch][sucker_punch]: background jobs threaded within the application process
+and switch to separated processes later using another backend.
<a target="_blank" href="https://travis-ci.org/nicoolas25/tennis"><img src="https://travis-ci.org/nicoolas25/tennis.svg?branch=master" /></a>
<a target="_blank" href="https://codeclimate.com/github/nicoolas25/tennis"><img src="https://codeclimate.com/github/nicoolas25/tennis/badges/gpa.svg" /></a>
<a target="_blank" href="https://codeclimate.com/github/nicoolas25/tennis/coverage"><img src="https://codeclimate.com/github/nicoolas25/tennis/badges/coverage.svg" /></a>
<a target="_blank" href="https://rubygems.org/gems/tennis-jobs"><img src="https://badge.fury.io/rb/tennis-jobs.svg" /></a>
-## Features
-
-- Hooks: `.before(symbol, &block)`
-- Serializers: `.serialize(loader:)`
-- Helpers for defering method calls: `object.defer.method(*arguments)`
-
-**Extra**
-
-- A `Tennis::Serializer::Generic` handling classes and ActiveRecord objects
-
## Configuration
-The background job require a group of processes to handle the tasks you want to
-do asynchronously. Tennis uses YAML configuration file in order to launch thoses
-processes.
+Install the gem in your Gemfile:
-``` yaml
-# tennis.conf.yml
-group1:
- exchange: "default"
- workers: 1
- classes:
- - "Scope::MyClass"
- - "Scope::Model"
-group2:
- exchange: "important"
- workers: 10
- classes:
- - "Only::ImportantWorker"
-```
-
-Here we see two groups of worker. Each group can be launch with the `tennis`
-command:
-
- $ bundle exec tennis group1
-
-The `workers` options is directly given to sneakers, it will determine the
-number of subprocesses that will handle the messages, the level of parallelism.
-
-The classes are the classes that will receive your `send_work` or `defer` calls
-but we'll see that later...
-
-Also it is possible to add options directly in your workers:
-
``` ruby
-module WorkerHelpers
- BeforeFork = -> { ActiveRecord::Base.connection_pool.disconnect! rescue nil }
- AfterFork = -> { ActiveRecord::Base.establish_connection }
-end
-
-class MyClass
- include Tennis::Worker::Generic
-
- set_option :before_fork, WorkerHelpers::BeforeFork
- set_option :after_fork, WorkerHelpers::AfterFork
- set_option :handler, Sneakers::Handlers::MaxretryWithoutErrors
-
- work do |message|
- MyActiveRecordModel.create(message: message)
- end
-end
+gem "tennis-jobs"
+gem "tennis-jobs-redis" # Not available at the moment
```
-In this example I use constants to store the Proc options. This is because
-having different options for the workers of a same group isn't possible. By
-using this constant, I can have another worker with those same options and put
-it in the same group.
+Configure Tennis in your `config/application.rb` (or any other file):
-## Examples
-
-Those examples are what we wish to achieve.
-
-The name of the queue is the name of the class by default and can be reset
-using `set_option :queue_name, "your-queue-name"`.
-
-### Hooks
-
``` ruby
-class MyClass
- include Tennis::Worker::Generic
+Tennis.configure do |config|
+ config.backend Tennis::Backend::Redis.new(redis_url)
- before do
- puts "Before processing"
- end
-
- work do |message|
- puts "Working with #{message}"
- ack!
- end
+ # require "logger"
+ # config.logger = Logger.new(STDOUT)
end
-
-MyClass.send_work("my class")
-# => Before processing
-# => Working with my class
```
-### Serializers
+Start tennis from the command line:
-You can provide a Proc for the loader and/or the dumper keywords.
-The dumper will be used when calling `MyClass.send_work(message)` receiving
-the `message` as argument. It should return a string. The loader will be
-used when the message is poped from the RabbitMQ queue.
-
-``` ruby
-class MyClass
- include Tennis::Worker::Generic
-
- serialize loader: ->(message){ JSON.parse(message) },
- dumper: ->(message){ JSON.generate(message) }
-
- work do |message|
- one, two = message
- puts "Message is serialized and deserialized correctly"
- puts "one: #{one}, two: #{two}"
- ack!
- end
-end
-
-MyClass.send_work([1, "foo"])
-# => Message is serialized and deserialized correctly
-# => one: 1, two: foo
```
+bundle exec tennis --concurrency 4 --require ./config/application.rb --jobs "MyJob,MyOtherJob"
-``` ruby
-class MyClass
- include Tennis::Worker::Generic
-
- serialize Tennis::Serializer::Generic.new
-
- work do |message|
- klass, active_record_object = message
- puts "Classes can be passed: #{klass.name} - #{klass.class}"
- puts "Active record object can be passed too: #{active_record_object}"
- ack!
- end
-end
-
-MyClass.send_work([String, User.find(1)])
-# => Classes can be passed: String - Class
-# => Active record object can be passed too: <User#1 ...>
+# There is also a shorter equivalent:
+# bundle exex tennis -c 4 -r ./config/application.rb -j "MyJob,MyOtherJob"
```
-### Helpers
+## Usage
-Any class method can be defered:
-
``` ruby
-class MyClass
- include Tennis::Worker::Deferable
+MINUTES = 60
- def self.my_method(user)
- puts "Running my method on #{user}"
+class MyJob
+ include Tennis::Job
+
+ def my_method(*args)
+ puts "=> #{args}.sum = args.inject(0, &:+)"
end
end
-MyClass.defer.my_method(User.find(1))
-# => Running my method on <User#1 ...>
-```
+my_job_instance = MyJob.new
+my_job_instance.async.my_method(1, 2, 3)
-An ActiveRecord::Base instance can be the receiver if it has an `id`:
+# Will print in your `tennis` process:
+# => [1, 2, 3].sum = 6
-``` ruby
-class MyModel < ActiveRecord::Base
- include Tennis::Worker::Deferable
+my_job_instance.async_in(2 * MINUTES).my_method(4, 5, 6)
- def my_method
- puts "Running my method on #{self}"
- end
-end
-
-instance = MyModel.find(1)
-instance.defer.my_method
-# => Running my method on <MyModel#1 ...>
+# Will print, in approximatively two minutes, in your `tennis` process:
+# => [4, 5, 6].sum = 15
```
-Handling errors and results for the deferred methods is via `on_error` and
-`on_success` keyword. You must return `ack!` or `reject!` here as in a
-Sneakers' `work` method.
+The `my_method`'s arguments can be quite complex depending on your backend support.
+The same goes for the `MyJob`'s instance.
-``` ruby
-class MyModel < ActiveRecord::Base
- include Tennis::Worker::Deferable
+With the `Tennis::Backend::Memory` backend, you can use anything and it will be kept as it is.
- on_error do |exception|
- puts "I just saved the day handling a #{exception}"
- reject!
- end
+## Testing
- def my_method
- puts "Running my method on #{self}"
- raise StandardError
- end
-end
+This section is waiting to beeing written.
-instance = MyModel.find(1)
-instance.defer.my_method
-# => Running my method on <MyModel#1 ...>
-# => I just saved the day handling a StandardError
-```
+
+[sidekiq]: https://github.com/mperham/sidekiq
+[sucker_punch]: https://github.com/brandonhilkert/sucker_punch