Allows one to declaratively supply a block of code to be fired for a resource at a given point in time.
class Course < ActiveRecord::Base
include Chron::Observable
at_time :close_at do
Rails.logger.info "performing task for #{[self.class.to_s, id]}."
Rails.logger.info "self.start_at (#{start_at}) == Time.current (#{Time.current})"
update_column :state, 'closed' # set any state you want for this record
## bake in any conditional business logic required here
end
end
This gem encapsulates the ActiveJob classes required to trigger the above block in the background.
Add this line to your application's Gemfile:
gem 'chron'
And then execute:
$ bundle
Or install it yourself as:
$ gem install chron
To add a new observation, one can simply run
rails g chron:observation Course close_at
which just automates the following boilerplate.
In order to play well with rails autoload, you must tell the poller
about your observable resources and their columns by creating a config/initializers/chron.rb
file.
Chron.configure do
# model name provided as a string to avoid an autoload hit on boot
observe 'Course' do
at :close_at
end
end
Mix Chron::Observable
into ActiveRecord::Base
children that you want to declare observations against.
You can provide an arbitrary block of code to be fired against a given record at the time stored as the value in that column.
class Course < ActiveRecord::Base
include Chron::Observable
at_time :close_at do
do_anything_for_this_resource
# self == self.class.find(id)
# self is an instance whose :close_at is now
# this block gets fired at the :close_at time
end
end
An rspec helper is provided to help you avoid reaching into the internals to test your block. Just provide your block expectations to this matcher.
require 'chron/testing/matchers' # usually goes in `spec_helper.rb`
# in model_spec.rb
describe 'chron blocks' do
it { is_expected.to at_time(:close_at, -> { change(Course.closed, :count).by(1) }) }
end
Chron::Job
will poll observable records and trigger matching observation blocks.
We recommend using the tomykaira/clockwork gem to run the poller.
Clockwork.every(2.minutes, 'chron polling job') { Chron::Job.perform_later }
Continuing the case above, the poller effectively does the following:
- find every record
where(close_at: Time.at(0)...Time.current, close_at__observation_started_at: nil)
- schedule a background job for each record to run provided block on the record
So, of course the actual poller implementation just does this for all of the at_time
declarations that you provide it.
- Open an issue
- Say what's on your mind
- Discuss!
This whole section is here just to invite you to talk.
- Fork it ( https://github.com/[my-github-username]/chron/fork )
- Create your feature branch (
git checkout -b feature/my-stuff
) - Test your stuff with
rspec spec
- Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin HEAD
) - Create a new Pull Request