khronos 0.0.0 → 0.0.1.pre1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/.travis.yml +4 -0
- data/Gemfile +18 -7
- data/Rakefile +36 -0
- data/bin/khronos +2 -1
- data/config.ru +9 -1
- data/config/environment.yml +27 -5
- data/{lib/khronos/storage/adapter/mongo/.schedule_log.rb.un~ → db/test.db} +0 -0
- data/khronos.gemspec +10 -7
- data/lib/khronos.rb +4 -7
- data/lib/khronos/config.rb +0 -2
- data/lib/khronos/logger.rb +16 -0
- data/lib/khronos/scheduler.rb +17 -3
- data/lib/khronos/server.rb +4 -31
- data/lib/khronos/server/controller.rb +31 -0
- data/lib/khronos/server/runner.rb +50 -0
- data/lib/khronos/server/scheduler.rb +110 -0
- data/lib/khronos/storage.rb +34 -13
- data/lib/khronos/storage/adapter.rb +44 -0
- data/lib/khronos/storage/adapter/activerecord.rb +39 -0
- data/lib/khronos/storage/adapter/activerecord/migrations/schedule.rb +29 -0
- data/lib/khronos/storage/adapter/activerecord/migrations/schedule_log.rb +23 -0
- data/lib/khronos/storage/adapter/activerecord/schedule.rb +24 -0
- data/lib/khronos/storage/adapter/activerecord/schedule_log.rb +14 -0
- data/lib/khronos/storage/adapter/mongoid.rb +37 -0
- data/lib/khronos/storage/adapter/{mongo → mongoid}/schedule.rb +6 -4
- data/lib/khronos/storage/adapter/{mongo → mongoid}/schedule_log.rb +3 -4
- data/lib/khronos/tasks/db.rake +25 -0
- data/lib/khronos/version.rb +1 -1
- data/server.rb +29 -0
- data/spec/functional/adapters_spec.rb +61 -0
- data/spec/functional/controller_spec.rb +11 -0
- data/spec/functional/scheduler_spec.rb +30 -0
- data/spec/integration/runner_server_spec.rb +26 -0
- data/spec/integration/scheduler_server_spec.rb +70 -0
- data/spec/spec_helper.rb +17 -1
- data/spec/support/factories.rb +12 -0
- data/spec/support/mocks.rb +23 -0
- data/{lib/khronos/storage/adapter/postgres/.schedule.rb.un~ → spec/tmp/scheduler.db} +0 -0
- data/{lib/khronos/.version.rb.swp → spec/tmp/sqlite3.db} +0 -0
- metadata +92 -55
- data/config/.config.yml.un~ +0 -0
- data/config/.environment.yml.un~ +0 -0
- data/config/.redis.yml.un~ +0 -0
- data/config/.storage.yml.un~ +0 -0
- data/lib/.khronos.rb.un~ +0 -0
- data/lib/.scheduler.rb.un~ +0 -0
- data/lib/khronos/.config.rb.un~ +0 -0
- data/lib/khronos/.controller.rb.un~ +0 -0
- data/lib/khronos/.runner.rb.un~ +0 -0
- data/lib/khronos/.schedule.rb.un~ +0 -0
- data/lib/khronos/.scheduler.rb.un~ +0 -0
- data/lib/khronos/.server.rb.un~ +0 -0
- data/lib/khronos/.storage.rb.un~ +0 -0
- data/lib/khronos/.task.rb.un~ +0 -0
- data/lib/khronos/.version.rb.un~ +0 -0
- data/lib/khronos/controller.rb +0 -26
- data/lib/khronos/runner.rb +0 -11
- data/lib/khronos/storage/adapter/.client.rb.un~ +0 -0
- data/lib/khronos/storage/adapter/.memcached.rb.un~ +0 -0
- data/lib/khronos/storage/adapter/.mongo.rb.un~ +0 -0
- data/lib/khronos/storage/adapter/.mongodb.rb.un~ +0 -0
- data/lib/khronos/storage/adapter/.postgres.rb.un~ +0 -0
- data/lib/khronos/storage/adapter/.redis.rb.un~ +0 -0
- data/lib/khronos/storage/adapter/mongo.rb +0 -13
- data/lib/khronos/storage/adapter/mongo/.mongo.rb.un~ +0 -0
- data/lib/khronos/storage/adapter/mongo/.schedule.rb.un~ +0 -0
- data/lib/khronos/storage/adapter/postgres.rb +0 -15
- data/lib/khronos/storage/adapter/postgres/.schedule_log.rb.un~ +0 -0
- data/lib/khronos/storage/adapter/postgres/schedule.rb +0 -13
- data/lib/khronos/storage/adapter/postgres/schedule_log.rb +0 -13
- data/lib/khronos/storage/db/migrate/.schedule.rb.un~ +0 -0
- data/lib/khronos/storage/db/migrate/.schedule_log.rb.un~ +0 -0
- data/lib/khronos/storage/db/migrate/schedule.rb +0 -15
- data/lib/khronos/storage/db/migrate/schedule_log.rb +0 -16
- data/spec/.spec_helper.rb.un~ +0 -0
- data/spec/functional/.client_spec.rb.un~ +0 -0
- data/spec/functional/client_spec.rb +0 -24
- data/spec/integration/.server_spec.rb.un~ +0 -0
- data/spec/integration/server_spec.rb +0 -31
data/.gitignore
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
deploy
|
data/.travis.yml
ADDED
data/Gemfile
CHANGED
@@ -2,17 +2,28 @@ source :rubygems
|
|
2
2
|
gemspec
|
3
3
|
|
4
4
|
group :test do
|
5
|
-
|
6
|
-
gem 'activesupport', "~> 3.2.8"
|
7
|
-
|
5
|
+
gem 'thin'
|
8
6
|
gem 'simplecov', '= 0.6.4'
|
9
7
|
|
10
|
-
|
11
|
-
gem
|
8
|
+
# Testing
|
9
|
+
gem "rspec", "~> 2.11.0"
|
10
|
+
gem 'rack-test', '~> 0.6.1'
|
12
11
|
gem "fakefs", "~> 0.4.0"
|
13
12
|
gem "delorean", "~> 2.0.0"
|
13
|
+
gem "factory_girl", "~> 4.0.0"
|
14
|
+
gem "webmock", "~> 1.8.9"
|
15
|
+
#gem "em-spec", ''
|
16
|
+
|
17
|
+
#
|
18
|
+
# Used for time functions
|
19
|
+
#
|
20
|
+
gem 'activesupport', "~> 3.2.8"
|
14
21
|
|
15
|
-
|
16
|
-
|
22
|
+
#
|
23
|
+
# Database support testing
|
24
|
+
#
|
17
25
|
gem 'mongo'
|
26
|
+
gem "mysql2", "~> 0.3.11"
|
27
|
+
gem 'sqlite3'
|
28
|
+
gem 'pg'
|
18
29
|
end
|
data/Rakefile
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
$: << 'lib'
|
2
|
+
|
3
|
+
require 'bundler/setup'
|
4
|
+
|
5
|
+
ENV['RACK_ENV'] = ENV['ENV'] || 'test'
|
6
|
+
require 'khronos'
|
7
|
+
|
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
|
24
|
+
|
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
|
34
|
+
|
35
|
+
end
|
36
|
+
|
data/bin/khronos
CHANGED
data/config.ru
CHANGED
@@ -4,4 +4,12 @@ require 'bundler/setup'
|
|
4
4
|
require 'active_support/all'
|
5
5
|
require 'khronos'
|
6
6
|
|
7
|
-
|
7
|
+
#controller = Khronos::Controller.new
|
8
|
+
#controller.start!
|
9
|
+
|
10
|
+
run Khronos::Server::Scheduler
|
11
|
+
|
12
|
+
# Note that this will block current thread.
|
13
|
+
#EventMachine.run {
|
14
|
+
#EventMachine.start_server "127.0.0.1", 8081, Khronos::Server::Runner
|
15
|
+
#}
|
data/config/environment.yml
CHANGED
@@ -1,11 +1,33 @@
|
|
1
1
|
production:
|
2
|
-
storage:
|
2
|
+
storage: mongodb://localhost:27017/khronos
|
3
3
|
interval: 5
|
4
|
+
controller:
|
5
|
+
interval: 1
|
6
|
+
runner:
|
7
|
+
host: 'localhost'
|
8
|
+
port: '7243'
|
9
|
+
scheduler:
|
10
|
+
host: 'localhost'
|
11
|
+
port: '8080'
|
4
12
|
|
5
13
|
development:
|
6
|
-
storage:
|
7
|
-
|
14
|
+
storage: mongodb://localhost:27017/khronos_development
|
15
|
+
controller:
|
16
|
+
interval: 1
|
17
|
+
runner:
|
18
|
+
host: 'localhost'
|
19
|
+
port: '7243'
|
20
|
+
scheduler:
|
21
|
+
host: 'localhost'
|
22
|
+
port: '8080'
|
8
23
|
|
9
24
|
test:
|
10
|
-
storage:
|
11
|
-
|
25
|
+
storage: sqlite3://localhost/db/test.db
|
26
|
+
controller:
|
27
|
+
interval: 1
|
28
|
+
runner:
|
29
|
+
host: 'localhost'
|
30
|
+
port: '7243'
|
31
|
+
scheduler:
|
32
|
+
host: 'localhost'
|
33
|
+
port: '8080'
|
Binary file
|
data/khronos.gemspec
CHANGED
@@ -8,17 +8,20 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.platform = Gem::Platform::RUBY
|
9
9
|
s.authors = ["Endel Dreyer"]
|
10
10
|
s.email = ["endel@ocapi.com.br"]
|
11
|
-
s.homepage = "http://github.com/ocapi/
|
11
|
+
s.homepage = "http://github.com/ocapi/khronos"
|
12
12
|
|
13
13
|
s.summary = "Ruby HTTP Job Scheduler Interface."
|
14
|
-
s.description = "
|
14
|
+
s.description = "Ruby HTTP Job Scheduler Interface. An advanced Cron replacement for the cloud."
|
15
15
|
s.licenses = ['MIT']
|
16
16
|
|
17
|
-
s.add_dependency "sinatra",
|
18
|
-
s.add_dependency
|
19
|
-
s.add_dependency
|
20
|
-
s.add_dependency
|
21
|
-
s.add_dependency
|
17
|
+
s.add_dependency "sinatra", "~> 1.3.3"
|
18
|
+
s.add_dependency "mongoid", "~> 3.0.5"
|
19
|
+
s.add_dependency "bson_ext", "~> 1.6.4"
|
20
|
+
s.add_dependency "activerecord", "~> 3.2.8"
|
21
|
+
s.add_dependency "json", "~> 1.7.5"
|
22
|
+
s.add_dependency "activesupport", "~> 3.2.8"
|
23
|
+
s.add_dependency "eventmachine", "~> 1.0.0.beta.4"
|
24
|
+
s.add_dependency "em-http-request", "~> 1.0.3"
|
22
25
|
|
23
26
|
s.files = `git ls-files`.split("\n")
|
24
27
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
data/lib/khronos.rb
CHANGED
@@ -2,19 +2,16 @@ require 'rubygems'
|
|
2
2
|
require 'bundler'
|
3
3
|
require 'bundler/setup'
|
4
4
|
require 'json'
|
5
|
+
require 'logger'
|
5
6
|
|
6
7
|
module Khronos
|
7
8
|
autoload :Config, 'khronos/config'
|
9
|
+
autoload :Logger, 'khronos/logger'
|
10
|
+
autoload :Scheduler, 'khronos/scheduler'
|
8
11
|
|
9
12
|
autoload :Storage, 'khronos/storage'
|
10
13
|
autoload :Server, 'khronos/server'
|
11
|
-
|
12
|
-
autoload :Scheduler, 'khronos/scheduler'
|
13
|
-
autoload :Runner, 'khronos/runner'
|
14
|
-
autoload :Controller, 'khronos/controller'
|
15
14
|
end
|
16
15
|
|
16
|
+
Khronos::Logger.setup!(Logger.new(STDOUT))
|
17
17
|
Khronos::Config.instance.load!('config/environment.yml', ENV['RACK_ENV'])
|
18
|
-
|
19
|
-
controller = Khronos::Controller.new
|
20
|
-
controller.start!
|
data/lib/khronos/config.rb
CHANGED
data/lib/khronos/scheduler.rb
CHANGED
@@ -1,12 +1,26 @@
|
|
1
|
-
require '
|
1
|
+
require 'socket'
|
2
|
+
require 'json'
|
2
3
|
|
3
4
|
module Khronos
|
4
5
|
class Scheduler
|
5
|
-
|
6
|
+
module Methods
|
7
|
+
def run(schedule)
|
8
|
+
client = TCPSocket.new( Config.instance.runner['host'], Config.instance.runner['port'] )
|
9
|
+
client.puts( schedule.to_json )
|
6
10
|
|
7
|
-
|
11
|
+
while !(client.closed?) && (message = client.gets)
|
12
|
+
puts message.inspect
|
13
|
+
client.close
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def fetch(target_time=Time.now)
|
18
|
+
Storage::Schedule.where(['at <= ?', target_time]).where(:active => true)
|
19
|
+
end
|
8
20
|
end
|
9
21
|
|
22
|
+
include Methods
|
23
|
+
extend Methods
|
10
24
|
end
|
11
25
|
end
|
12
26
|
|
data/lib/khronos/server.rb
CHANGED
@@ -1,34 +1,7 @@
|
|
1
|
-
require 'sinatra'
|
2
|
-
|
3
1
|
module Khronos
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
#
|
9
|
-
# @return [Hash] JSON
|
10
|
-
get '/' do
|
11
|
-
context = retrieve_context!
|
12
|
-
settings.storage.get(context).to_json
|
13
|
-
end
|
14
|
-
|
15
|
-
# Creates or updates a schedule from a context
|
16
|
-
#
|
17
|
-
# @param [String]
|
18
|
-
#
|
19
|
-
# @return [Hash] Context JSON status hash
|
20
|
-
put '/' do
|
21
|
-
context = retrieve_context!
|
22
|
-
puts params.inspect
|
23
|
-
context.to_json
|
24
|
-
end
|
25
|
-
|
26
|
-
private
|
27
|
-
|
28
|
-
def retrieve_context!
|
29
|
-
halt 400, "Missing 'context' on query string." unless params[:context]
|
30
|
-
(params[:namespace].nil?) ? params[:context] : "#{params[:namespace]}:#{params[:context]}"
|
31
|
-
end
|
32
|
-
|
2
|
+
module Server
|
3
|
+
autoload :Runner, 'khronos/server/runner'
|
4
|
+
autoload :Scheduler, 'khronos/server/scheduler'
|
5
|
+
autoload :Controller, 'khronos/server/controller'
|
33
6
|
end
|
34
7
|
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Khronos
|
2
|
+
module Server
|
3
|
+
class Controller
|
4
|
+
attr_reader :storage, :scheduler
|
5
|
+
|
6
|
+
def initialize
|
7
|
+
@storage = Storage.new
|
8
|
+
@scheduler = Scheduler.new
|
9
|
+
end
|
10
|
+
|
11
|
+
def logger=(logger)
|
12
|
+
puts "WARNING: Not implemented yet."
|
13
|
+
end
|
14
|
+
|
15
|
+
def start!
|
16
|
+
loop do
|
17
|
+
@scheduler.fetch(Time.now).each do |schedule|
|
18
|
+
schedule.update_attributes(:status => false)
|
19
|
+
schedule.save
|
20
|
+
@scheduler.run(schedule)
|
21
|
+
end
|
22
|
+
|
23
|
+
#
|
24
|
+
# Sleep 'interval' seconds
|
25
|
+
#
|
26
|
+
sleep(Config.instance.controller['interval'])
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'eventmachine'
|
3
|
+
require 'em-http'
|
4
|
+
|
5
|
+
module Khronos
|
6
|
+
module Server
|
7
|
+
|
8
|
+
class Runner < EventMachine::Connection
|
9
|
+
def post_init
|
10
|
+
puts "-- someone connected to the server!"
|
11
|
+
end
|
12
|
+
|
13
|
+
def receive_data json
|
14
|
+
schedule = JSON.parse(json)
|
15
|
+
send_data ">>> you sent: #{schedule.inspect}"
|
16
|
+
|
17
|
+
# Close connection with client immediatelly
|
18
|
+
close_connection
|
19
|
+
|
20
|
+
if (url = schedule['task_url'])
|
21
|
+
http = EventMachine::HttpRequest.new(url).get :redirects => 5
|
22
|
+
http.callback do
|
23
|
+
puts "#{url}\n#{http.response_header.status} - #{http.response.length} bytes\n"
|
24
|
+
puts http.response
|
25
|
+
end
|
26
|
+
|
27
|
+
http.errback do
|
28
|
+
puts "#{url}\n" + http.error
|
29
|
+
end
|
30
|
+
|
31
|
+
enqueue_recurrency!(schedule)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
def enqueue_recurrency!(schedule)
|
37
|
+
url = "http://#{Config.instance.scheduler['host']}"
|
38
|
+
url += ":#{Config.instance.scheduler['port']}" if Config.instance.scheduler['port']
|
39
|
+
url += "/task?id=#{schedule['id']}"
|
40
|
+
EventMachine::HttpRequest.new(url).patch :redirects => 2
|
41
|
+
end
|
42
|
+
|
43
|
+
def unbind
|
44
|
+
puts "-- someone disconnected from the echo server!"
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'sinatra'
|
2
|
+
|
3
|
+
module Khronos
|
4
|
+
module Server
|
5
|
+
|
6
|
+
class Scheduler < Sinatra::Base
|
7
|
+
set :storage, Storage.new
|
8
|
+
|
9
|
+
# Creates a schedule
|
10
|
+
#
|
11
|
+
# @param [String] context application-level identifier
|
12
|
+
# @param [Integer] at timestamp which will run for the first time
|
13
|
+
# @param [Integer] recurrency next execution interval, in seconds
|
14
|
+
# @param [String] task_url url of the task that will run
|
15
|
+
# @param [String, JSON] callbacks callback urls (e.g. '{"success" : ... , "error" : ...}')
|
16
|
+
#
|
17
|
+
# @return [Hash] created schedule data
|
18
|
+
post '/task' do
|
19
|
+
Storage::Schedule.create(params).to_json
|
20
|
+
end
|
21
|
+
|
22
|
+
# Retrieves scheduling tasks from a context
|
23
|
+
#
|
24
|
+
# @param [Integer] id
|
25
|
+
# @param [String] context
|
26
|
+
#
|
27
|
+
# @return [Hash] JSON
|
28
|
+
get '/task' do
|
29
|
+
schedule = (!params.empty?) ? Storage::Schedule.where(params).first : nil
|
30
|
+
if schedule.nil?
|
31
|
+
# Requested task not found
|
32
|
+
404
|
33
|
+
else
|
34
|
+
schedule.to_json
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Retrieve a list of scheduling tasks
|
39
|
+
get '/tasks' do
|
40
|
+
if Storage::Schedule.name =~ /ActiveRecord/
|
41
|
+
criteria = Storage::Schedule
|
42
|
+
params.each_pair do |field, value|
|
43
|
+
if field == 'context'
|
44
|
+
field = "#{field} LIKE ?"
|
45
|
+
else
|
46
|
+
field = "#{field} = ?"
|
47
|
+
end
|
48
|
+
criteria = criteria.where(field, value)
|
49
|
+
end
|
50
|
+
criteria.to_json
|
51
|
+
else
|
52
|
+
Storage::Schedule.where(params).to_json
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# Creates or updates a schedule from a context
|
57
|
+
#
|
58
|
+
# @param [String]
|
59
|
+
#
|
60
|
+
# @return [Hash] Context JSON status hash
|
61
|
+
put '/task' do
|
62
|
+
schedule = Storage::Schedule.where({:id => params.delete(:id)}).first
|
63
|
+
|
64
|
+
# No schedule found for this params.
|
65
|
+
return {}.to_json unless schedule
|
66
|
+
|
67
|
+
schedule.update_attributes(params)
|
68
|
+
schedule.save
|
69
|
+
|
70
|
+
schedule.to_json
|
71
|
+
end
|
72
|
+
|
73
|
+
# Checks recurrency and reactivates a schedule if necessary
|
74
|
+
#
|
75
|
+
# @param [String] id
|
76
|
+
#
|
77
|
+
# @return [Hash] data
|
78
|
+
patch '/task' do
|
79
|
+
schedule = Storage::Schedule.where(params).first
|
80
|
+
|
81
|
+
# No schedule found for this params.
|
82
|
+
return {}.to_json unless schedule
|
83
|
+
|
84
|
+
# Is recurrency check requested
|
85
|
+
if schedule.recurrency > 0
|
86
|
+
schedule.at += schedule.recurrency
|
87
|
+
schedule.active = true
|
88
|
+
end
|
89
|
+
schedule.save
|
90
|
+
|
91
|
+
schedule.to_json
|
92
|
+
end
|
93
|
+
|
94
|
+
# Force a task to be scheduled right now
|
95
|
+
#
|
96
|
+
# @param [Integer] id
|
97
|
+
#
|
98
|
+
# @return [Hash] queued
|
99
|
+
post '/task/run' do
|
100
|
+
schedule = Storage::Schedule.where(:id => params[:id]).first
|
101
|
+
Khronos::Scheduler.run(schedule) if schedule
|
102
|
+
{:queued => !schedule.nil?}.to_json
|
103
|
+
end
|
104
|
+
|
105
|
+
# Log requests
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|