mirror of
https://github.com/plashchynski/crono.git
synced 2026-01-15 06:43:25 +01:00
Compare commits
33 Commits
v0.8.0
...
v0.8.7.pre
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8f9ff4e34 | ||
|
|
84ac08e5d4 | ||
|
|
e8812b1329 | ||
|
|
f6b393ad6b | ||
|
|
55e3956618 | ||
|
|
50aec2ea87 | ||
|
|
aaa8bc40e5 | ||
|
|
a11a8985c3 | ||
|
|
b4ad8fb953 | ||
|
|
b010b7349f | ||
|
|
cd5813049c | ||
|
|
c74291a001 | ||
|
|
4aeb29891e | ||
|
|
4415211100 | ||
|
|
4b28f3dd80 | ||
|
|
48db3ef245 | ||
|
|
01a761d919 | ||
|
|
75f1b43c84 | ||
|
|
13ab4838e7 | ||
|
|
d075a55f03 | ||
|
|
2d72020ac4 | ||
|
|
cde8a2d214 | ||
|
|
2ec9cfa829 | ||
|
|
63c86c8cd9 | ||
|
|
e10daec9c6 | ||
|
|
f72c288ce8 | ||
|
|
78ce578484 | ||
|
|
0c77c490bd | ||
|
|
d889b9380d | ||
|
|
f75bdf352b | ||
|
|
fa97f573e0 | ||
|
|
dc70212f9d | ||
|
|
7328bea24c |
12
.gitignore
vendored
12
.gitignore
vendored
@@ -1,4 +1,8 @@
|
||||
pkg/*
|
||||
*.gem
|
||||
.bundle
|
||||
tmp/*.sqlite3
|
||||
/.bundle/
|
||||
/.yardoc
|
||||
/_yardoc/
|
||||
/coverage/
|
||||
/doc/
|
||||
/pkg/
|
||||
/spec/reports/
|
||||
/tmp/
|
||||
|
||||
4
Gemfile
4
Gemfile
@@ -1,2 +1,4 @@
|
||||
source "https://rubygems.org"
|
||||
source 'https://rubygems.org'
|
||||
|
||||
# Specify your gem's dependencies in crono.gemspec
|
||||
gemspec
|
||||
|
||||
30
Gemfile.lock
30
Gemfile.lock
@@ -1,7 +1,7 @@
|
||||
PATH
|
||||
remote: .
|
||||
specs:
|
||||
crono (0.8.0)
|
||||
crono (0.8.7.pre)
|
||||
activejob (~> 4.0)
|
||||
activerecord (~> 4.0)
|
||||
activesupport (~> 4.0)
|
||||
@@ -9,17 +9,17 @@ PATH
|
||||
GEM
|
||||
remote: https://rubygems.org/
|
||||
specs:
|
||||
activejob (4.2.0)
|
||||
activesupport (= 4.2.0)
|
||||
activejob (4.2.1)
|
||||
activesupport (= 4.2.1)
|
||||
globalid (>= 0.3.0)
|
||||
activemodel (4.2.0)
|
||||
activesupport (= 4.2.0)
|
||||
activemodel (4.2.1)
|
||||
activesupport (= 4.2.1)
|
||||
builder (~> 3.1)
|
||||
activerecord (4.2.0)
|
||||
activemodel (= 4.2.0)
|
||||
activesupport (= 4.2.0)
|
||||
activerecord (4.2.1)
|
||||
activemodel (= 4.2.1)
|
||||
activesupport (= 4.2.1)
|
||||
arel (~> 6.0)
|
||||
activesupport (4.2.0)
|
||||
activesupport (4.2.1)
|
||||
i18n (~> 0.7)
|
||||
json (~> 1.7, >= 1.7.7)
|
||||
minitest (~> 5.1)
|
||||
@@ -27,14 +27,11 @@ GEM
|
||||
tzinfo (~> 1.1)
|
||||
arel (6.0.0)
|
||||
builder (3.2.2)
|
||||
byebug (3.5.1)
|
||||
columnize (~> 0.8)
|
||||
debugger-linecache (~> 1.2)
|
||||
slop (~> 3.6)
|
||||
byebug (4.0.5)
|
||||
columnize (= 0.9.0)
|
||||
columnize (0.9.0)
|
||||
debugger-linecache (1.2.0)
|
||||
diff-lcs (1.2.5)
|
||||
globalid (0.3.3)
|
||||
globalid (0.3.5)
|
||||
activesupport (>= 4.1.0)
|
||||
haml (4.0.6)
|
||||
tilt
|
||||
@@ -51,7 +48,7 @@ GEM
|
||||
rspec-core (~> 3.2.0)
|
||||
rspec-expectations (~> 3.2.0)
|
||||
rspec-mocks (~> 3.2.0)
|
||||
rspec-core (3.2.1)
|
||||
rspec-core (3.2.2)
|
||||
rspec-support (~> 3.2.0)
|
||||
rspec-expectations (3.2.0)
|
||||
diff-lcs (>= 1.2.0, < 2.0)
|
||||
@@ -64,7 +61,6 @@ GEM
|
||||
rack (~> 1.4)
|
||||
rack-protection (~> 1.4)
|
||||
tilt (~> 1.3, >= 1.3.4)
|
||||
slop (3.6.0)
|
||||
sqlite3 (1.3.10)
|
||||
thread_safe (0.3.5)
|
||||
tilt (1.4.1)
|
||||
|
||||
33
README.md
33
README.md
@@ -49,7 +49,7 @@ Now you are ready to move forward to create a job and schedule it.
|
||||
|
||||
Crono can use Active Job jobs from `app/jobs/`. The only requirements is that the `perform` method should take no arguments.
|
||||
|
||||
Here's an example of a test job:
|
||||
Here's an example of a job:
|
||||
|
||||
```ruby
|
||||
# app/jobs/test_job.rb
|
||||
@@ -72,6 +72,35 @@ class TestJob # This is not an Active Job job, but pretty legal Crono job.
|
||||
end
|
||||
```
|
||||
|
||||
Here's an example of a Rake Task within a job:
|
||||
|
||||
```ruby
|
||||
# config/cronotab.rb
|
||||
require 'rake'
|
||||
# Be sure to change AppName to your application name!
|
||||
AppName::Application.load_tasks
|
||||
|
||||
class Test
|
||||
def perform
|
||||
Rake::Task['crono:hello'].invoke
|
||||
end
|
||||
end
|
||||
|
||||
Crono.perform(Test).every 5.seconds
|
||||
```
|
||||
With the rake task of:
|
||||
```Ruby
|
||||
# lib/tasks/test.rake
|
||||
namespace :crono do
|
||||
desc 'Update all tables'
|
||||
task :hello => :environment do
|
||||
puts "hello"
|
||||
end
|
||||
end
|
||||
```
|
||||
|
||||
_Please note that crono uses threads, so your code should be thread-safe_
|
||||
|
||||
#### Job Schedule
|
||||
|
||||
Schedule list is defined in the file `config/cronotab.rb`, that created using `crono:install`. The semantic is pretty straightforward:
|
||||
@@ -118,7 +147,7 @@ Crono comes with a Sinatra application that can display the current state of Cro
|
||||
Add `sinatra` and `haml` to your Gemfile
|
||||
|
||||
```ruby
|
||||
gam 'haml'
|
||||
gem 'haml'
|
||||
gem 'sinatra', require: nil
|
||||
```
|
||||
|
||||
|
||||
3
Rakefile
3
Rakefile
@@ -1,5 +1,4 @@
|
||||
require 'bundler'
|
||||
Bundler::GemHelper.install_tasks
|
||||
require 'bundler/gem_tasks'
|
||||
|
||||
require 'rspec/core/rake_task'
|
||||
RSpec::Core::RakeTask.new('spec')
|
||||
|
||||
14
bin/console
Executable file
14
bin/console
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require "bundler/setup"
|
||||
require "crono"
|
||||
|
||||
# You can add fixtures and/or initialization code here to make experimenting
|
||||
# with your gem easier. You can also use a different console, if you like.
|
||||
|
||||
# (If you use this, don't forget to add pry to your Gemfile!)
|
||||
# require "pry"
|
||||
# Pry.start
|
||||
|
||||
require "irb"
|
||||
IRB.start
|
||||
7
bin/setup
Normal file
7
bin/setup
Normal file
@@ -0,0 +1,7 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
IFS=$'\n\t'
|
||||
|
||||
bundle install
|
||||
|
||||
# Do any other automated setup that you need to do here
|
||||
@@ -1,32 +1,34 @@
|
||||
# -*- encoding: utf-8 -*-
|
||||
require File.expand_path('../lib/crono/version', __FILE__)
|
||||
# coding: utf-8
|
||||
lib = File.expand_path('../lib', __FILE__)
|
||||
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
||||
require 'crono/version'
|
||||
|
||||
Gem::Specification.new do |s|
|
||||
s.name = 'crono'
|
||||
s.version = Crono::VERSION
|
||||
s.authors = ['Dzmitry Plashchynski']
|
||||
s.email = ['plashchynski@gmail.com']
|
||||
s.homepage = 'https://github.com/plashchynski/crono'
|
||||
s.description = s.summary = 'Job scheduler for Rails'
|
||||
s.license = 'Apache-2.0'
|
||||
Gem::Specification.new do |spec|
|
||||
spec.name = 'crono'
|
||||
spec.version = Crono::VERSION
|
||||
spec.authors = ['Dzmitry Plashchynski']
|
||||
spec.email = ['plashchynski@gmail.com']
|
||||
|
||||
s.required_rubygems_version = '>= 1.3.6'
|
||||
s.rubyforge_project = 'crono'
|
||||
spec.summary = 'Job scheduler for Rails'
|
||||
spec.description = 'A time-based background job scheduler daemon (just like Cron) for Rails'
|
||||
spec.homepage = 'https://github.com/plashchynski/crono'
|
||||
spec.license = 'Apache-2.0'
|
||||
|
||||
s.add_runtime_dependency 'activejob', '~> 4.0'
|
||||
s.add_runtime_dependency 'activesupport', '~> 4.0'
|
||||
s.add_runtime_dependency 'activerecord', '~> 4.0'
|
||||
s.add_development_dependency 'rake', '~> 10.0'
|
||||
s.add_development_dependency 'bundler', '>= 1.0.0'
|
||||
s.add_development_dependency 'rspec', '~> 3.0'
|
||||
s.add_development_dependency 'timecop', '~> 0.7'
|
||||
s.add_development_dependency 'sqlite3'
|
||||
s.add_development_dependency 'byebug'
|
||||
s.add_development_dependency 'sinatra'
|
||||
s.add_development_dependency 'haml'
|
||||
s.add_development_dependency 'rack-test'
|
||||
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
||||
spec.bindir = 'exe' # http://bundler.io/blog/2015/03/20/moving-bins-to-exe.html
|
||||
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
||||
spec.require_paths = ['lib']
|
||||
|
||||
s.files = `git ls-files`.split("\n")
|
||||
s.executables = ['crono']
|
||||
s.require_path = 'lib'
|
||||
spec.add_runtime_dependency 'activejob', '~> 4.0'
|
||||
spec.add_runtime_dependency 'activesupport', '~> 4.0'
|
||||
spec.add_runtime_dependency 'activerecord', '~> 4.0'
|
||||
spec.add_development_dependency 'rake', '~> 10.0'
|
||||
spec.add_development_dependency 'bundler', '>= 1.0.0'
|
||||
spec.add_development_dependency 'rspec', '~> 3.0'
|
||||
spec.add_development_dependency 'timecop', '~> 0.7'
|
||||
spec.add_development_dependency 'sqlite3'
|
||||
spec.add_development_dependency 'byebug'
|
||||
spec.add_development_dependency 'sinatra'
|
||||
spec.add_development_dependency 'haml'
|
||||
spec.add_development_dependency 'rack-test'
|
||||
end
|
||||
|
||||
@@ -11,5 +11,6 @@ require 'crono/scheduler'
|
||||
require 'crono/config'
|
||||
require 'crono/performer_proxy'
|
||||
require 'crono/orm/active_record/crono_job'
|
||||
require 'crono/railtie' if defined?(Rails)
|
||||
|
||||
Crono.autoload :Web, 'crono/web'
|
||||
|
||||
@@ -2,8 +2,6 @@ require 'crono'
|
||||
require 'optparse'
|
||||
|
||||
module Crono
|
||||
mattr_accessor :scheduler
|
||||
|
||||
# Crono::CLI - The main class for the crono daemon exacutable `bin/crono`
|
||||
class CLI
|
||||
include Singleton
|
||||
@@ -33,7 +31,7 @@ module Crono
|
||||
|
||||
def setup_log
|
||||
if config.daemonize
|
||||
self.logifile = config.logfile
|
||||
self.logfile = config.logfile
|
||||
daemonize
|
||||
else
|
||||
self.logfile = STDOUT
|
||||
@@ -52,6 +50,7 @@ module Crono
|
||||
end
|
||||
|
||||
def write_pid
|
||||
return unless config.pidfile
|
||||
pidfile = File.expand_path(config.pidfile)
|
||||
File.write(pidfile, ::Process.pid)
|
||||
end
|
||||
@@ -63,7 +62,7 @@ module Crono
|
||||
logger.info 'Jobs:'
|
||||
Crono.scheduler.jobs.each do |job|
|
||||
logger.info "'#{job.performer}' with rule '#{job.period.description}'"\
|
||||
"next time will perform at #{job.next}"
|
||||
" next time will perform at #{job.next}"
|
||||
end
|
||||
end
|
||||
|
||||
@@ -81,9 +80,10 @@ module Crono
|
||||
end
|
||||
|
||||
def start_working_loop
|
||||
while (job = Crono.scheduler.next)
|
||||
sleep(job.next - Time.now)
|
||||
job.perform
|
||||
loop do
|
||||
next_time, jobs = Crono.scheduler.next_jobs
|
||||
sleep(next_time - Time.now) if next_time > Time.now
|
||||
jobs.each(&:perform)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -10,9 +10,12 @@ module Crono
|
||||
def initialize
|
||||
self.cronotab = CRONOTAB
|
||||
self.logfile = LOGFILE
|
||||
self.pidfile = PIDFILE
|
||||
self.daemonize = false
|
||||
self.environment = ENV['RAILS_ENV'] || ENV['RACK_ENV'] || 'development'
|
||||
end
|
||||
|
||||
def pidfile
|
||||
@pidfile || (daemonize ? PIDFILE : nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -17,8 +17,7 @@ module Crono
|
||||
end
|
||||
|
||||
def next
|
||||
next_time = period.next(since: last_performed_at)
|
||||
next_time.past? ? period.next : next_time
|
||||
period.next(since: last_performed_at)
|
||||
end
|
||||
|
||||
def description
|
||||
|
||||
@@ -5,5 +5,9 @@ module Crono
|
||||
class CronoJob < ActiveRecord::Base
|
||||
self.table_name = 'crono_jobs'
|
||||
validates :job_id, presence: true, uniqueness: true
|
||||
|
||||
def self.outdated
|
||||
self
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
module Crono
|
||||
# Period describe frequency of performing a task
|
||||
# Period describe frequency of jobs
|
||||
class Period
|
||||
DAYS = [:monday, :tuesday, :wednesday, :thursday, :friday, :saturday,
|
||||
:sunday]
|
||||
@@ -14,7 +14,9 @@ module Crono
|
||||
return initial_next unless since
|
||||
@next = @period.since(since)
|
||||
@next = @next.beginning_of_week.advance(days: @on) if @on
|
||||
@next.change(time_atts)
|
||||
@next = @next.change(time_atts)
|
||||
return @next if @next.future?
|
||||
Time.now
|
||||
end
|
||||
|
||||
def description
|
||||
|
||||
9
lib/crono/railtie.rb
Normal file
9
lib/crono/railtie.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
module Crono
|
||||
class Railtie < ::Rails::Railtie
|
||||
rake_tasks do
|
||||
Dir[File.join(File.dirname(__FILE__), '../tasks/*.rake')].each do |file|
|
||||
load file
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -12,14 +12,10 @@ module Crono
|
||||
jobs << job
|
||||
end
|
||||
|
||||
def next
|
||||
queue.first
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def queue
|
||||
jobs.sort_by(&:next)
|
||||
def next_jobs
|
||||
jobs.group_by(&:next).sort_by {|time,_| time }.first
|
||||
end
|
||||
end
|
||||
|
||||
mattr_accessor :scheduler
|
||||
end
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
module Crono
|
||||
VERSION = '0.8.0'
|
||||
VERSION = '0.8.7.pre'
|
||||
end
|
||||
|
||||
26
lib/tasks/crono_tasks.rake
Normal file
26
lib/tasks/crono_tasks.rake
Normal file
@@ -0,0 +1,26 @@
|
||||
module Crono
|
||||
def self.load_cronotab
|
||||
cronotab_path = ENV['CRONOTAB'] || (defined?(Rails) &&
|
||||
File.join(Rails.root, cronotab_path))
|
||||
fail 'No cronotab defined' unless cronotab_path
|
||||
puts "Load cronotab #{cronotab_path}"
|
||||
require cronotab_path
|
||||
end
|
||||
end
|
||||
|
||||
namespace :crono do
|
||||
desc 'Clean unused job stats from DB'
|
||||
task clean: :environment do
|
||||
Crono.scheduler = Crono::Scheduler.new
|
||||
Crono.load_cronotab
|
||||
current_job_ids = Crono.scheduler.jobs.map(&:job_id)
|
||||
Crono::CronoJob.where.not(job_id: current_job_ids).destroy_all
|
||||
end
|
||||
|
||||
desc 'Check cronotab.rb syntax'
|
||||
task check: :environment do
|
||||
Crono.scheduler = Crono::Scheduler.new
|
||||
Crono.load_cronotab
|
||||
puts 'Syntax ok'
|
||||
end
|
||||
end
|
||||
12
spec/assets/bad_cronotab.rb
Normal file
12
spec/assets/bad_cronotab.rb
Normal file
@@ -0,0 +1,12 @@
|
||||
# This is an example of a bad cronotab for tests
|
||||
|
||||
class TestJob
|
||||
def perform
|
||||
puts 'Test!'
|
||||
end
|
||||
end
|
||||
|
||||
# This is an error, because you can use `on` options with
|
||||
# a period less than 7 days.
|
||||
|
||||
Crono.perform(TestJob).every 5.days, on: :sunday
|
||||
9
spec/assets/good_cronotab.rb
Normal file
9
spec/assets/good_cronotab.rb
Normal file
@@ -0,0 +1,9 @@
|
||||
# This is an example of a good cronotab for tests
|
||||
|
||||
class TestJob
|
||||
def perform
|
||||
puts 'Test!'
|
||||
end
|
||||
end
|
||||
|
||||
Crono.perform(TestJob).every 5.seconds
|
||||
@@ -1,11 +1,6 @@
|
||||
require 'spec_helper'
|
||||
require 'crono/cli'
|
||||
|
||||
class TestJob
|
||||
def perform
|
||||
end
|
||||
end
|
||||
|
||||
describe Crono::CLI do
|
||||
let(:cli) { Crono::CLI.instance }
|
||||
|
||||
|
||||
@@ -1,15 +1,42 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Crono::Config do
|
||||
let(:config) { Crono::Config.new }
|
||||
describe '#initialize' do
|
||||
it 'should initialize with default configuration options' do
|
||||
ENV['RAILS_ENV'] = 'test'
|
||||
@config = Crono::Config.new
|
||||
expect(@config.cronotab).to be Crono::Config::CRONOTAB
|
||||
expect(@config.logfile).to be Crono::Config::LOGFILE
|
||||
expect(@config.pidfile).to be Crono::Config::PIDFILE
|
||||
expect(@config.pidfile).to be nil
|
||||
expect(@config.daemonize).to be false
|
||||
expect(@config.environment).to be_eql ENV['RAILS_ENV']
|
||||
end
|
||||
|
||||
describe "#pidfile" do
|
||||
subject(:pidfile) { config.pidfile }
|
||||
|
||||
context "not explicity configured" do
|
||||
context "daemonize is false" do
|
||||
before { config.daemonize = false }
|
||||
|
||||
specify { expect(pidfile).to be_nil }
|
||||
end
|
||||
|
||||
context "daemonize is true" do
|
||||
before { config.daemonize = true }
|
||||
|
||||
specify { expect(pidfile).to eq Crono::Config::PIDFILE }
|
||||
end
|
||||
end
|
||||
|
||||
context "explicity configured" do
|
||||
let(:path) { "foo/bar/pid.pid" }
|
||||
|
||||
before { config.pidfile = path }
|
||||
|
||||
specify { expect(pidfile).to eq path }
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
7
spec/crono_spec.rb
Normal file
7
spec/crono_spec.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe Crono do
|
||||
it 'has a version number' do
|
||||
expect(Crono::VERSION).not_to be nil
|
||||
end
|
||||
end
|
||||
@@ -1,18 +1,7 @@
|
||||
require 'spec_helper'
|
||||
|
||||
class TestJob
|
||||
def perform
|
||||
end
|
||||
end
|
||||
|
||||
class TestFailingJob
|
||||
def perform
|
||||
fail 'Some error'
|
||||
end
|
||||
end
|
||||
|
||||
describe Crono::Job do
|
||||
let(:period) { Crono::Period.new(2.day) }
|
||||
let(:period) { Crono::Period.new(2.day, at: '15:00') }
|
||||
let(:job) { Crono::Job.new(TestJob, period) }
|
||||
let(:failing_job) { Crono::Job.new(TestFailingJob, period) }
|
||||
|
||||
@@ -21,6 +10,12 @@ describe Crono::Job do
|
||||
expect(job.period).to be period
|
||||
end
|
||||
|
||||
describe '#next' do
|
||||
it 'should return next performing time according to period' do
|
||||
expect(job.next).to be_eql period.next
|
||||
end
|
||||
end
|
||||
|
||||
describe '#perform' do
|
||||
after { job.send(:model).destroy }
|
||||
|
||||
@@ -37,11 +32,6 @@ describe Crono::Job do
|
||||
expect(saved_log).to include 'Some error'
|
||||
end
|
||||
|
||||
it 'should set Job#healthy to true if perform ok' do
|
||||
job.perform.join
|
||||
expect(job.healthy).to be true
|
||||
end
|
||||
|
||||
it 'should set Job#healthy to false if perform with error' do
|
||||
failing_job.perform.join
|
||||
expect(failing_job.healthy).to be false
|
||||
@@ -50,7 +40,7 @@ describe Crono::Job do
|
||||
|
||||
describe '#description' do
|
||||
it 'should return job identificator' do
|
||||
expect(job.description).to be_eql('Perform TestJob every 2 days')
|
||||
expect(job.description).to be_eql('Perform TestJob every 2 days at 15:00')
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
require 'spec_helper'
|
||||
|
||||
class TestJob
|
||||
def perform
|
||||
end
|
||||
end
|
||||
|
||||
describe Crono::PerformerProxy do
|
||||
it 'should add job to schedule' do
|
||||
expect(Crono.scheduler).to receive(:add_job).with(kind_of(Crono::Job))
|
||||
|
||||
@@ -53,28 +53,33 @@ describe Crono::Period do
|
||||
end
|
||||
|
||||
context 'in daily basis' do
|
||||
it "should return Time.now if the next time in past" do
|
||||
@period = Crono::Period.new(1.day, at: '06:00')
|
||||
expect(@period.next(since: 2.days.ago)).to be_eql(Time.now)
|
||||
end
|
||||
|
||||
it 'should return the time 2 days from now' do
|
||||
@period = Crono::Period.new(2.day)
|
||||
expect(@period.next).to be_eql(2.day.from_now)
|
||||
expect(@period.next).to be_eql(2.days.from_now)
|
||||
end
|
||||
|
||||
it "should set time to 'at' time as a string" do
|
||||
time = 10.minutes.ago
|
||||
at = [time.hour, time.min].join(':')
|
||||
@period = Crono::Period.new(2.day, at: at)
|
||||
expect(@period.next).to be_eql(2.day.from_now.change(hour: time.hour, min: time.min))
|
||||
@period = Crono::Period.new(2.days, at: at)
|
||||
expect(@period.next).to be_eql(2.days.from_now.change(hour: time.hour, min: time.min))
|
||||
end
|
||||
|
||||
it "should set time to 'at' time as a hash" do
|
||||
time = 10.minutes.ago
|
||||
at = { hour: time.hour, min: time.min }
|
||||
@period = Crono::Period.new(2.day, at: at)
|
||||
expect(@period.next).to be_eql(2.day.from_now.change(at))
|
||||
@period = Crono::Period.new(2.days, at: at)
|
||||
expect(@period.next).to be_eql(2.days.from_now.change(at))
|
||||
end
|
||||
|
||||
it "should raise error when 'at' is wrong" do
|
||||
expect {
|
||||
Crono::Period.new(2.day, at: 1)
|
||||
Crono::Period.new(2.days, at: 1)
|
||||
}.to raise_error("Unknown 'at' format")
|
||||
end
|
||||
|
||||
@@ -85,14 +90,14 @@ describe Crono::Period do
|
||||
end
|
||||
|
||||
it 'should return time in relation to last time' do
|
||||
@period = Crono::Period.new(2.day)
|
||||
@period = Crono::Period.new(2.days)
|
||||
expect(@period.next(since: 1.day.ago)).to be_eql(1.day.from_now)
|
||||
end
|
||||
|
||||
it 'should return today time if it is first run and not too late' do
|
||||
time = 10.minutes.from_now
|
||||
at = { hour: time.hour, min: time.min }
|
||||
@period = Crono::Period.new(2.day, at: at)
|
||||
@period = Crono::Period.new(2.days, at: at)
|
||||
expect(@period.next.utc.to_s).to be_eql(Time.now.change(at).utc.to_s)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,32 +1,38 @@
|
||||
require 'spec_helper'
|
||||
|
||||
class TestJob
|
||||
def perform
|
||||
end
|
||||
end
|
||||
|
||||
describe Crono::Scheduler do
|
||||
before(:each) do
|
||||
@scheduler = Crono::Scheduler.new
|
||||
@jobs = [
|
||||
Crono::Period.new(3.day, at: 10.minutes.from_now.strftime('%H:%M')),
|
||||
Crono::Period.new(1.day, at: 20.minutes.from_now.strftime('%H:%M')),
|
||||
Crono::Period.new(7.day, at: 40.minutes.from_now.strftime('%H:%M'))
|
||||
].map { |period| Crono::Job.new(TestJob, period) }
|
||||
@scheduler.jobs = @jobs
|
||||
end
|
||||
let(:scheduler) { Crono::Scheduler.new }
|
||||
|
||||
describe '#add_job' do
|
||||
it 'should call Job#load on Job' do
|
||||
@job = Crono::Job.new(TestJob, Crono::Period.new(10.day, at: '04:05'))
|
||||
expect(@job).to receive(:load)
|
||||
@scheduler.add_job(@job)
|
||||
scheduler.add_job(@job)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#next' do
|
||||
describe '#next_jobs' do
|
||||
it 'should return next job in schedule' do
|
||||
expect(@scheduler.next).to be @jobs[0]
|
||||
scheduler.jobs = jobs = [
|
||||
Crono::Period.new(3.days, at: 10.minutes.from_now.strftime('%H:%M')),
|
||||
Crono::Period.new(1.day, at: 20.minutes.from_now.strftime('%H:%M')),
|
||||
Crono::Period.new(7.days, at: 40.minutes.from_now.strftime('%H:%M'))
|
||||
].map { |period| Crono::Job.new(TestJob, period) }
|
||||
|
||||
time, jobs = scheduler.next_jobs
|
||||
expect(jobs).to be_eql [jobs[0]]
|
||||
end
|
||||
|
||||
it 'should return an array of jobs scheduled at same time' do
|
||||
time = 5.minutes.from_now
|
||||
scheduler.jobs = jobs = [
|
||||
Crono::Period.new(1.day, at: time.strftime('%H:%M')),
|
||||
Crono::Period.new(1.day, at: time.strftime('%H:%M')),
|
||||
Crono::Period.new(1.day, at: 10.minutes.from_now.strftime('%H:%M'))
|
||||
].map { |period| Crono::Job.new(TestJob, period) }
|
||||
|
||||
time, jobs = scheduler.next_jobs
|
||||
expect(jobs).to be_eql [jobs[0], jobs[1]]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
require 'bundler/setup'
|
||||
Bundler.setup
|
||||
|
||||
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
||||
|
||||
require 'timecop'
|
||||
require 'byebug'
|
||||
require 'crono'
|
||||
@@ -13,3 +15,14 @@ ActiveRecord::Base.establish_connection(
|
||||
|
||||
ActiveRecord::Base.logger = Logger.new(STDOUT)
|
||||
CreateCronoJobs.up
|
||||
|
||||
class TestJob
|
||||
def perform
|
||||
end
|
||||
end
|
||||
|
||||
class TestFailingJob
|
||||
def perform
|
||||
fail 'Some error'
|
||||
end
|
||||
end
|
||||
|
||||
23
spec/tasks/crono_tasks_spec.rb
Normal file
23
spec/tasks/crono_tasks_spec.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
require 'spec_helper'
|
||||
require 'rake'
|
||||
|
||||
load 'tasks/crono_tasks.rake'
|
||||
Rake::Task.define_task(:environment)
|
||||
|
||||
describe 'rake' do
|
||||
describe 'crono:clean' do
|
||||
it 'should clean unused tasks from DB' do
|
||||
Crono::CronoJob.create!(job_id: 'used_job')
|
||||
ENV['CRONOTAB'] = File.expand_path('../../assets/good_cronotab.rb', __FILE__)
|
||||
Rake::Task['crono:clean'].invoke
|
||||
expect(Crono::CronoJob.where(job_id: 'used_job')).not_to exist
|
||||
end
|
||||
end
|
||||
|
||||
describe 'crono:check' do
|
||||
it 'should check cronotab syntax' do
|
||||
ENV['CRONOTAB'] = File.expand_path('../../assets/bad_cronotab.rb', __FILE__)
|
||||
expect { Rake::Task['crono:check'].invoke }.to raise_error
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -6,6 +6,7 @@ describe Crono::Web do
|
||||
let(:app) { Crono::Web }
|
||||
|
||||
before do
|
||||
Crono::CronoJob.destroy_all
|
||||
@test_job_id = 'Perform TestJob every 5 seconds'
|
||||
@test_job_log = 'All runs ok'
|
||||
@test_job = Crono::CronoJob.create!(
|
||||
@@ -28,6 +29,18 @@ describe Crono::Web do
|
||||
get '/'
|
||||
expect(last_response.body).to include 'Error'
|
||||
end
|
||||
|
||||
it 'should show a success mark when a job is healthy' do
|
||||
@test_job.update(healthy: true)
|
||||
get '/'
|
||||
expect(last_response.body).to include 'Success'
|
||||
end
|
||||
|
||||
it 'should show a pending mark when a job is pending' do
|
||||
@test_job.update(healthy: nil)
|
||||
get '/'
|
||||
expect(last_response.body).to include 'Pending'
|
||||
end
|
||||
end
|
||||
|
||||
describe '/job/:id' do
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
%tr
|
||||
%th Job
|
||||
%th Last performed at
|
||||
%th
|
||||
%th Status
|
||||
%th
|
||||
- @jobs.each do |job|
|
||||
%tr
|
||||
@@ -16,6 +16,12 @@
|
||||
- if job.healthy == false
|
||||
%a{ href: url("/job/#{job.id}") }
|
||||
%span.label.label-danger Error
|
||||
- if job.healthy == true
|
||||
%a{ href: url("/job/#{job.id}") }
|
||||
%span.label.label-success Success
|
||||
- else
|
||||
%a{ href: url("/job/#{job.id}") }
|
||||
%span.label.label-default Pending
|
||||
%td
|
||||
%a{ href: url("/job/#{job.id}") }
|
||||
Log
|
||||
|
||||
Reference in New Issue
Block a user