perfectsched 0.7.19 → 0.8.0
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/.gitignore +6 -0
- data/ChangeLog +0 -36
- data/Gemfile +3 -0
- data/README.md +219 -0
- data/Rakefile +19 -0
- data/lib/perfectsched/application.rb +25 -0
- data/lib/perfectsched/backend/rdb_compat.rb +254 -0
- data/lib/perfectsched/backend.rb +44 -82
- data/lib/perfectsched/blocking_flag.rb +25 -0
- data/lib/perfectsched/client.rb +129 -0
- data/lib/perfectsched/command/perfectsched.rb +103 -290
- data/lib/perfectsched/daemons_logger.rb +24 -0
- data/lib/perfectsched/engine.rb +54 -54
- data/lib/perfectsched/error.rb +43 -0
- data/lib/perfectsched/model.rb +37 -0
- data/lib/perfectsched/runner.rb +35 -0
- data/lib/perfectsched/schedule.rb +65 -0
- data/lib/perfectsched/schedule_collection.rb +62 -0
- data/lib/perfectsched/schedule_metadata.rb +76 -0
- data/lib/perfectsched/signal_queue.rb +25 -0
- data/lib/perfectsched/task.rb +46 -0
- data/lib/perfectsched/version.rb +1 -3
- data/lib/perfectsched/worker.rb +163 -0
- data/lib/perfectsched.rb +98 -4
- data/perfectsched.gemspec +27 -0
- data/spec/schedule_collection_spec.rb +172 -0
- data/spec/spec_helper.rb +46 -0
- data/spec/worker_spec.rb +51 -0
- metadata +98 -52
- checksums.yaml +0 -7
- data/README.rdoc +0 -137
- data/lib/perfectsched/backend/null.rb +0 -45
- data/lib/perfectsched/backend/rdb.rb +0 -165
- data/lib/perfectsched/backend/simpledb.rb +0 -174
- data/lib/perfectsched/croncalc.rb +0 -29
- data/test/backend_test.rb +0 -217
- data/test/test_helper.rb +0 -19
data/lib/perfectsched/backend.rb
CHANGED
@@ -1,87 +1,49 @@
|
|
1
|
+
#
|
2
|
+
# PerfectSched
|
3
|
+
#
|
4
|
+
# Copyright (C) 2012 FURUHASHI Sadayuki
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
1
18
|
|
2
19
|
module PerfectSched
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
end
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
# => true (success) or false (canceled)
|
33
|
-
def finish(token, next_time)
|
34
|
-
end
|
35
|
-
|
36
|
-
# => true (success) or nil (already exists)
|
37
|
-
def add(id, cron, delay, data, start_time, timezone=nil)
|
38
|
-
timezone = TZInfo::Timezone.get(timezone).name if timezone # normalize
|
39
|
-
first_time = @croncalc.next_time(cron, start_time.to_i, timezone)
|
40
|
-
timeout = first_time + delay
|
41
|
-
add_checked(id, cron, delay, data, first_time, timeout, timezone)
|
42
|
-
end
|
43
|
-
|
44
|
-
# => true (success) or nil (already exists)
|
45
|
-
def add_checked(id, cron, delay, data, next_time, timeout, timezone)
|
46
|
-
end
|
47
|
-
|
48
|
-
# => true (success) or false (not found, canceled or finished)
|
49
|
-
def delete(id)
|
50
|
-
end
|
51
|
-
|
52
|
-
# => true (success) or false (not found)
|
53
|
-
def modify(id, cron, delay, data, timezone)
|
54
|
-
cron = cron.strip
|
55
|
-
@croncalc.next_time(cron, 0, timezone)
|
56
|
-
modify_checked(id, cron, delay, data, timezone)
|
57
|
-
end
|
58
|
-
|
59
|
-
def modify_checked(id, cron, delay, data, timezone)
|
60
|
-
end
|
61
|
-
|
62
|
-
# => true (success) or false (not found)
|
63
|
-
def modify_sched(id, cron, delay)
|
64
|
-
cron_, delay_, data_, timezone, next_time = get(id)
|
65
|
-
cron = cron.strip
|
66
|
-
@croncalc.next_time(cron, 0, timezone)
|
67
|
-
modify_sched_checked(id, cron, delay)
|
68
|
-
end
|
69
|
-
|
70
|
-
def modify_sched_checked(id, cron, delay)
|
20
|
+
module Backend
|
21
|
+
def self.new_backend(client, config)
|
22
|
+
case config[:type]
|
23
|
+
when nil
|
24
|
+
raise ConfigError, "'type' option is not set"
|
25
|
+
when 'rdb_compat'
|
26
|
+
require_backend('rdb_compat')
|
27
|
+
RDBCompatBackend.new(client, config)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.require_backend(fname)
|
32
|
+
require File.expand_path("backend/#{fname}", File.dirname(__FILE__))
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module BackendHelper
|
37
|
+
def initialize(client, config)
|
38
|
+
@client = client
|
39
|
+
@config = config
|
40
|
+
end
|
41
|
+
|
42
|
+
attr_reader :client
|
43
|
+
|
44
|
+
def close
|
45
|
+
# do nothing by default
|
46
|
+
end
|
71
47
|
end
|
72
|
-
|
73
|
-
# => true (success) or false (not found)
|
74
|
-
def modify_data(id, data)
|
75
|
-
modify_data_checked(id, data)
|
76
|
-
end
|
77
|
-
|
78
|
-
def modify_data_checked(id, data)
|
79
|
-
end
|
80
|
-
|
81
|
-
def close
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
|
86
48
|
end
|
87
49
|
|
@@ -0,0 +1,25 @@
|
|
1
|
+
#
|
2
|
+
# PerfectSched
|
3
|
+
#
|
4
|
+
# Copyright (C) 2012 FURUHASHI Sadayuki
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
module PerfectSched
|
20
|
+
|
21
|
+
require 'perfectqueue/blocking_flag'
|
22
|
+
BlockingFlag = PerfectQueue::BlockingFlag
|
23
|
+
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,129 @@
|
|
1
|
+
#
|
2
|
+
# PerfectSched
|
3
|
+
#
|
4
|
+
# Copyright (C) 2012 FURUHASHI Sadayuki
|
5
|
+
#
|
6
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
7
|
+
# you may not use this file except in compliance with the License.
|
8
|
+
# You may obtain a copy of the License at
|
9
|
+
#
|
10
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
11
|
+
#
|
12
|
+
# Unless required by applicable law or agreed to in writing, software
|
13
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
14
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
15
|
+
# See the License for the specific language governing permissions and
|
16
|
+
# limitations under the License.
|
17
|
+
#
|
18
|
+
|
19
|
+
module PerfectSched
|
20
|
+
class Client
|
21
|
+
def initialize(config)
|
22
|
+
@config = {}
|
23
|
+
config.each_pair {|k,v| @config[k.to_sym] = v }
|
24
|
+
|
25
|
+
@backend = Backend.new_backend(self, @config)
|
26
|
+
|
27
|
+
@timezone = @config[:timezone] || 'UTC'
|
28
|
+
@max_acquire = @config[:max_acquire] || 1
|
29
|
+
@alive_time = @config[:alive_time] || 300
|
30
|
+
@retry_wait = @config[:retry_wait] || 300 # TODO retry wait algorithm
|
31
|
+
end
|
32
|
+
|
33
|
+
attr_reader :backend
|
34
|
+
attr_reader :config
|
35
|
+
|
36
|
+
def init_database(options={})
|
37
|
+
@backend.init_database(options)
|
38
|
+
end
|
39
|
+
|
40
|
+
def get_schedule_metadata(key, options={})
|
41
|
+
@backend.get_schedule_metadata(key, options)
|
42
|
+
end
|
43
|
+
|
44
|
+
# :next_time => Time.now
|
45
|
+
# :next_run_time => Time.now
|
46
|
+
# :cron
|
47
|
+
# :data
|
48
|
+
# :delay => 0
|
49
|
+
# :timezone => UTC
|
50
|
+
def add(key, type, options={})
|
51
|
+
cron = options[:cron]
|
52
|
+
|
53
|
+
raise ArgumentError, ":cron option is required" unless cron
|
54
|
+
|
55
|
+
delay = options[:delay] || 0
|
56
|
+
timezone = options[:timezone] || @timezone
|
57
|
+
data = options[:data] || {}
|
58
|
+
|
59
|
+
next_time = options[:next_time] || Time.now.to_i
|
60
|
+
next_time = PerfectSched.cron_time(cron, next_time.to_i, timezone)
|
61
|
+
|
62
|
+
next_run_time = options[:next_run_time]
|
63
|
+
if next_run_time
|
64
|
+
next_run_time = next_run_time.to_i
|
65
|
+
else
|
66
|
+
next_run_time = next_time + delay
|
67
|
+
end
|
68
|
+
|
69
|
+
@backend.add(key, type, cron, delay, timezone, data, next_time, next_run_time, options)
|
70
|
+
|
71
|
+
# TODO return value
|
72
|
+
return next_time, next_run_time
|
73
|
+
end
|
74
|
+
|
75
|
+
def delete(key, options={})
|
76
|
+
@backend.delete(key, options)
|
77
|
+
end
|
78
|
+
|
79
|
+
# :next_time => nil
|
80
|
+
# :next_run_time => nil
|
81
|
+
# :cron => nil
|
82
|
+
# :delay => nil
|
83
|
+
# :timezone => nil
|
84
|
+
def modify(key, options={})
|
85
|
+
@backend.modify(key, options)
|
86
|
+
end
|
87
|
+
|
88
|
+
def list(options={}, &block)
|
89
|
+
@backend.list(options, &block)
|
90
|
+
end
|
91
|
+
|
92
|
+
# :now => Time.now
|
93
|
+
# :max_acquire
|
94
|
+
def acquire(options={})
|
95
|
+
alive_time = options[:alive_time] || @alive_time
|
96
|
+
max_acquire = options[:max_acquire] || 1
|
97
|
+
|
98
|
+
@backend.acquire(alive_time, max_acquire, options)
|
99
|
+
end
|
100
|
+
|
101
|
+
def release(task_token, options={})
|
102
|
+
alive_time = options[:alive_time] || @alive_time
|
103
|
+
|
104
|
+
@backend.release(task_token, alive_time, options)
|
105
|
+
end
|
106
|
+
|
107
|
+
# :alive_time => nil
|
108
|
+
def heartbeat(task_token, options={})
|
109
|
+
alive_time = options[:alive_time] || @alive_time
|
110
|
+
|
111
|
+
@backend.heartbeat(task_token, alive_time, options)
|
112
|
+
end
|
113
|
+
|
114
|
+
def retry(task_token, options={})
|
115
|
+
alive_time = options[:retry_wait] || @retry_wait
|
116
|
+
|
117
|
+
@backend.heartbeat(task_token, alive_time, options)
|
118
|
+
end
|
119
|
+
|
120
|
+
def finish(task_token, options={})
|
121
|
+
@backend.finish(task_token, options)
|
122
|
+
end
|
123
|
+
|
124
|
+
def close
|
125
|
+
@backend.close
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
@@ -3,355 +3,168 @@ require 'perfectsched/version'
|
|
3
3
|
|
4
4
|
op = OptionParser.new
|
5
5
|
|
6
|
-
op.banner +=
|
7
|
-
op.version = PerfectSched::VERSION
|
8
|
-
|
9
|
-
type = nil
|
10
|
-
id = nil
|
11
|
-
confout = nil
|
12
|
-
|
13
|
-
conf = {
|
14
|
-
:timeout => 600,
|
15
|
-
:poll_interval => 1,
|
16
|
-
#:expire => 345600,
|
17
|
-
}
|
6
|
+
op.banner += %[ <command>
|
18
7
|
|
19
|
-
|
20
|
-
|
21
|
-
|
8
|
+
commands:
|
9
|
+
list Show list of registered schedules
|
10
|
+
add <key> <type> <cron> <data> Register a new schedule
|
11
|
+
delete <key> Delete a registered schedule
|
12
|
+
run <class> Run a worker process
|
13
|
+
init Initialize a backend database
|
22
14
|
|
15
|
+
]
|
16
|
+
op.version = PerfectSched::VERSION
|
23
17
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
18
|
+
env = ENV['RAILS_ENV'] || 'development'
|
19
|
+
config_path = 'config/perfectsched.yml'
|
20
|
+
include_dirs = []
|
21
|
+
require_files = []
|
28
22
|
|
29
|
-
|
30
|
-
|
23
|
+
add_options = {
|
24
|
+
:delay => 0,
|
25
|
+
:timezone => 'UTC',
|
26
|
+
:next_time => nil,
|
27
|
+
:next_run_time => nil,
|
31
28
|
}
|
32
29
|
|
33
|
-
op.separator("")
|
30
|
+
op.separator("options:")
|
34
31
|
|
35
|
-
op.on('
|
36
|
-
|
32
|
+
op.on('-e', '--environment ENV', 'Framework environment (default: development)') {|s|
|
33
|
+
env = s
|
37
34
|
}
|
38
35
|
|
39
|
-
op.on('--
|
40
|
-
|
41
|
-
id = s
|
36
|
+
op.on('-c', '--config PATH.yml', 'Path to a configuration file (default: config/perfectsched.yml)') {|s|
|
37
|
+
config_path = s
|
42
38
|
}
|
43
39
|
|
44
|
-
op.separator("")
|
45
|
-
|
46
|
-
op.on('--add <ID> <CRON> <DATA>', 'Register a schedule') {|s|
|
47
|
-
type = :add
|
48
|
-
id = s
|
49
|
-
}
|
40
|
+
op.separator("\noptions for add:")
|
50
41
|
|
51
42
|
op.on('-d', '--delay SEC', 'Delay time before running a schedule (default: 0)', Integer) {|i|
|
52
|
-
|
43
|
+
add_options[:delay] = i
|
53
44
|
}
|
54
45
|
|
55
|
-
op.on('-t', '--timezone NAME', 'Set timezone (default:
|
56
|
-
|
46
|
+
op.on('-t', '--timezone NAME', 'Set timezone (default: UTC)') {|s|
|
47
|
+
add_options[:timezone] = s
|
57
48
|
}
|
58
49
|
|
59
|
-
op.on('-s', '--start UNIXTIME', '
|
60
|
-
|
50
|
+
op.on('-s', '--start UNIXTIME', 'Set the first schedule time (default: now)', Integer) {|i|
|
51
|
+
add_options[:next_time] = i
|
61
52
|
}
|
62
53
|
|
63
|
-
op.
|
64
|
-
|
65
|
-
op.on('-S', '--modify-sched <ID> <CRON>', 'Modify schedule of a registered schedule') {|s|
|
66
|
-
type = :modify_sched
|
67
|
-
id = s
|
68
|
-
}
|
69
|
-
|
70
|
-
op.on('-D', '--modify-delay <ID> <DELAY>', 'Modify delay of a registered schedule') {|s|
|
71
|
-
type = :modify_delay
|
72
|
-
id = s
|
54
|
+
op.on('-a', '--at UNIXTIME', 'Set the first run time (default: start+delay)', Integer) {|i|
|
55
|
+
add_options[:next_run_time] = i
|
73
56
|
}
|
74
57
|
|
75
|
-
op.
|
76
|
-
type = :modify_data
|
77
|
-
id = s
|
78
|
-
}
|
79
|
-
|
80
|
-
op.separator("")
|
58
|
+
op.separator("\noptions for run:")
|
81
59
|
|
82
|
-
op.on('-
|
83
|
-
|
60
|
+
op.on('-I', '--include PATH', 'Add $LOAD_PATH directory') {|s|
|
61
|
+
include_dirs << s
|
84
62
|
}
|
85
63
|
|
86
|
-
op.on('-
|
87
|
-
|
64
|
+
op.on('-r', '--require PATH', 'Require files before starting') {|s|
|
65
|
+
require_files << s
|
88
66
|
}
|
89
67
|
|
90
|
-
op.on('-v', '--verbose', "verbose mode", TrueClass) {|b|
|
91
|
-
conf[:verbose] = true
|
92
|
-
}
|
93
|
-
|
94
|
-
|
95
68
|
(class<<self;self;end).module_eval do
|
96
69
|
define_method(:usage) do |msg|
|
97
70
|
puts op.to_s
|
98
|
-
puts "
|
71
|
+
puts "\nerror: #{msg}" if msg
|
99
72
|
exit 1
|
100
73
|
end
|
101
74
|
end
|
102
75
|
|
103
|
-
|
104
76
|
begin
|
105
77
|
op.parse!(ARGV)
|
106
78
|
|
107
|
-
|
108
|
-
|
109
|
-
case type
|
110
|
-
when :add
|
111
|
-
if ARGV.length != 2
|
112
|
-
usage nil
|
113
|
-
end
|
114
|
-
add_conf[:cron] = ARGV[0]
|
115
|
-
add_conf[:data] = ARGV[1]
|
116
|
-
|
117
|
-
when :modify_sched
|
118
|
-
if ARGV.length != 1
|
119
|
-
usage nil
|
120
|
-
end
|
121
|
-
add_conf[:cron] = ARGV[0]
|
122
|
-
|
123
|
-
when :modify_data
|
124
|
-
if ARGV.length != 1
|
125
|
-
usage nil
|
126
|
-
end
|
127
|
-
add_conf[:data] = ARGV[0]
|
128
|
-
|
129
|
-
when :modify_delay
|
130
|
-
if ARGV.length != 1 || ARGV[0].to_i.to_s != ARGV[0]
|
131
|
-
usage nil
|
132
|
-
end
|
133
|
-
add_conf[:delay] = ARGV[0].to_i
|
134
|
-
|
135
|
-
else
|
136
|
-
if ARGV.length != 0
|
137
|
-
usage nil
|
138
|
-
end
|
139
|
-
end
|
140
|
-
|
141
|
-
if confout
|
142
|
-
require 'yaml'
|
143
|
-
|
144
|
-
File.open(confout, "w") {|f|
|
145
|
-
f.write <<EOF
|
146
|
-
---
|
147
|
-
timeout: 300
|
148
|
-
poll_interval: 1
|
149
|
-
backend:
|
150
|
-
database: "mysql2://user:password@localhost/mydb"
|
151
|
-
table: "perfectsched"
|
152
|
-
#simpledb: your-simpledb-domain-name-for-scheduler
|
153
|
-
#aws_key_id: "AWS_ACCESS_KEY_ID"
|
154
|
-
#aws_secret_key: "AWS_SECRET_ACCESS_KEY"
|
155
|
-
queue:
|
156
|
-
database: "mysql2://user:password@localhost/mydb"
|
157
|
-
table: "perfectqueue"
|
158
|
-
#simpledb: your-simpledb-domain-name-for-queue
|
159
|
-
#aws_key_id: "AWS_ACCESS_KEY_ID"
|
160
|
-
#aws_secret_key: "AWS_SECRET_ACCESS_KEY"
|
161
|
-
EOF
|
162
|
-
}
|
163
|
-
exit 0
|
164
|
-
end
|
79
|
+
usage nil if ARGV.empty?
|
165
80
|
|
166
|
-
|
167
|
-
|
168
|
-
|
81
|
+
cmd = ARGV.shift
|
82
|
+
case cmd
|
83
|
+
when 'list'
|
84
|
+
cmd = :list
|
85
|
+
usage nil unless ARGV.length == 0
|
169
86
|
|
170
|
-
|
171
|
-
|
172
|
-
|
87
|
+
when 'delete'
|
88
|
+
cmd = :delete
|
89
|
+
usage nil unless ARGV.length == 1
|
90
|
+
key = ARGV[0]
|
173
91
|
|
92
|
+
when 'add'
|
93
|
+
cmd = :add
|
94
|
+
usage nil unless ARGV.length == 4
|
95
|
+
key, type, cron, data = *ARGV
|
96
|
+
require 'json'
|
97
|
+
data = JSON.load(data)
|
174
98
|
|
175
|
-
|
176
|
-
|
99
|
+
when 'run'
|
100
|
+
cmd = :run
|
101
|
+
usage nil unless ARGV.length == 1
|
102
|
+
klass = ARGV[0]
|
177
103
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
docs << File.read(file)
|
182
|
-
}
|
183
|
-
YAML.load_documents(docs) {|yaml|
|
184
|
-
yaml.each_pair {|k,v| conf[k.to_sym] = v }
|
185
|
-
}
|
104
|
+
when 'init'
|
105
|
+
cmd = :init
|
106
|
+
usage nil unless ARGV.length == 0
|
186
107
|
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
# backend
|
191
|
-
bconf = conf[:backend]
|
192
|
-
if domain = bconf['simpledb']
|
193
|
-
require 'perfectsched/backend/simpledb'
|
194
|
-
key_id = bconf['aws_key_id'] || ENV['AWS_ACCESS_KEY_ID']
|
195
|
-
secret_key = bconf['aws_secret_key'] || ENV['AWS_SECRET_ACCESS_KEY']
|
196
|
-
backend = PerfectSched::SimpleDBBackend.new(key_id, secret_key, domain)
|
197
|
-
if type != :run
|
198
|
-
backend.use_consistent_read
|
108
|
+
else
|
109
|
+
raise "unknown command: '#{cmd}'"
|
199
110
|
end
|
200
111
|
|
201
|
-
|
202
|
-
|
203
|
-
table = bconf['table'] || "perfectsched"
|
204
|
-
backend = PerfectSched::RDBBackend.new(uri, table)
|
205
|
-
|
206
|
-
else
|
207
|
-
$stderr.puts "Invalid configuration file: backend section is required"
|
208
|
-
exit 1
|
112
|
+
rescue
|
113
|
+
usage $!.to_s
|
209
114
|
end
|
210
115
|
|
211
|
-
|
212
|
-
|
213
|
-
bconf = conf[:queue]
|
214
|
-
if domain = bconf['simpledb']
|
215
|
-
require 'perfectqueue/backend/simpledb'
|
216
|
-
key_id = bconf['aws_key_id'] || ENV['AWS_ACCESS_KEY_ID']
|
217
|
-
secret_key = bconf['aws_secret_key'] || ENV['AWS_SECRET_ACCESS_KEY']
|
218
|
-
queue = PerfectQueue::SimpleDBBackend.new(key_id, secret_key, domain)
|
219
|
-
|
220
|
-
elsif uri = bconf['database']
|
221
|
-
require 'perfectqueue/backend/rdb'
|
222
|
-
table = bconf['table'] || "perfectqueue"
|
223
|
-
queue = PerfectQueue::RDBBackend.new(uri, table)
|
116
|
+
require 'yaml'
|
117
|
+
require 'perfectsched'
|
224
118
|
|
225
|
-
|
226
|
-
|
227
|
-
|
119
|
+
config_load_proc = Proc.new {
|
120
|
+
yaml = YAML.load(File.read(config_path))
|
121
|
+
conf = yaml[env]
|
122
|
+
unless conf
|
123
|
+
raise "Configuration file #{config_path} doesn't include configuration for environment '#{env}'"
|
228
124
|
end
|
229
|
-
|
230
|
-
|
231
|
-
require 'logger'
|
125
|
+
conf
|
126
|
+
}
|
232
127
|
|
233
|
-
case
|
128
|
+
case cmd
|
234
129
|
when :list
|
235
|
-
format = "%26s %18s %8s %20s %20s %20s %s"
|
236
|
-
puts format % ["id", "schedule", "delay", "next time", "next run", "timezone", "data"]
|
237
|
-
time_format = "%Y-%m-%d %H:%M:%S"
|
238
130
|
n = 0
|
239
|
-
|
240
|
-
|
241
|
-
|
131
|
+
PerfectSched.open(config_load_proc.call) {|scheds|
|
132
|
+
format = "%30s %15s %18s %7s %11s %28s %28s %s"
|
133
|
+
puts format % ['key', 'type', 'cron', 'delay', 'timezone', 'next_time', 'next_run_time', 'data']
|
134
|
+
scheds.list {|sched|
|
135
|
+
next_time = sched.next_time ? Time.at(sched.next_time) : sched.next_time
|
136
|
+
next_run_time = sched.next_run_time ? Time.at(sched.next_run_time) : sched.next_run_time
|
137
|
+
puts format % [sched.key, sched.type, sched.cron, sched.delay, sched.timezone, next_time, next_run_time, sched.data]
|
138
|
+
n += 1
|
139
|
+
}
|
242
140
|
}
|
243
141
|
puts "#{n} entries."
|
244
142
|
|
245
143
|
when :delete
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
else
|
250
|
-
puts "Schedule id=#{id} does not exist."
|
251
|
-
exit 1
|
252
|
-
end
|
144
|
+
PerfectSched.open(config_load_proc.call) {|scheds|
|
145
|
+
scheds[key].delete!
|
146
|
+
}
|
253
147
|
|
254
148
|
when :add
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
added = backend.add(id, cron, delay, data, start, timezone)
|
262
|
-
if added
|
263
|
-
puts "Schedule id=#{id} is added."
|
264
|
-
else
|
265
|
-
puts "Schedule id=#{id} already exists."
|
266
|
-
exit 1
|
267
|
-
end
|
268
|
-
|
269
|
-
when :modify_sched, :modify_delay, :modify_data
|
270
|
-
cron, delay, data, timezone = backend.get(id)
|
271
|
-
unless cron
|
272
|
-
puts "Schedule id=#{id} does not exist."
|
273
|
-
exit 1
|
274
|
-
end
|
275
|
-
|
276
|
-
case type
|
277
|
-
when :modify_sched
|
278
|
-
cron = add_conf[:cron]
|
279
|
-
modified = backend.modify_sched(id, cron, delay)
|
280
|
-
|
281
|
-
when :modify_delay
|
282
|
-
delay = add_conf[:delay]
|
283
|
-
modified = backend.modify_sched(id, cron, delay)
|
284
|
-
|
285
|
-
when :modify_data
|
286
|
-
data = add_conf[:data]
|
287
|
-
modified = backend.modify_data(id, data)
|
288
|
-
end
|
289
|
-
|
290
|
-
if modified
|
291
|
-
puts "Schedule id=#{id} is modified."
|
292
|
-
else
|
293
|
-
puts "Schedule id=#{id} does not exist."
|
294
|
-
exit 1
|
295
|
-
end
|
149
|
+
PerfectSched.open(config_load_proc.call) {|scheds|
|
150
|
+
add_options[:cron] = cron
|
151
|
+
add_options[:data] = data
|
152
|
+
scheds.add(key, type, add_options)
|
153
|
+
}
|
296
154
|
|
297
155
|
when :run
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
File.open(conf[:daemon], "w") {|f|
|
307
|
-
f.write Process.pid.to_s
|
308
|
-
}
|
309
|
-
end
|
310
|
-
|
311
|
-
if log_file = conf[:log]
|
312
|
-
log_out = File.open(conf[:log], "a")
|
313
|
-
else
|
314
|
-
log_out = STDOUT
|
315
|
-
end
|
316
|
-
log_out.sync = true
|
317
|
-
|
318
|
-
log = Logger.new(log_out)
|
319
|
-
if conf[:verbose]
|
320
|
-
log.level = Logger::DEBUG
|
321
|
-
else
|
322
|
-
log.level = Logger::INFO
|
323
|
-
end
|
324
|
-
|
325
|
-
queue = make_queue.call
|
326
|
-
engine = PerfectSched::Engine.new(backend, queue, log, conf)
|
327
|
-
|
328
|
-
trap :INT do
|
329
|
-
log.info "shutting down..."
|
330
|
-
engine.stop
|
331
|
-
end
|
332
|
-
|
333
|
-
trap :TERM do
|
334
|
-
log.info "shutting down..."
|
335
|
-
engine.stop
|
336
|
-
end
|
337
|
-
|
338
|
-
trap :HUP do
|
339
|
-
if log_file
|
340
|
-
log_out.reopen(log_file, "a")
|
341
|
-
end
|
342
|
-
end
|
343
|
-
|
344
|
-
log.info "PerfectSched-#{PerfectSched::VERSION}"
|
156
|
+
include_dirs.each {|path|
|
157
|
+
$LOAD_PATH << File.expand_path(path)
|
158
|
+
}
|
159
|
+
require_files.each {|file|
|
160
|
+
require file
|
161
|
+
}
|
162
|
+
klass = Object.const_get(klass)
|
163
|
+
PerfectSched::Worker.run(klass, &config_load_proc)
|
345
164
|
|
346
|
-
|
347
|
-
|
348
|
-
|
349
|
-
|
350
|
-
log.error $!.to_s
|
351
|
-
$!.backtrace.each {|x|
|
352
|
-
log.error " #{x}"
|
353
|
-
}
|
354
|
-
exit 1
|
355
|
-
end
|
165
|
+
when :init
|
166
|
+
PerfectSched.open(config_load_proc.call) {|scheds|
|
167
|
+
scheds.client.init_database
|
168
|
+
}
|
356
169
|
end
|
357
170
|
|