crono 0.6.1 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 64a9cf0a8dfbbb07d720a55e4e8d00fdcf38d792
4
- data.tar.gz: b17baffc9f7f8c8c20ea747ff95003cffc2c0593
3
+ metadata.gz: 88e53a7c4eee894469cb7980928acb90726d65c9
4
+ data.tar.gz: b0cf49ee7f5edfb936271d5ba4cb7f71319e156e
5
5
  SHA512:
6
- metadata.gz: e660b9fc13581744848bfa9efcd70d2350c3f97741118f0b29c15b6c544c2f164fab47324d1bd937ecccf0d2e8426bf344d4b521f9e41236da00b8cb19a38d63
7
- data.tar.gz: b85e7a57c38a82db19827206dc93bc30033107f21b21857d9ef460472b437f54360f761891b268d7549fd002b5e92363e210a950d2a1c434b87b9c326543ae3d
6
+ metadata.gz: 283289e7b9ef4cb6840d55513cbbce57b3c4773e816957e3e5394646c2920f2c50954abd240302c0d0c8dff2f623bc576d12ef682d6c3624e74f6486a7de8842
7
+ data.tar.gz: 5c59231c15eb083f7ca341fdf1d0637cb50cd4ceec8cd05f17661ead5aa68507c664a217598cb1ae858b2ff784058b0fae3db760ffd10ab01fa106916460ea23
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  pkg/*
2
2
  *.gem
3
3
  .bundle
4
+ tmp/*.sqlite3
data/Changes.md CHANGED
@@ -17,3 +17,8 @@
17
17
  -----------
18
18
 
19
19
  - Persist job state to your database.
20
+
21
+ 0.7.0
22
+ -----------
23
+
24
+ - Added simple Web UI
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- crono (0.6.1)
4
+ crono (0.7.0)
5
5
  activejob (~> 4.0)
6
6
  activerecord (~> 4.0)
7
7
  activesupport (~> 4.0)
@@ -27,12 +27,23 @@ GEM
27
27
  tzinfo (~> 1.1)
28
28
  arel (6.0.0)
29
29
  builder (3.2.2)
30
+ byebug (3.5.1)
31
+ columnize (~> 0.8)
32
+ debugger-linecache (~> 1.2)
33
+ slop (~> 3.6)
34
+ columnize (0.9.0)
35
+ debugger-linecache (1.2.0)
30
36
  diff-lcs (1.2.5)
31
37
  globalid (0.3.3)
32
38
  activesupport (>= 4.1.0)
39
+ haml (4.0.6)
40
+ tilt
33
41
  i18n (0.7.0)
34
42
  json (1.8.2)
35
43
  minitest (5.5.1)
44
+ rack (1.6.0)
45
+ rack-protection (1.5.3)
46
+ rack
36
47
  rake (10.4.2)
37
48
  rspec (3.2.0)
38
49
  rspec-core (~> 3.2.0)
@@ -47,8 +58,14 @@ GEM
47
58
  diff-lcs (>= 1.2.0, < 2.0)
48
59
  rspec-support (~> 3.2.0)
49
60
  rspec-support (3.2.2)
61
+ sinatra (1.4.5)
62
+ rack (~> 1.4)
63
+ rack-protection (~> 1.4)
64
+ tilt (~> 1.3, >= 1.3.4)
65
+ slop (3.6.0)
50
66
  sqlite3 (1.3.10)
51
67
  thread_safe (0.3.4)
68
+ tilt (1.4.1)
52
69
  timecop (0.7.3)
53
70
  tzinfo (1.2.2)
54
71
  thread_safe (~> 0.1)
@@ -58,8 +75,11 @@ PLATFORMS
58
75
 
59
76
  DEPENDENCIES
60
77
  bundler (>= 1.0.0)
78
+ byebug
61
79
  crono!
80
+ haml
62
81
  rake (~> 10.0)
63
82
  rspec (~> 3.0)
83
+ sinatra
64
84
  sqlite3
65
85
  timecop (~> 0.7)
data/README.md CHANGED
@@ -13,6 +13,7 @@ Crono is a time-based background job scheduler daemon (just like Cron) for Ruby
13
13
 
14
14
  Currently there is no such thing as Cron in Ruby for Rails. Well, there's [Whenever](https://github.com/javan/whenever) but it works on top of Unix Cron, so you have no total control of it from Ruby. Crono is pure Ruby. It doesn't use Unix Cron and other platform-dependent things. So you can use it on all platforms supported by Ruby. It persists job state to your database using Active Record. You have full control of jobs performing process. You have Ruby code, so you can understand and modify it to fit your needs.
15
15
 
16
+ ![Web UI](https://github.com/plashchynski/crono/raw/master/examples/crono_web_ui.png)
16
17
 
17
18
  ## Requirements
18
19
 
@@ -24,7 +25,9 @@ Other versions are untested but might work fine.
24
25
 
25
26
  Add the following line to your application's Gemfile:
26
27
 
27
- gem 'crono'
28
+ ```ruby
29
+ gem 'crono'
30
+ ```
28
31
 
29
32
  Run the `bundle` command to install it.
30
33
  After you install Crono, you can run the generator:
@@ -47,40 +50,48 @@ Crono can use Active Job jobs from `app/jobs/`. The only requirements is that th
47
50
 
48
51
  Here's an example of a test job:
49
52
 
50
- # app/jobs/test_job.rb
51
- class TestJob < ActiveJob::Base
52
- def perform
53
- # put you scheduled code here
54
- # Comments.deleted.clean_up...
55
- end
56
- end
53
+ ```ruby
54
+ # app/jobs/test_job.rb
55
+ class TestJob < ActiveJob::Base
56
+ def perform
57
+ # put you scheduled code here
58
+ # Comments.deleted.clean_up...
59
+ end
60
+ end
61
+ ```
57
62
 
58
63
  The ActiveJob jobs is convenient because you can use one job in both periodic and enqueued ways. But Active Job is not required. Any class can be used as a crono job if it implements a method `perform` without arguments:
59
64
 
60
- class TestJob # This is not an Active Job job, but pretty legal Crono job.
61
- def perform
62
- # put you scheduled code here
63
- # Comments.deleted.clean_up...
64
- end
65
- end
66
-
65
+ ```ruby
66
+ class TestJob # This is not an Active Job job, but pretty legal Crono job.
67
+ def perform
68
+ # put you scheduled code here
69
+ # Comments.deleted.clean_up...
70
+ end
71
+ end
72
+ ```
67
73
 
68
74
  #### Job Schedule
69
75
 
70
76
  The schedule described in the configuration file `config/cronotab.rb`, that created using `crono:install` or manually. The semantic is pretty straightforward:
71
77
 
72
- # config/cronotab.rb
73
- Crono.perform(TestJob).every 2.days, at: "15:30"
78
+ ```ruby
79
+ # config/cronotab.rb
80
+ Crono.perform(TestJob).every 2.days, at: "15:30"
81
+ ```
74
82
 
75
83
  You can schedule one job a few times, if you want a job to be performed a few times a day:
76
84
 
77
- Crono.perform(TestJob).every 1.day, at: "00:00"
78
- Crono.perform(TestJob).every 1.day, at: "12:00"
85
+ ```ruby
86
+ Crono.perform(TestJob).every 1.day, at: "00:00"
87
+ Crono.perform(TestJob).every 1.day, at: "12:00"
88
+ ```
79
89
 
80
90
  The `at` can be a Hash:
81
91
 
82
- Crono.perform(TestJob).every 1.day, at: {hour: 12, min: 15}
83
-
92
+ ```ruby
93
+ Crono.perform(TestJob).every 1.day, at: {hour: 12, min: 15}
94
+ ```
84
95
 
85
96
  #### Run daemon
86
97
 
@@ -98,6 +109,28 @@ Usage: crono [options]
98
109
  -e, --environment ENV Application environment (Default: development)
99
110
  ```
100
111
 
112
+ ## Web UI
113
+
114
+ Crono comes with a Sinatra application that can display the current state of Crono jobs.
115
+ Add `sinatra` and `haml` to your Gemfile
116
+
117
+ ```ruby
118
+ gam 'haml'
119
+ gem 'sinatra', require: nil
120
+ ```
121
+
122
+ Add the following to your `config/routes.rb`:
123
+
124
+ ```ruby
125
+ require 'crono/web'
126
+
127
+ Rails.application.routes.draw do
128
+ mount Crono::Web, at: '/crono'
129
+ ...
130
+ ```
131
+
132
+ Access management and other questions described in the [wiki](https://github.com/plashchynski/crono/wiki/Web-UI).
133
+
101
134
  ## Capistrano
102
135
 
103
136
  Use the `capistrano-crono` gem ([github](https://github.com/plashchynski/capistrano-crono/)).
@@ -21,6 +21,9 @@ Gem::Specification.new do |s|
21
21
  s.add_development_dependency "rspec", "~> 3.0"
22
22
  s.add_development_dependency "timecop", "~> 0.7"
23
23
  s.add_development_dependency "sqlite3"
24
+ s.add_development_dependency "byebug"
25
+ s.add_development_dependency "sinatra"
26
+ s.add_development_dependency "haml"
24
27
 
25
28
  s.files = `git ls-files`.split("\n")
26
29
  s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact
Binary file
@@ -1,15 +1,15 @@
1
- # cronotab.rb — Crono configuration example file
1
+ # cronotab.rb — Crono configuration file
2
2
  #
3
- # Here you can specify periodic jobs and their schedule.
4
- # You can specify a periodic job as a ActiveJob class in `app/jobs/`
5
- # Actually you can use any class. The only requirement is that
6
- # the class should implement a method `perform` without arguments.
3
+ # Here you can specify periodic jobs and schedule.
4
+ # You can use ActiveJob's jobs from `app/jobs/`
5
+ # You can use any class. The only requirement is that
6
+ # class should have a method `perform` without arguments.
7
7
  #
8
-
9
8
  class TestJob
10
9
  def perform
11
10
  puts "Test!"
12
11
  end
13
12
  end
14
13
 
15
- Crono.perform(TestJob).every 5.second
14
+ Crono.perform(TestJob).every 2.days, at: "15:30"
15
+
@@ -56,7 +56,7 @@ module Crono
56
56
 
57
57
  logger.info "Jobs:"
58
58
  Crono.scheduler.jobs.each do |job|
59
- logger.info job.description
59
+ logger.info %{"#{job.performer}" with rule "#{job.period.description}" next time will perform at #{job.next}}
60
60
  end
61
61
  end
62
62
 
@@ -75,7 +75,6 @@ module Crono
75
75
  end
76
76
 
77
77
  def start_working_loop
78
- Thread.abort_on_exception = true
79
78
  while job = Crono.scheduler.next do
80
79
  sleep(job.next - Time.now)
81
80
  job.perform
@@ -1,3 +1,6 @@
1
+ require 'stringio'
2
+ require 'logger'
3
+
1
4
  module Crono
2
5
  class Job
3
6
  include Logging
@@ -5,9 +8,14 @@ module Crono
5
8
  attr_accessor :performer
6
9
  attr_accessor :period
7
10
  attr_accessor :last_performed_at
11
+ attr_accessor :job_log
12
+ attr_accessor :job_logger
8
13
 
9
14
  def initialize(performer, period)
10
15
  self.performer, self.period = performer, period
16
+ self.job_log = StringIO.new
17
+ self.job_logger = Logger.new(job_log)
18
+ @semaphore = Mutex.new
11
19
  end
12
20
 
13
21
  def next
@@ -24,17 +32,30 @@ module Crono
24
32
  end
25
33
 
26
34
  def perform
27
- logger.info "Perform #{performer}"
35
+ log "Perform #{performer}"
28
36
  self.last_performed_at = Time.now
29
- save
37
+
30
38
  Thread.new do
31
- performer.new.perform
32
- logger.info "Finished #{performer} in %.2f seconds" % (Time.now - last_performed_at)
39
+ begin
40
+ performer.new.perform
41
+ rescue Exception => e
42
+ log "Finished #{performer} in %.2f seconds with error: #{e.message}" % (Time.now - last_performed_at)
43
+ log e.backtrace.join("\n")
44
+ else
45
+ log "Finished #{performer} in %.2f seconds" % (Time.now - last_performed_at)
46
+ ensure
47
+ save
48
+ end
33
49
  end
34
50
  end
35
51
 
36
52
  def save
37
- model.update(last_performed_at: last_performed_at)
53
+ @semaphore.synchronize do
54
+ log = model.reload.log || ""
55
+ log << job_log.string
56
+ job_log.truncate(job_log.rewind)
57
+ model.update(last_performed_at: last_performed_at, log: log)
58
+ end
38
59
  end
39
60
 
40
61
  def load
@@ -42,6 +63,13 @@ module Crono
42
63
  end
43
64
 
44
65
  private
66
+ def log(message)
67
+ @semaphore.synchronize do
68
+ logger.info message
69
+ job_logger.info message
70
+ end
71
+ end
72
+
45
73
  def model
46
74
  @model ||= Crono::CronoJob.find_or_create_by(job_id: job_id)
47
75
  end
@@ -6,8 +6,13 @@ module Crono
6
6
  end
7
7
 
8
8
  def next(since: nil)
9
- since ||= Time.now
10
- @period.since(since).change({hour: @at_hour, min: @at_min}.compact)
9
+ if since.nil?
10
+ @next = Time.now.change(time_atts)
11
+ return @next if @next.future?
12
+ since = Time.now
13
+ end
14
+
15
+ @period.since(since).change(time_atts)
11
16
  end
12
17
 
13
18
  def description
@@ -27,5 +32,10 @@ module Crono
27
32
  raise "Unknown 'at' format"
28
33
  end
29
34
  end
35
+
36
+ private
37
+ def time_atts
38
+ {hour: @at_hour, min: @at_min}.compact
39
+ end
30
40
  end
31
41
  end
@@ -1,3 +1,3 @@
1
1
  module Crono
2
- VERSION = '0.6.1'
2
+ VERSION = '0.7.0'
3
3
  end
@@ -0,0 +1,20 @@
1
+ require 'haml'
2
+ require 'sinatra/base'
3
+
4
+ module Crono
5
+ class Web < Sinatra::Base
6
+ set :root, File.expand_path(File.dirname(__FILE__) + "/../../web")
7
+ set :public_folder, Proc.new { "#{root}/assets" }
8
+ set :views, Proc.new { "#{root}/views" }
9
+
10
+ get '/' do
11
+ @jobs = Crono::CronoJob.all
12
+ haml :dashboard, format: :html5
13
+ end
14
+
15
+ get '/jobs/:id' do
16
+ @job = Crono::CronoJob.find(params[:id])
17
+ haml :job
18
+ end
19
+ end
20
+ end
@@ -1,9 +1,15 @@
1
1
  # cronotab.rb — Crono configuration file
2
2
  #
3
- # Here you can specify periodic jobs and their schedule.
4
- # You can specify a periodic job as a ActiveJob class in `app/jobs/`
5
- # Actually you can use any class. The only requirement is that
6
- # the class should implement a method `perform` without arguments.
3
+ # Here you can specify periodic jobs and schedule.
4
+ # You can use ActiveJob's jobs from `app/jobs/`
5
+ # You can use any class. The only requirement is that
6
+ # class should have a method `perform` without arguments.
7
+ #
8
+ # class TestJob
9
+ # def perform
10
+ # puts "Test!"
11
+ # end
12
+ # end
7
13
  #
8
14
  # Crono.perform(TestJob).every 2.days, at: "15:30"
9
15
  #
@@ -4,7 +4,7 @@ class CreateCronoJobs < ActiveRecord::Migration
4
4
  t.string :job_id, null: false
5
5
  t.text :log
6
6
  t.datetime :last_performed_at
7
- t.timestamps
7
+ t.timestamps null: false
8
8
  end
9
9
  add_index :crono_jobs, [:job_id], unique: true
10
10
  end
@@ -4,9 +4,16 @@ class TestJob
4
4
  def perform;end
5
5
  end
6
6
 
7
+ class TestFailingJob
8
+ def perform
9
+ raise "Some error"
10
+ end
11
+ end
12
+
7
13
  describe Crono::Job do
8
14
  let(:period) { Crono::Period.new(2.day) }
9
15
  let(:job) { Crono::Job.new(TestJob, period) }
16
+ let(:failing_job) { Crono::Job.new(TestFailingJob, period) }
10
17
 
11
18
  it "should contain performer and period" do
12
19
  expect(job.performer).to be TestJob
@@ -15,14 +22,17 @@ describe Crono::Job do
15
22
 
16
23
  describe "#perform" do
17
24
  it "should run performer in separate thread" do
25
+ expect(job).to receive(:save)
18
26
  thread = job.perform.join
19
27
  expect(thread).to be_stop
28
+ job.send(:model).destroy
20
29
  end
21
30
 
22
- it "should call Job#save after run" do
23
- expect(job).to receive(:save)
24
- job.perform.join
25
- job.send(:model).destroy
31
+ it "should save performin errors to log" do
32
+ thread = failing_job.perform.join
33
+ expect(thread).to be_stop
34
+ saved_log = Crono::CronoJob.find_by(job_id: failing_job.job_id).log
35
+ expect(saved_log).to include "Some error"
26
36
  end
27
37
  end
28
38
 
@@ -43,7 +53,15 @@ describe Crono::Job do
43
53
  job.last_performed_at = Time.now
44
54
  job.save
45
55
  @crono_job = Crono::CronoJob.find_by(job_id: job.job_id)
46
- expect(@crono_job.last_performed_at).to be_eql(job.last_performed_at)
56
+ expect(@crono_job.last_performed_at.utc.to_s).to be_eql job.last_performed_at.utc.to_s
57
+ end
58
+
59
+ it "should save and truncate job log" do
60
+ message = "test message"
61
+ job.send(:log, message)
62
+ job.save
63
+ expect(job.send(:model).reload.log).to include message
64
+ expect(job.job_log.string).to be_empty
47
65
  end
48
66
  end
49
67
 
@@ -53,10 +71,25 @@ describe Crono::Job do
53
71
  job.save
54
72
  end
55
73
 
56
- it "should load info from DB" do
74
+ it "should load last_performed_at from DB" do
57
75
  @job = Crono::Job.new(TestJob, period)
58
76
  @job.load
59
- expect(@job.last_performed_at).to be_eql @saved_last_performed_at
77
+ expect(@job.last_performed_at.utc.to_s).to be_eql @saved_last_performed_at.utc.to_s
78
+ end
79
+ end
80
+
81
+ describe "#log" do
82
+ it "should write log messages to both common and job log" do
83
+ message = "Test message"
84
+ expect(job.logger).to receive(:info).with(message)
85
+ expect(job.job_logger).to receive(:info).with(message)
86
+ job.send(:log, message)
87
+ end
88
+
89
+ it "should write job log to Job#job_log" do
90
+ message = "Test message"
91
+ job.send(:log, message)
92
+ expect(job.job_log.string).to include(message)
60
93
  end
61
94
  end
62
95
  end
@@ -22,12 +22,14 @@ describe Crono::Period do
22
22
  end
23
23
 
24
24
  it "should set time to 'at' time as a string" do
25
- @period = Crono::Period.new(2.day, at: "15:20")
26
- expect(@period.next).to be_eql(2.day.from_now.change(hour: 15, min: 20))
25
+ time = 10.minutes.ago
26
+ @period = Crono::Period.new(2.day, at: [time.hour, time.min].join(':'))
27
+ expect(@period.next).to be_eql(2.day.from_now.change(hour: time.hour, min: time.min))
27
28
  end
28
29
 
29
30
  it "should set time to 'at' time as a hash" do
30
- at = {hour: 18, min: 45}
31
+ time = 10.minutes.ago
32
+ at = {hour: time.hour, min: time.min}
31
33
  @period = Crono::Period.new(2.day, at: at)
32
34
  expect(@period.next).to be_eql(2.day.from_now.change(at))
33
35
  end
@@ -42,6 +44,13 @@ describe Crono::Period do
42
44
  @period = Crono::Period.new(2.day)
43
45
  expect(@period.next(since: 1.day.ago)).to be_eql(1.day.from_now)
44
46
  end
47
+
48
+ it "should return today time if it is first run and not too late" do
49
+ time = 10.minutes.from_now
50
+ at = {hour: time.hour, min: time.min}
51
+ @period = Crono::Period.new(2.day, at: at)
52
+ expect(@period.next).to be_eql(Time.now.change(at))
53
+ end
45
54
  end
46
55
  end
47
56
  end
@@ -8,9 +8,9 @@ describe Crono::Scheduler do
8
8
  before(:each) do
9
9
  @scheduler = Crono::Scheduler.new
10
10
  @jobs = [
11
- Crono::Period.new(3.day, at: "18:55"),
12
- Crono::Period.new(1.day, at: "15:30"),
13
- Crono::Period.new(7.day, at: "06:05")
11
+ Crono::Period.new(3.day, at: 10.minutes.from_now.strftime("%H:%M")),
12
+ Crono::Period.new(1.day, at: 20.minutes.from_now.strftime("%H:%M")),
13
+ Crono::Period.new(7.day, at: 40.minutes.from_now.strftime("%H:%M"))
14
14
  ].map { |period| Crono::Job.new(TestJob, period) }
15
15
  @scheduler.jobs = @jobs
16
16
  end
@@ -25,11 +25,7 @@ describe Crono::Scheduler do
25
25
 
26
26
  describe "#next" do
27
27
  it "should return next job in schedule" do
28
- expect(@scheduler.next).to be @jobs[1]
29
- end
30
-
31
- it "should return next based on last" do
32
- expect(@scheduler.next)
28
+ expect(@scheduler.next).to be @jobs[0]
33
29
  end
34
30
  end
35
31
  end
@@ -2,10 +2,11 @@ require 'bundler/setup'
2
2
  Bundler.setup
3
3
 
4
4
  require 'timecop'
5
+ require 'byebug'
5
6
  require 'crono'
6
7
  require 'generators/crono/install/templates/migrations/create_crono_jobs.rb'
7
8
 
8
- ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: ':memory:')
9
+ ActiveRecord::Base.establish_connection(adapter: 'sqlite3', database: "file::memory:?cache=shared")
9
10
  ActiveRecord::Base.logger = Logger.new(STDOUT)
10
11
  CreateCronoJobs.up
11
12
 
File without changes
@@ -0,0 +1,20 @@
1
+ .container {
2
+ background-color: #CFD8DC;
3
+ }
4
+
5
+ body {
6
+ background-color: #455A64;
7
+ }
8
+
9
+ .page-header {
10
+ border-bottom: 1px solid #B6B6B6;
11
+ }
12
+
13
+ #job_list td,#job_list th {
14
+ border-top: 1px solid #B6B6B6;
15
+ color: #212121;
16
+ }
17
+
18
+ .breadcrumb {
19
+ background-color: #FFFFFF;
20
+ }
@@ -0,0 +1,17 @@
1
+ %ol.breadcrumb
2
+ %li.active Home
3
+
4
+ %h3 Running Jobs
5
+ %table.table#job_list
6
+ %tr
7
+ %th Job
8
+ %th Last performed at
9
+ %th
10
+ - for job in @jobs
11
+ %tr
12
+ %td= job.job_id
13
+ %td= job.last_performed_at || "—"
14
+ %td
15
+ %a{href: url("/jobs/#{job.id}")}
16
+ Log
17
+ %span.glyphicon.glyphicon-menu-right
@@ -0,0 +1,8 @@
1
+ %ol.breadcrumb
2
+ %li
3
+ %a{href: url("/")} Home
4
+ %li.active= @job.job_id
5
+
6
+ %h2
7
+ "#{@job.job_id}" Log:
8
+ %pre= @job.log
@@ -0,0 +1,25 @@
1
+ !!! 5
2
+ %html{lang: "en"}
3
+ %head
4
+ %meta{charset: "utf-8"}
5
+ %meta{"http-equiv" => "X-UA-Compatible", content: "IE=edge"}
6
+ %meta{name: "viewport", content: "width=device-width, initial-scale=1"}
7
+
8
+ %title Crono Dashboard
9
+
10
+ %link{href: "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css", rel: "stylesheet"}
11
+ %link{href: "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap-theme.min.css", rel: "stylesheet"}
12
+ %link{href: "#{env['SCRIPT_NAME']}/custom.css", rel: "stylesheet"}
13
+
14
+ %body
15
+ %br
16
+ %br
17
+ .container
18
+ .page-header
19
+ %h1
20
+ Crono #{Crono::VERSION}
21
+ %small Dashboard
22
+ = yield
23
+
24
+ %script{src: "https://ajax.googleapis.com/ajax/libs/jquery/1.11.2/jquery.min.js"}
25
+ %script{src: "https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"}
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: crono
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.7.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dzmitry Plashchynski
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-06 00:00:00.000000000 Z
11
+ date: 2015-03-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob
@@ -122,6 +122,48 @@ dependencies:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
124
  version: '0'
125
+ - !ruby/object:Gem::Dependency
126
+ name: byebug
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - ">="
130
+ - !ruby/object:Gem::Version
131
+ version: '0'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ - !ruby/object:Gem::Dependency
140
+ name: sinatra
141
+ requirement: !ruby/object:Gem::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: '0'
146
+ type: :development
147
+ prerelease: false
148
+ version_requirements: !ruby/object:Gem::Requirement
149
+ requirements:
150
+ - - ">="
151
+ - !ruby/object:Gem::Version
152
+ version: '0'
153
+ - !ruby/object:Gem::Dependency
154
+ name: haml
155
+ requirement: !ruby/object:Gem::Requirement
156
+ requirements:
157
+ - - ">="
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ type: :development
161
+ prerelease: false
162
+ version_requirements: !ruby/object:Gem::Requirement
163
+ requirements:
164
+ - - ">="
165
+ - !ruby/object:Gem::Version
166
+ version: '0'
125
167
  description: Job scheduler for Rails
126
168
  email:
127
169
  - plashchynski@gmail.com
@@ -142,6 +184,7 @@ files:
142
184
  - Rakefile
143
185
  - bin/crono
144
186
  - crono.gemspec
187
+ - examples/crono_web_ui.png
145
188
  - examples/cronotab.rb
146
189
  - examples/monitrc.conf
147
190
  - lib/crono.rb
@@ -154,6 +197,7 @@ files:
154
197
  - lib/crono/period.rb
155
198
  - lib/crono/scheduler.rb
156
199
  - lib/crono/version.rb
200
+ - lib/crono/web.rb
157
201
  - lib/generators/crono/install/install_generator.rb
158
202
  - lib/generators/crono/install/templates/cronotab.rb.erb
159
203
  - lib/generators/crono/install/templates/migrations/create_crono_jobs.rb
@@ -165,6 +209,11 @@ files:
165
209
  - spec/period_spec.rb
166
210
  - spec/scheduler_spec.rb
167
211
  - spec/spec_helper.rb
212
+ - tmp/.gitkeep
213
+ - web/assets/custom.css
214
+ - web/views/dashboard.haml
215
+ - web/views/job.haml
216
+ - web/views/layout.haml
168
217
  homepage: https://github.com/plashchynski/crono
169
218
  licenses:
170
219
  - Apache-2.0