diff --git a/examples/cronotab.rb b/examples/cronotab.rb new file mode 100644 index 0000000..17ca1ba --- /dev/null +++ b/examples/cronotab.rb @@ -0,0 +1,15 @@ +# cronotab.rb — Crono configuration example file +# +# Here you can specify periodic jobs and their schedule. +# You can specify a periodic job as a ActiveJob class in `app/jobs/` +# Actually you can use any class. The only requirement is that +# the class should implement a method `perform` without arguments. +# + +class TestJob + def perform + puts "Test!" + end +end + +Crono.perform(TestJob).every 5.second diff --git a/lib/crono.rb b/lib/crono.rb index ccf9ced..f23e1fa 100644 --- a/lib/crono.rb +++ b/lib/crono.rb @@ -4,6 +4,7 @@ end require "active_support/all" require "crono/version.rb" require "crono/period.rb" +require "crono/job.rb" require "crono/schedule.rb" require "crono/config.rb" require "crono/performer_proxy.rb" diff --git a/lib/crono/cli.rb b/lib/crono/cli.rb index bebdf48..974550c 100644 --- a/lib/crono/cli.rb +++ b/lib/crono/cli.rb @@ -3,17 +3,15 @@ require 'optparse' module Crono mattr_accessor :schedule + mattr_accessor :logger class CLI include Singleton attr_accessor :config - attr_accessor :schedule - attr_accessor :logger def initialize self.config = Config.new - self.schedule = Schedule.new - Crono.schedule = schedule + Crono.schedule = Schedule.new end def run @@ -44,12 +42,12 @@ module Crono def init_logger logfile = config.daemonize ? config.logfile : STDOUT - self.logger = Logger.new(logfile) + Crono.logger = Logger.new(logfile) end def print_banner - logger.info "Loading Crono #{Crono::VERSION}" - logger.info "Running in #{RUBY_DESCRIPTION}" + Crono.logger.info "Loading Crono #{Crono::VERSION}" + Crono.logger.info "Running in #{RUBY_DESCRIPTION}" end def load_rails @@ -60,16 +58,11 @@ module Crono require File.expand_path(config.cronotab) end - def run_job(klass) - logger.info "Perform #{klass}" - Thread.new { klass.new.perform } - end - def start_working_loop loop do - klass, time = schedule.next - sleep(time - Time.now) - run_job(klass) + job = Crono.schedule.next + sleep(job.next - Time.now) + job.perform end end diff --git a/lib/crono/job.rb b/lib/crono/job.rb new file mode 100644 index 0000000..ea25c47 --- /dev/null +++ b/lib/crono/job.rb @@ -0,0 +1,19 @@ +module Crono + class Job + attr_accessor :performer + attr_accessor :period + + def initialize(performer, period) + self.performer, self.period = performer, period + end + + def next + period.next + end + + def perform + Crono.logger.info "Perform #{performer}" + Thread.new { performer.new.perform } + end + end +end diff --git a/lib/crono/performer_proxy.rb b/lib/crono/performer_proxy.rb index 5edb3b8..4bab9ac 100644 --- a/lib/crono/performer_proxy.rb +++ b/lib/crono/performer_proxy.rb @@ -6,7 +6,8 @@ module Crono end def every(period, *args) - @schedule.add(@performer, Period.new(period, *args)) + job = Job.new(@performer, Period.new(period, *args)) + @schedule.add(job) end end diff --git a/lib/crono/schedule.rb b/lib/crono/schedule.rb index 1fd7c09..361a51f 100644 --- a/lib/crono/schedule.rb +++ b/lib/crono/schedule.rb @@ -1,20 +1,22 @@ module Crono class Schedule + attr_accessor :schedule + def initialize - @schedule = [] + self.schedule = [] end - def add(peformer, period) - @schedule << [peformer, period] + def add(job) + schedule << job end def next - [queue.first[0], queue.first[1].next] + queue.first end - private + private def queue - @schedule.sort { |a,b| a[1].next <=> b[1].next } + schedule.sort { |a,b| a.next <=> b.next } end end end diff --git a/spec/cli_spec.rb b/spec/cli_spec.rb index 9a6ce0f..b58585d 100644 --- a/spec/cli_spec.rb +++ b/spec/cli_spec.rb @@ -18,13 +18,6 @@ describe Crono::CLI do end end - describe "#run_job" do - it "should run job in separate thread" do - thread = cli.send(:run_job, TestJob).join - expect(thread).to be_stop - end - end - describe "#start_working_loop" do it "should start working loop" end diff --git a/spec/job_spec.rb b/spec/job_spec.rb new file mode 100644 index 0000000..0d93486 --- /dev/null +++ b/spec/job_spec.rb @@ -0,0 +1,22 @@ +require "spec_helper" + +class TestJob + def perform;end +end + +describe Crono::Job do + let(:period) { Crono::Period.new(2.day) } + let(:job) { Crono::Job.new(TestJob, period) } + + it "should contain performer and period" do + expect(job.performer).to be TestJob + expect(job.period).to be period + end + + describe "#perform" do + it "should run performer in separate thread" do + thread = job.perform.join + expect(thread).to be_stop + end + end +end diff --git a/spec/performer_proxy_spec.rb b/spec/performer_proxy_spec.rb index 30e5539..a43bc16 100644 --- a/spec/performer_proxy_spec.rb +++ b/spec/performer_proxy_spec.rb @@ -5,8 +5,8 @@ class TestJob end describe Crono::PerformerProxy do - it "should add job and period to schedule" do - expect(Crono.schedule).to receive(:add).with(TestJob, kind_of(Crono::Period)) + it "should add job to schedule" do + expect(Crono.schedule).to receive(:add).with(kind_of(Crono::Job)) Crono.perform(TestJob).every(2.days, at: "15:30") end end diff --git a/spec/schedule_spec.rb b/spec/schedule_spec.rb index cef32e5..0a9c718 100644 --- a/spec/schedule_spec.rb +++ b/spec/schedule_spec.rb @@ -5,16 +5,23 @@ class TestJob end describe Crono::Schedule do + before(:each) do + @schedule = Crono::Schedule.new + @jobs = [ + Crono::Period.new(3.day, at: "18:55"), + Crono::Period.new(1.day, at: "15:30"), + Crono::Period.new(7.day, at: "06:05") + ].map { |period| Crono::Job.new(TestJob, period) } + @schedule.schedule = @jobs + end + describe "#next" do it "should return next job in schedule" do - @schedule = Crono::Schedule.new - [ - Crono::Period.new(3.day, at: "18:55"), - Crono::Period.new(1.day, at: "15:30"), - Crono::Period.new(7.day, at: "06:05") - ].each { |period| @schedule.add(TestJob, period) } + expect(@schedule.next).to be @jobs[1] + end - expect(@schedule.next).to be_eql([TestJob, 1.day.from_now.change(hour: 15, min: 30)]) + it "should return next based on last" do + expect(@schedule.next) end end end