README.md in sidetiq-0.2.0 vs README.md in sidetiq-0.3.0

- old
+ new

@@ -4,12 +4,32 @@ [![Build Status](https://travis-ci.org/tobiassvn/sidetiq.png)](https://travis-ci.org/tobiassvn/sidetiq) [![Dependency Status](https://gemnasium.com/tobiassvn/sidetiq.png)](https://gemnasium.com/tobiassvn/sidetiq) Recurring jobs for [Sidekiq](http://mperham.github.com/sidekiq/). -## DESCRIPTION +Table Of Contents +----------------- + * [Overview](#section_Overview) + * [Dependencies](#section_Dependencies) + * [Installation](#section_Installation) + * [Introduction](#section_Introduction) + * [Backfills](#section_Backfills) + * [Configuration](#section_Configuration) + * [Logging](#section_Configuration_Logging) + * [API](#section_API) + * [Polling](#section_Polling) + * [Known Issues](#section_Known_Issues) + * [Web Extension](#section_Web_Extension) + * [Contribute](#section_Contribute) + * [License](#section_License) + * [Author](#section_Author) + +<a name='section_Overview'></a> +Overview +-------- + Sidetiq provides a simple API for defining recurring workers for Sidekiq. - Flexible DSL based on [ice_cube](http://seejohnrun.github.com/ice_cube/) - High-resolution timer using `clock_gettime(3)` (or `mach_absolute_time()` on @@ -18,37 +38,49 @@ - Sidetiq uses a locking mechanism (based on `setnx` and `pexpire`) internally so Sidetiq clocks can run in each Sidekiq process without interfering with each other (tested with sub-second polling of scheduled jobs by Sidekiq and Sidetiq clock rates above 100hz). -## DEPENDENCIES +Detailed API documentation is available on [rubydoc.info](http://rdoc.info/github/tobiassvn/sidetiq/). +<a name='section_Dependencies'></a> +Dependencies +------------ + - [Sidekiq](http://mperham.github.com/sidekiq/) - [ice_cube](http://seejohnrun.github.com/ice_cube/) -## INSTALLATION +<a name='section_Installation'></a> +Installation +------------ The best way to install Sidetiq is with RubyGems: $ [sudo] gem install sidetiq If you're installing from source, you can use [Bundler](http://gembundler.com/) to pick up all the gems ([more info](http://gembundler.com/bundle_install.html)): $ bundle install -## GETTING STARTED +<a name='section_Introduction'></a> +Introduction +------------ Defining recurring jobs is simple: ```ruby class MyWorker include Sidekiq::Worker include Sidetiq::Schedulable # Daily at midnight tiq { daily } + + def perform + # do stuff ... + end end ``` It also is possible to define multiple scheduling rules for a worker: @@ -62,10 +94,14 @@ yearly(3).month_of_year(:march) # Every second year in February yearly(2).month_of_year(:february) end + + def perform + # do stuff ... + end end ``` Or complex schedules: @@ -74,13 +110,35 @@ include Sidekiq::Worker include Sidetiq::Schedulable # Every other month on the first monday and last tuesday at 12 o'clock. tiq { monthly(2).day_of_week(1 => [1], 2 => [-1]).hour_of_day(12) } + + def perform + # do stuff ... + end end ``` +Additionally, the last and current occurrence time (as a `Float`) can be +passed to the worker simply by adding arguments to `#perform`. Sidetiq +will check the method arity before enqueuing the job: + +```ruby +class MyWorker + include Sidekiq::Worker + include Sidetiq::Schedulable + + tiq { daily } + + # Receive last and current occurrence times. + def perform(last_occurrence, current_occurrence) + # do stuff ... + end +end +``` + To start Sidetiq, simply call `Sidetiq::Clock.start!` in a server specific configuration block: ```ruby Sidekiq.configure_server do |config| @@ -89,13 +147,41 @@ ``` Additionally, Sidetiq includes a middleware that will check if the clock thread is still alive and restart it if necessary. -## CONFIGURATION +<a name='section_Backfills''></a> +Backfills +--------- +In certain cases it is desirable that missed jobs will be enqueued +retroactively, for example when a critical, hourly job isn't run due to +server downtime. To solve this, `#tiq` takes a *backfill* option. If +missing job occurrences have been detected, Sidetiq will then enqueue +the jobs automatically. It will also ensure that the timestamps passed to +`#perform` are as expected: + ```ruby +class MyWorker + include Sidekiq::Worker + include Sidetiq::Schedulable + + tiq backfill: true do + hourly + end + + def perform(last_occurrence, current_occurrence) + # do stuff ... + end +end +``` + +<a name='section_Configuration'></a> +Configuration +------------- + +```ruby Sidetiq.configure do |config| # Thread priority of the clock thread (default: Thread.main.priority as # defined when Sidetiq is loaded). config.priority = 2 @@ -107,23 +193,122 @@ # When `true` uses UTC instead of local times (default: false) config.utc = false end ``` +<a name='section_Configuration_Logging'></a> +### Logging -## NOTES +By default Sidetiq uses Sidekiq's logger. However, this is configuration: +```ruby +Sidetiq.logger = Logger.new(STDOUT) +``` + +The logger should implement Ruby's [Logger API](http://www.ruby-doc.org/stdlib-1.9.3/libdoc/logger/rdoc/Logger.html). + +<a name='section_API'></a> +API +--- + +Sidetiq implements a simple API to support reflection of recurring jobs at +runtime: + +`Sidetiq.schedules` returns a `Hash` with the `Sidekiq::Worker` class as the +key and the Sidetiq::Schedule object as the value: + +```ruby +Sidetiq.schedules +# => { MyWorker => #<Sidetiq::Schedule> } +``` + +`Sidetiq.workers` returns an `Array` of all workers currently tracked by +Sidetiq (workers which include `Sidetiq::Schedulable` and a `.tiq` call): + +```ruby +Sidetiq.workers +# => [MyWorker, AnotherWorker] +``` + +`Sidetiq.scheduled` returns an `Array` of currently scheduled Sidetiq jobs +as `Sidekiq::SortedEntry` (`Sidekiq::Job`) objects. Optionally, it is +possible to pass a block to which each job will be yielded: + +```ruby +Sidetiq.scheduled do |job| + # do stuff ... +end +``` + +This list can further be filtered by passing the worker class to `#scheduled`, +either as a String or the constant itself: + +```ruby +Sidetiq.scheduled(MyWorker) do |job| + # do stuff ... +end +``` + +The same can be done for recurring jobs currently scheduled for retries +(`.retries` wraps `Sidekiq::RetrySet` instead of `Sidekiq::ScheduledSet`): + +```ruby +Sidetiq.retries(MyWorker) do |job| + # do stuff ... +end +``` + +<a name='section_Polling'></a> +Polling +------- + By default Sidekiq uses a 15 second polling interval to check if scheduled jobs are due. If a recurring job has to run more often than that you should lower this value. ```ruby Sidekiq.options[:poll_interval] = 1 ``` -## WEB EXTENSION +More information about this can be found in the +[Sidekiq Wiki](https://github.com/mperham/sidekiq/wiki/Scheduled-Jobs). +<a name='section_Known_Issues'></a> +Known Issues +------------ + +Unfortunately, using ice_cube's interval methods is terribly slow on +start-up (it tends to eat up 100% CPU for quite a while). This is due to it +calculating every possible occurrence since the schedule's start time. The way +around is to avoid using them. + +For example, instead of defining a job that should run every 15 minutes like this: + +```ruby +class MyWorker + include Sidekiq::Worker + include Sidetiq::Schedulable + + tiq { minutely(15) } +end +``` + +It is better to use the more explicit way: + +```ruby +class MyWorker + include Sidekiq::Worker + include Sidetiq::Schedulable + + tiq { hourly.minute_of_hour(0, 15, 30, 45) } +end +``` + +<a name='section_Web_Extension'></a> +Web Extension +------------- + Sidetiq includes an extension for Sidekiq's web interface. It will not be loaded by default, so it will have to be required manually: ```ruby require 'sidetiq/web' @@ -131,11 +316,13 @@ ### SCREENSHOT ![Screenshot](http://f.cl.ly/items/1P2u1v091F3V1n381g2I/Screen%20Shot%202013-02-01%20at%2012.16.17.png) -## CONTRIBUTE +<a name='section_Contribute'></a> +Contribute +---------- If you'd like to contribute to Sidetiq, start by forking my repo on GitHub: [http://github.com/tobiassvn/sidetiq](http://github.com/tobiassvn/sidetiq) @@ -150,8 +337,17 @@ 1. Do not change the version number, I will do that on my end 1. If necessary, rebase your commits into logical chunks, without errors 1. Push the branch up to GitHub 1. Send a pull request to the tobiassvn/sidetiq project. -## LICENSE +<a name='section_License'></a> +License +------- Sidetiq is released under the MIT License. See LICENSE for further details. + +<a name='section_Author'></a> +Author +------ + +Tobias Svensson, [@tobiassvn](https://twitter.com/tobiassvn), [http://github.com/tobiassvn](http://github.com/tobiassvn) +