khronos 0.1.3 → 0.1.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.rspec CHANGED
@@ -1 +1,2 @@
1
1
  --color
2
+ --format d
data/Gemfile CHANGED
@@ -1,6 +1,8 @@
1
1
  source :rubygems
2
2
  gemspec
3
3
 
4
+ gem 'rake'
5
+
4
6
  group :test do
5
7
  gem 'thin'
6
8
  gem 'simplecov', '= 0.6.4'
@@ -13,6 +15,7 @@ group :test do
13
15
  gem "factory_girl", "~> 4.0.0"
14
16
  gem "webmock", "~> 1.8.9"
15
17
  gem "database_cleaner"
18
+ gem 'netrc', '= 0.7.7'
16
19
 
17
20
  #
18
21
  # Used for time functions
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- khronos (0.1.3)
4
+ khronos (0.1.4)
5
5
  activerecord (~> 3.2.8)
6
6
  girl_friday (~> 0.10.0)
7
7
  json (~> 1.7.5)
@@ -63,6 +63,7 @@ GEM
63
63
  rack
64
64
  rack-test (0.6.1)
65
65
  rack (>= 1.0)
66
+ rake (0.9.2.2)
66
67
  rest-client (1.6.8)
67
68
  mime-types (>= 1.16)
68
69
  netrc
@@ -107,8 +108,10 @@ DEPENDENCIES
107
108
  mongo
108
109
  mongoid (~> 3.0.5)
109
110
  mysql2 (~> 0.3.11)
111
+ netrc (= 0.7.7)
110
112
  pg
111
113
  rack-test (~> 0.6.1)
114
+ rake
112
115
  rspec (~> 2.11.0)
113
116
  simplecov (= 0.6.4)
114
117
  sqlite3
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- khronos
1
+ khronos [![Build Status](https://secure.travis-ci.org/endel/khronos.png)](http://travis-ci.org/endel/khronos)
2
2
  ===
3
3
 
4
4
  Simple HTTP-based Job scheduling for the cloud.
@@ -10,7 +10,8 @@ Features
10
10
  - Configure recurrency per request
11
11
  - Log HTTP status code for every request made
12
12
  - Query the database via REST API
13
- - Postgresql, MySQL and SQLite supported. (mongodb will be supported soon)
13
+
14
+ Currently only PostgreSQL is supported. Patches for other databases are welcome.
14
15
 
15
16
  How it works
16
17
  ---
@@ -31,24 +32,24 @@ Create a scheduled task:
31
32
  :task_url => "http://myapp.com/do-something-awesome",
32
33
  :recurrency => 12.hours
33
34
  })
34
- # => "{\"active\":true,\"at\":\"2012-09-15T21:24:56-03:00\",\"context\":\"test\",\"id\":1,\"recurrency\":1,\"task_url\":\"http://myapp.com/do-something-awesome\"}"
35
+ # => {"active":true,"at":"2012-09-15T21:24:56-03:00","context":"test","id":1,"recurrency":1,"task_url":"http://myapp.com/do-something-awesome"}
35
36
 
36
37
  Query for a scheduled task:
37
38
 
38
39
  RestClient.get('http://localhost:3000/task', :params => { :context => 'test' })
39
- # => "{\"active\":true,\"at\":\"2012-09-15T21:24:56-03:00\",\"context\":\"test\",\"id\":1,\"recurrency\":1,\"task_url\":\"http://myapp.com/do-something-awesome\"}"
40
+ # => {"active":true,"at":"2012-09-15T21:24:56-03:00","context":"test","id":1,"recurrency":1,"task_url":"http://myapp.com/do-something-awesome"}
40
41
 
41
42
  Delete a scheduled task by query:
42
43
 
43
44
  RestClient.delete('http://localhost:3000/task', :params => { :status_code => 404 })
44
- # => "{\"deleted\":3}"
45
+ # => {"deleted":3}
45
46
  RestClient.delete('http://localhost:3000/task', :params => { :id => 9 })
46
- # => "{\"deleted\":1}"
47
+ # => {"deleted":1}
47
48
 
48
49
  Query for logs for tasks that already ran.
49
50
 
50
51
  RestClient.get('http://localhost:3000/schedule/logs', :params => { :status_code => 500 })
51
- # => "[{\"id\":3,\"schedule_id\":1,\"started_at\":\"2012-09-15T13:38:48-03:00\",\"status_code\":500},{\"id\":5,\"schedule_id\":2,\"started_at\":\"2012-09-15T13:38:48-03:00\",\"status_code\":500}]"
52
+ # => [{"id":3,"schedule_id":1,"started_at":"2012-09-15T13:38:48-03:00","status_code":500},{"id":5,"schedule_id":2,"started_at":"2012-09-15T13:38:48-03:00","status_code":500}]
52
53
 
53
54
  Note: these examples are using [rest-client](https://github.com/archiloque/rest-client/) and [activesupport](https://github.com/rails/rails/tree/master/activesupport).
54
55
 
data/Rakefile CHANGED
@@ -1,36 +1,20 @@
1
1
  $: << 'lib'
2
2
 
3
+ require 'rake'
3
4
  require 'bundler/setup'
4
5
 
5
6
  ENV['RACK_ENV'] = ENV['ENV'] || 'test'
6
7
  require 'khronos'
7
8
 
8
- def load_migrations!
9
- require 'khronos/storage/adapter/activerecord/migrations/schedule'
10
- require 'khronos/storage/adapter/activerecord/migrations/schedule_log'
11
- end
12
-
13
- namespace :db do
14
-
15
- desc 'Create the database.'
16
- task :create do
17
- adapter = Khronos::Storage::Adapter.get(ENV['KHRONOS_STORAGE'])
18
- if adapter.name =~ /ActiveRecord/
19
- load_migrations!
20
- CreateSchedule.up
21
- CreateScheduleLog.up
22
- end
23
- end
9
+ require "rspec/core/rake_task"
24
10
 
25
- desc 'Destroy entire database.'
26
- task :drop do
27
- adapter = Khronos::Storage::Adapter.get(ENV['KHRONOS_STORAGE'])
28
- if adapter.name =~ /ActiveRecord/
29
- load_migrations!
30
- CreateSchedule.down
31
- CreateScheduleLog.down
32
- end
33
- end
11
+ desc "Run all specs"
12
+ task :spec => ["spec:all"]
34
13
 
14
+ desc "Run unit specs"
15
+ RSpec::Core::RakeTask.new(:'spec:all') do |t|
16
+ t.rspec_opts = ['--colour']
17
+ t.pattern = 'spec/**/*_spec.rb'
35
18
  end
36
19
 
20
+ task :default => :spec
@@ -7,7 +7,6 @@ require 'logger'
7
7
  module Khronos
8
8
  autoload :Config, 'khronos/config'
9
9
  autoload :Logger, 'khronos/logger'
10
- autoload :Scheduler, 'khronos/scheduler'
11
10
 
12
11
  autoload :Storage, 'khronos/storage'
13
12
  autoload :Server, 'khronos/server'
@@ -15,10 +15,12 @@ module Khronos
15
15
  def check_schedule!
16
16
  puts "Checking... #{Time.now}"
17
17
  count = 0
18
- Khronos::Scheduler.fetch(Time.now).each do |schedule|
19
- Khronos::Scheduler.run(schedule, @runner)
18
+
19
+ Storage::Schedule.fetch(Time.now).each do |schedule|
20
+ @runner.enqueue(schedule)
20
21
  count += 1
21
22
  end
23
+
22
24
  puts "Tick. #{count} jobs to run."
23
25
  end
24
26
 
@@ -111,9 +111,8 @@ module Khronos
111
111
  #
112
112
  # @return [Hash] queued
113
113
  post '/task/run' do
114
- schedule = Storage::Schedule.where(:id => params[:id]).first
115
- Khronos::Scheduler.run(schedule) if schedule
116
- {:queued => !schedule.nil?}.to_json
114
+ schedule = Storage::Schedule.where(:id => params[:id]).update_all(:at => Time.now)
115
+ {:queued => schedule}.to_json
117
116
  end
118
117
 
119
118
  # Schedule logs querying interface
@@ -8,7 +8,6 @@ module Khronos
8
8
  raise RuntimeError.new("Please configure 'KHRONOS_STORAGE' on your environment variables.") if uri.nil?
9
9
 
10
10
  @adapter = Adapter.get(uri)
11
- self.migrate! if @adapter.name =~ /ActiveRecord/
12
11
  self.class.send(:include, @adapter)
13
12
  end
14
13
 
@@ -24,24 +23,5 @@ module Khronos
24
23
  ScheduleLog.delete_all
25
24
  end
26
25
 
27
- protected
28
-
29
- def migrate!
30
- require 'khronos/storage/adapter/activerecord/migrations/schedule'
31
- require 'khronos/storage/adapter/activerecord/migrations/schedule_log'
32
-
33
- unless ActiveRecord::Base.connection.table_exists?(:schedules)
34
- Adapter::ActiveRecord::CreateSchedule.up
35
- else
36
- Logger.debug "Schedules table already exists."
37
- end
38
-
39
- unless ActiveRecord::Base.connection.table_exists?(:schedule_logs)
40
- Adapter::ActiveRecord::CreateScheduleLog.up
41
- else
42
- Logger.debug "ScheduleLog table already exists."
43
- end
44
- end
45
-
46
26
  end
47
27
  end
@@ -29,14 +29,10 @@ module Khronos
29
29
  def self.get(url)
30
30
  uri = parse_uri(url)
31
31
  framework = @frameworks[uri[:scheme]]
32
-
33
32
  require "khronos/storage/adapter/#{framework}"
34
33
 
35
34
  # Get and connect with the adapter class.
36
- adapter = const_get(@classes[framework])
37
-
38
- # uri.merge(:adapter => @adapters[uri[:scheme]] || uri[:scheme])
39
- adapter.connect!(url)
35
+ const_get(@classes[framework]).connect!(url)
40
36
  end
41
37
 
42
38
  end
@@ -10,25 +10,33 @@ module Khronos
10
10
  def self.connect!(url)
11
11
  require 'active_record'
12
12
 
13
- #if File.exists?("config/database.yml")
14
- #::ActiveRecord::Base.establish_connection(YAML.load_file("config/database.yml")[ENV['RACK_ENV']])
15
- #else
16
- ::ActiveRecord::Base.establish_connection(url)
17
- ::ActiveRecord::Base.include_root_in_json = false
18
- #end
19
-
20
- #
21
- # ::ActiveRecord::Base.logger = ::Logger.new(STDOUT)
22
- #
13
+ ::ActiveRecord::Base.establish_connection(url)
14
+ ::ActiveRecord::Base.include_root_in_json = false
23
15
  self
24
16
  end
25
17
 
26
18
  def self.included(base)
27
- #puts "included in #{base}"
19
+ self.migrate!
28
20
  end
29
21
 
30
- def self.extended(base)
31
- #puts "extended in #{base.inspect}"
22
+
23
+ protected
24
+
25
+ def self.migrate!
26
+ require 'khronos/storage/adapter/activerecord/migrations/schedule'
27
+ require 'khronos/storage/adapter/activerecord/migrations/schedule_log'
28
+
29
+ unless ::ActiveRecord::Base.connection.table_exists?(:schedules)
30
+ ActiveRecord::CreateSchedule.up
31
+ else
32
+ Logger.debug "Schedules table already exists."
33
+ end
34
+
35
+ unless ::ActiveRecord::Base.connection.table_exists?(:schedule_logs)
36
+ ActiveRecord::CreateScheduleLog.up
37
+ else
38
+ Logger.debug "ScheduleLog table already exists."
39
+ end
32
40
  end
33
41
 
34
42
  end
@@ -9,6 +9,14 @@ module Khronos
9
9
  attr_accessible :context, :at, :recurrency, :task_url, :callbacks, :active
10
10
  has_many :logs, :class_name => ScheduleLog
11
11
 
12
+ class << self
13
+ def fetch(time)
14
+ self.find_by_sql([
15
+ "UPDATE #{self.table_name} SET active = false WHERE at <= ? AND active = true RETURNING *", time
16
+ ])
17
+ end
18
+ end
19
+
12
20
  def callbacks=(options)
13
21
  write_attribute(:callbacks, options.to_json)
14
22
  end
@@ -1,3 +1,3 @@
1
1
  module Khronos
2
- VERSION = '0.1.3'
2
+ VERSION = '0.1.4'
3
3
  end
@@ -31,7 +31,7 @@ describe Khronos::Storage do
31
31
  Khronos::Storage::Schedule.last.task_url.should == "http://some-service.com/task"
32
32
  end
33
33
 
34
- it "should identify activerecord adapter for sqlite3" do
34
+ xit "should identify activerecord adapter for sqlite3" do
35
35
  client = subject.new('sqlite3://localhost/spec/tmp/sqlite3.db')
36
36
  Khronos::Storage::Schedule.should == Khronos::Storage::Adapter::ActiveRecord::Schedule
37
37
  Khronos::Storage::ScheduleLog.should == Khronos::Storage::Adapter::ActiveRecord::ScheduleLog
@@ -0,0 +1,46 @@
1
+ require 'spec_helper'
2
+
3
+ describe Khronos::Storage do
4
+ subject { Khronos::Storage::Schedule }
5
+ let(:schedule) { subject }
6
+
7
+ before(:all) do
8
+ ENV['KHRONOS_STORAGE'] = 'postgresql://localhost:5432/khronos'
9
+
10
+ @storage = Khronos::Storage.new
11
+ @storage.truncate!
12
+
13
+ load_factory_girl!
14
+ end
15
+
16
+ it "fetch schedules by time" do
17
+ FactoryGirl.create(:schedule, :at => 1.minutes.from_now)
18
+ schedule.fetch(1.minutes.from_now).length.should == 1
19
+
20
+ FactoryGirl.create(:schedule, :at => 1.minutes.from_now)
21
+ FactoryGirl.create(:schedule, :at => 5.minutes.from_now)
22
+ schedule.fetch(5.minutes.from_now).length.should == 2
23
+
24
+ FactoryGirl.create(:schedule, :at => 1.minutes.from_now)
25
+ FactoryGirl.create(:schedule, :at => 5.minutes.from_now)
26
+ FactoryGirl.create(:schedule, :at => 10.minutes.from_now)
27
+ schedule.fetch(10.minutes.from_now).length.should == 3
28
+
29
+ FactoryGirl.create(:schedule, :at => 1.minutes.from_now)
30
+ FactoryGirl.create(:schedule, :at => 5.minutes.from_now)
31
+ FactoryGirl.create(:schedule, :at => 10.minutes.from_now)
32
+ FactoryGirl.create(:schedule, :at => 30.minutes.from_now)
33
+ schedule.fetch(30.minutes.from_now).length.should == 4
34
+
35
+ FactoryGirl.create(:schedule, :at => 1.minutes.from_now)
36
+ FactoryGirl.create(:schedule, :at => 5.minutes.from_now)
37
+ FactoryGirl.create(:schedule, :at => 10.minutes.from_now)
38
+ FactoryGirl.create(:schedule, :at => 30.minutes.from_now)
39
+ FactoryGirl.create(:schedule, :at => 60.minutes.from_now)
40
+ schedule.fetch(60.minutes.from_now).length.should == 5
41
+
42
+ schedule.fetch(60.minutes.from_now).length.should == 0
43
+ end
44
+
45
+ end
46
+
@@ -44,7 +44,7 @@ describe Khronos::Server::Scheduler do
44
44
  dummy_schedule = FactoryGirl.create(:schedule)
45
45
  post('/task/run', :id => dummy_schedule.id)
46
46
  last_response.status.should == 200
47
- JSON.parse(last_response.body).should == {'queued' => true}
47
+ JSON.parse(last_response.body).should == {'queued' => 1}
48
48
  end
49
49
 
50
50
  it "should update schedule data" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: khronos
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.1.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-16 00:00:00.000000000 Z
12
+ date: 2012-09-28 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: sinatra
@@ -165,7 +165,6 @@ files:
165
165
  - lib/khronos.rb
166
166
  - lib/khronos/config.rb
167
167
  - lib/khronos/logger.rb
168
- - lib/khronos/scheduler.rb
169
168
  - lib/khronos/server.rb
170
169
  - lib/khronos/server/controller.rb
171
170
  - lib/khronos/server/runner.rb
@@ -189,7 +188,7 @@ files:
189
188
  - spec/functional/adapters_spec.rb
190
189
  - spec/functional/controller_spec.rb
191
190
  - spec/functional/misc_spec.rb
192
- - spec/functional/scheduler_spec.rb
191
+ - spec/functional/storage_spec.rb
193
192
  - spec/integration/runner_server_spec.rb
194
193
  - spec/integration/scheduler_server_spec.rb
195
194
  - spec/spec_helper.rb
@@ -224,7 +223,7 @@ test_files:
224
223
  - spec/functional/adapters_spec.rb
225
224
  - spec/functional/controller_spec.rb
226
225
  - spec/functional/misc_spec.rb
227
- - spec/functional/scheduler_spec.rb
226
+ - spec/functional/storage_spec.rb
228
227
  - spec/integration/runner_server_spec.rb
229
228
  - spec/integration/scheduler_server_spec.rb
230
229
  - spec/spec_helper.rb
@@ -1,19 +0,0 @@
1
- require 'socket'
2
- require 'json'
3
-
4
- module Khronos
5
- class Scheduler
6
-
7
- def self.run(schedule, runner=nil)
8
- schedule.update_attributes(:active => false)
9
- schedule.save
10
- runner.enqueue(schedule) if runner
11
- end
12
-
13
- def self.fetch(target_time=Time.now)
14
- Storage::Schedule.where(['at <= ?', target_time]).where(:active => true)
15
- end
16
-
17
- end
18
- end
19
-
@@ -1,30 +0,0 @@
1
- require 'spec_helper'
2
-
3
- describe Khronos::Scheduler do
4
- subject { Khronos::Scheduler }
5
- let(:scheduler) { subject }
6
-
7
- before(:all) do
8
- ENV['KHRONOS_STORAGE'] = 'sqlite3://localhost/spec/tmp/scheduler.db'
9
-
10
- @storage = Khronos::Storage.new
11
- @storage.truncate!
12
-
13
- load_factory_girl!
14
- FactoryGirl.create(:schedule, :at => 1.minutes.from_now)
15
- FactoryGirl.create(:schedule, :at => 5.minutes.from_now)
16
- FactoryGirl.create(:schedule, :at => 10.minutes.from_now)
17
- FactoryGirl.create(:schedule, :at => 30.minutes.from_now)
18
- FactoryGirl.create(:schedule, :at => 60.minutes.from_now)
19
- end
20
-
21
- it "fetch schedules by time" do
22
- scheduler.fetch(1.minutes.from_now).length.should == 1
23
- scheduler.fetch(5.minutes.from_now).length.should == 2
24
- scheduler.fetch(10.minutes.from_now).length.should == 3
25
- scheduler.fetch(30.minutes.from_now).length.should == 4
26
- scheduler.fetch(60.minutes.from_now).length.should == 5
27
- end
28
-
29
- end
30
-