You are viewing the README of the development version. You can find the README of the latest release (v0.4.0) here.
Branch | Status |
---|---|
Release | |
Development |
- Adapter agnostic scheduling via ActiveJob
- Dynamic management (rather than via predefined configuration)
- Doesn't require its own worker or service
Scheduling is based on time spent between extecutions. This is useful for
- Running jobs constantly without delay in between
- Running jobs again some time after their execution
- Jobs where the execution time might be longer than the recurring timeframe but you don't want to trigger multiple jobs at once
10 minute RecurringActiveJob
recurrence schedule for a 5 minute job means it runs 10 minutes after the previous run finished:
- Run#1 00:00 - 00:05
- Run#2 00:15 - 00:20
As opposed to regular scheduling:
- Run#1 00:00 - 00:05
- Run#2 00:10 - 00:15
resque-scheduler provides regular dynamic scheduling (and more) and with a bit of tweaking it can also support ActiveJob. The drawback being the mandatory dependency on Resque (and therefore Redis) and having to run it as a separate service.
Add this line to your application's Gemfile:
gem 'recurring_active_job'
And then execute:
$ bundle
Or install it yourself as:
$ gem install recurring_active_job
Recurring jobs are stored in the DB therefore we need the following migration:
bin/rails generate migration CreateRecurringActiveJob
*_create_recurring_active_job.rb
def change
create_table :recurring_active_jobs do |t|
t.string :job_id
t.string :provider_job_id
t.boolean :active, default: true, null: false
t.integer :frequency_seconds, default: 600, null: false
t.boolean :auto_delete, default: true, null: false
t.string :last_error
t.text :last_error_details
t.timestamps
end
add_index :recurring_active_jobs, :job_id, unique: true
add_index :recurring_active_jobs, :provider_job_id, unique: true
end
Jobs need to subclass RecurringActiveJob::Base
instead of ActiveJob::Base
:
class MyRecurringJob < RecurringActiveJob::Base
def perform(*args)
puts "hi"
end
end
Create a RecurringActiveJob::Model
record and pass its ID when performing the job:
recurring_active_job = RecurringActiveJob::Model.create!(frequency_seconds: 10)
MyRecurringJob.perform_later(recurring_active_job_id: recurring_active_job.id)
Make sure that the class properly inherits:
describe MyJob
it "is a RecurringActiveJob" do
expect(described_class).to be < RecurringActiveJob::Base
end
end
Add a shared context to be included when testing Recurring jobs:
spec/support/shared_context_for_recurring_active_job.rb
RSpec.shared_context "recurring active job" do
let(:recurring_active_job) { create(:recurring_active_job) }
let(:recurring_active_job_params) { { recurring_active_job_id: recurring_active_job.id } }
before do
allow(RecurringActiveJob::Model).to receive(:find).and_return(recurring_active_job)
end
end
RSpec.describe MyJob do
describe "#perform" do
include_context "recurring active job"
# ...
end
end
RecurringActiveJob
defines the following generic error handling which is required for some features (but raises the original error at the end):
rescue_from(StandardError) do |e|
handle_exception(e)
end
To define your own error handling but keep those features working you can redefine handle_exception
like this:
rescue_from(StandardError) do |e|
handle_exception(e)
end
# ...
def handle_exception(e)
super rescue StandardError
# ...
end
Feedback is appreciated.
I can only tailor this project to fit use-cases I know about - which are usually my own ones. If you find that this might be the right direction to solve your problem too but you find that it's suboptimal or lacks features don't hesitate to contact me.
This gem is developed using the following conventions:
- Bundler's guide for developing a gem
- Better Specs
- Semantic versioning
- RubyGems' guide on gem naming
- RFC memo about key words used to Indicate Requirement Levels
- Bundler improvements
- Minimal dependencies
Bug reports and pull requests are welcome on GitHub at https://github.com/thisismydesign/recurring_active_job.
The gem is available as open source under the terms of the MIT License.