zhong 0.1.9 → 0.2.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +30 -0
- data/lib/zhong/job.rb +24 -12
- data/lib/zhong/scheduler.rb +13 -12
- data/lib/zhong/version.rb +1 -1
- data/test/test_library.rb +20 -0
- data/test/test_web.rb +14 -0
- metadata +2 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 902b025d6f1afe4edfa0f2cb6f6639bc0ff558ff
|
4
|
+
data.tar.gz: 939fedf9667d0dc26f7fb1adcddedd5cbe76deba
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16ce76fbea779cffa736f3c48f99bca3fa0ac0ba27e46261f20c41c037143317cb406715e8e866da4495dcf33a20a11830a37b6bd1b41ac9d64c39568c7e1896
|
7
|
+
data.tar.gz: 85abd697abfe5fa1ffd7513ae8e146f34c3360234f2685f9f89aec5224b259d086e25097614836ba90ebe8bc2347b8ea324051d87ea5e6813acc845267de96bf
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -53,12 +53,42 @@ Zhong.schedule do
|
|
53
53
|
puts "#{job} ran?: #{ran}"
|
54
54
|
end
|
55
55
|
|
56
|
+
on(:before_disable) do |job|
|
57
|
+
puts "#{job} is going to be disabled"
|
58
|
+
end
|
59
|
+
|
60
|
+
on(:after_disable) do |job|
|
61
|
+
puts "#{job} disabled"
|
62
|
+
end
|
63
|
+
|
64
|
+
on(:before_enable) do |job|
|
65
|
+
puts "#{job} is going to be enabled"
|
66
|
+
end
|
67
|
+
|
68
|
+
on(:after_enable) do |job|
|
69
|
+
puts "#{job} enabled"
|
70
|
+
end
|
71
|
+
|
56
72
|
error_handler do |e, job|
|
57
73
|
puts "dang, #{job} messed up: #{e}"
|
58
74
|
end
|
59
75
|
end
|
60
76
|
```
|
61
77
|
|
78
|
+
## Web UI
|
79
|
+
|
80
|
+
Zhong comes with a web application that can display jobs, their last run and
|
81
|
+
enable/disable them.
|
82
|
+
|
83
|
+
### Rails
|
84
|
+
|
85
|
+
Add the following to your config/routes.rb:
|
86
|
+
|
87
|
+
```ruby
|
88
|
+
require 'zhong/web'
|
89
|
+
mount Zhong::Web, at: "zhong"
|
90
|
+
```
|
91
|
+
|
62
92
|
## History
|
63
93
|
|
64
94
|
View the [changelog](https://github.com/nickelser/zhong/blob/master/CHANGELOG.md).
|
data/lib/zhong/job.rb
CHANGED
@@ -1,12 +1,16 @@
|
|
1
1
|
module Zhong
|
2
2
|
class Job
|
3
|
-
|
3
|
+
extend Forwardable
|
4
|
+
def_delegators Zhong, :redis, :tz, :logger, :heartbeat_key
|
4
5
|
|
5
|
-
|
6
|
+
attr_reader :name, :category, :last_ran, :at, :every, :id
|
7
|
+
|
8
|
+
def initialize(job_name, config = {}, callbacks = {}, &block)
|
6
9
|
@name = job_name
|
7
10
|
@category = config[:category]
|
8
11
|
@logger = config[:logger]
|
9
12
|
@config = config
|
13
|
+
@callbacks = callbacks
|
10
14
|
|
11
15
|
@at = config[:at] ? At.parse(config[:at], grace: config.fetch(:grace, 15.minutes)) : nil
|
12
16
|
@every = config[:every] ? Every.parse(config[:every]) : nil
|
@@ -15,8 +19,6 @@ module Zhong
|
|
15
19
|
|
16
20
|
@block = block
|
17
21
|
|
18
|
-
@redis = config[:redis]
|
19
|
-
@tz = config[:tz]
|
20
22
|
@if = config[:if]
|
21
23
|
@long_running_timeout = config[:long_running_timeout]
|
22
24
|
@running = false
|
@@ -88,20 +90,24 @@ module Zhong
|
|
88
90
|
end
|
89
91
|
|
90
92
|
def refresh_last_ran
|
91
|
-
last_ran_val =
|
93
|
+
last_ran_val = redis.get(last_ran_key)
|
92
94
|
@last_ran = last_ran_val ? Time.at(last_ran_val.to_i) : nil
|
93
95
|
end
|
94
96
|
|
95
97
|
def disable
|
96
|
-
|
98
|
+
fire_callbacks(:before_disable, self)
|
99
|
+
redis.set(disabled_key, "true")
|
100
|
+
fire_callbacks(:after_disable, self)
|
97
101
|
end
|
98
102
|
|
99
103
|
def enable
|
100
|
-
|
104
|
+
fire_callbacks(:before_enable, self)
|
105
|
+
redis.del(disabled_key)
|
106
|
+
fire_callbacks(:after_enable, self)
|
101
107
|
end
|
102
108
|
|
103
109
|
def disabled?
|
104
|
-
|
110
|
+
!redis.get(disabled_key).nil?
|
105
111
|
end
|
106
112
|
|
107
113
|
def to_s
|
@@ -115,7 +121,7 @@ module Zhong
|
|
115
121
|
end
|
116
122
|
|
117
123
|
def clear
|
118
|
-
|
124
|
+
redis.del(last_ran_key)
|
119
125
|
end
|
120
126
|
|
121
127
|
def last_ran_key
|
@@ -136,10 +142,16 @@ module Zhong
|
|
136
142
|
|
137
143
|
private
|
138
144
|
|
145
|
+
def fire_callbacks(event, *args)
|
146
|
+
@callbacks[event].to_a.map do |callback|
|
147
|
+
callback.call(*args)
|
148
|
+
end.compact.all? # do not skip on nils
|
149
|
+
end
|
150
|
+
|
139
151
|
# if the @at value is changed across runs, the last_run becomes invalid
|
140
152
|
# so clear it
|
141
153
|
def clear_last_ran_if_at_changed
|
142
|
-
previous_at_msgpack =
|
154
|
+
previous_at_msgpack = redis.get(desired_at_key)
|
143
155
|
|
144
156
|
if previous_at_msgpack
|
145
157
|
previous_at = At.deserialize(previous_at_msgpack)
|
@@ -150,7 +162,7 @@ module Zhong
|
|
150
162
|
end
|
151
163
|
end
|
152
164
|
|
153
|
-
|
165
|
+
redis.set(desired_at_key, @at.serialize)
|
154
166
|
end
|
155
167
|
|
156
168
|
def run_every?(time)
|
@@ -167,7 +179,7 @@ module Zhong
|
|
167
179
|
|
168
180
|
def ran!(time)
|
169
181
|
@last_ran = time
|
170
|
-
|
182
|
+
redis.set(last_ran_key, @last_ran.to_i)
|
171
183
|
end
|
172
184
|
|
173
185
|
def redis_lock
|
data/lib/zhong/scheduler.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
module Zhong
|
2
2
|
class Scheduler
|
3
|
-
|
3
|
+
extend Forwardable
|
4
|
+
|
5
|
+
def_delegators Zhong, :redis, :tz, :logger, :heartbeat_key
|
6
|
+
attr_reader :jobs
|
4
7
|
|
5
8
|
DEFAULT_CONFIG = {
|
6
9
|
timeout: 0.5,
|
7
10
|
grace: 15.minutes,
|
8
|
-
long_running_timeout: 5.minutes
|
9
|
-
tz: nil,
|
10
|
-
heartbeat_key: "zhong:heartbeat",
|
11
|
+
long_running_timeout: 5.minutes
|
11
12
|
}.freeze
|
12
13
|
|
13
14
|
def initialize(config = {})
|
@@ -15,9 +16,6 @@ module Zhong
|
|
15
16
|
@callbacks = {}
|
16
17
|
@config = DEFAULT_CONFIG.merge(config)
|
17
18
|
|
18
|
-
@logger = @config[:logger]
|
19
|
-
@redis = @config[:redis]
|
20
|
-
@tz = @config[:tz]
|
21
19
|
@category = nil
|
22
20
|
@error_handler = nil
|
23
21
|
@running = false
|
@@ -44,7 +42,7 @@ module Zhong
|
|
44
42
|
def every(period, name, opts = {}, &block)
|
45
43
|
raise "must specify a period for #{name} (#{caller.first})" unless period
|
46
44
|
|
47
|
-
job = Job.new(name, opts.merge(@config).merge(every: period, category: @category), &block)
|
45
|
+
job = Job.new(name, opts.merge(@config).merge(every: period, category: @category), @callbacks, &block)
|
48
46
|
|
49
47
|
raise "duplicate job #{job}" if jobs.key?(job.id)
|
50
48
|
|
@@ -57,7 +55,10 @@ module Zhong
|
|
57
55
|
end
|
58
56
|
|
59
57
|
def on(event, &block)
|
60
|
-
|
58
|
+
unless [:before_tick, :after_tick, :before_run, :after_run, :before_disable,
|
59
|
+
:after_disable, :before_enable, :after_enable].include?(event.to_sym)
|
60
|
+
raise "unknown callback #{event}"
|
61
|
+
end
|
61
62
|
(@callbacks[event.to_sym] ||= []) << block
|
62
63
|
end
|
63
64
|
|
@@ -112,9 +113,9 @@ module Zhong
|
|
112
113
|
end
|
113
114
|
|
114
115
|
def redis_time
|
115
|
-
s, ms =
|
116
|
+
s, ms = redis.time # returns [seconds since epoch, microseconds]
|
116
117
|
now = Time.at(s + ms / (10**6))
|
117
|
-
|
118
|
+
tz ? now.in_time_zone(tz) : now
|
118
119
|
end
|
119
120
|
|
120
121
|
private
|
@@ -144,7 +145,7 @@ module Zhong
|
|
144
145
|
end
|
145
146
|
|
146
147
|
def heartbeat(time)
|
147
|
-
|
148
|
+
redis.hset(heartbeat_key, heartbeat_field, time.to_i)
|
148
149
|
end
|
149
150
|
|
150
151
|
def heartbeat_field
|
data/lib/zhong/version.rb
CHANGED
data/test/test_library.rb
CHANGED
@@ -24,7 +24,27 @@ class TestLibrary < Minitest::Test
|
|
24
24
|
assert_equal true, Zhong.any_running?
|
25
25
|
assert_in_delta Zhong.redis_time.to_f, Time.now.to_f, 1
|
26
26
|
assert_in_delta Zhong.redis_time.to_f, Zhong.latest_heartbeat.to_f, 1
|
27
|
+
refute_empty Zhong.all_heartbeats
|
27
28
|
Zhong.stop
|
28
29
|
t.join
|
29
30
|
end
|
31
|
+
|
32
|
+
def test_redis_change
|
33
|
+
Zhong.schedule { nil }
|
34
|
+
t = Thread.new { Zhong.start }
|
35
|
+
sleep(1)
|
36
|
+
assert_equal true, Zhong.any_running?
|
37
|
+
test_redis = Zhong.redis
|
38
|
+
Zhong.stop
|
39
|
+
t.join
|
40
|
+
Zhong.redis = Redis.new(url: "redis://localhost/15")
|
41
|
+
refute Zhong.any_running?(5.seconds)
|
42
|
+
t = Thread.new { Zhong.start }
|
43
|
+
sleep(1)
|
44
|
+
assert_equal true, Zhong.any_running?
|
45
|
+
assert_in_delta Zhong.redis_time.to_f, Time.now.to_f, 1
|
46
|
+
Zhong.stop
|
47
|
+
Zhong.redis = test_redis
|
48
|
+
t.join
|
49
|
+
end
|
30
50
|
end
|
data/test/test_web.rb
CHANGED
@@ -32,8 +32,13 @@ class TestWeb < Minitest::Test
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def test_disable_job
|
35
|
+
test_before_disable = 0
|
36
|
+
test_after_disable = 0
|
37
|
+
|
35
38
|
Zhong.schedule do
|
36
39
|
every(30.seconds, "test_disable_web_job") { nil }
|
40
|
+
on(:before_disable) { test_before_disable += 1 }
|
41
|
+
on(:after_disable) { test_after_disable += 1 }
|
37
42
|
end
|
38
43
|
|
39
44
|
job = Zhong.scheduler.find_by_name("test_disable_web_job")
|
@@ -48,11 +53,18 @@ class TestWeb < Minitest::Test
|
|
48
53
|
assert_contains "every 30 seconds", last_response.body
|
49
54
|
assert_contains 'name="enable"', last_response.body
|
50
55
|
assert_equal true, job.disabled?
|
56
|
+
assert_equal 1, test_before_disable
|
57
|
+
assert_equal 1, test_after_disable
|
51
58
|
end
|
52
59
|
|
53
60
|
def test_enable_job
|
61
|
+
test_before_enable = 0
|
62
|
+
test_after_enable = 0
|
63
|
+
|
54
64
|
Zhong.schedule do
|
55
65
|
every(12.hours, "test_enable_web_job") { nil }
|
66
|
+
on(:before_enable) { test_before_enable += 1 }
|
67
|
+
on(:after_enable) { test_after_enable += 1 }
|
56
68
|
end
|
57
69
|
|
58
70
|
job = Zhong.scheduler.find_by_name("test_enable_web_job")
|
@@ -67,6 +79,8 @@ class TestWeb < Minitest::Test
|
|
67
79
|
assert_contains "every 12 hours", last_response.body
|
68
80
|
assert_contains 'name="disable"', last_response.body
|
69
81
|
assert_equal false, job.disabled?
|
82
|
+
assert_equal 1, test_before_enable
|
83
|
+
assert_equal 1, test_after_enable
|
70
84
|
end
|
71
85
|
|
72
86
|
def test_heartbeat
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: zhong
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Elser
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-10-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: suo
|
@@ -288,4 +288,3 @@ test_files:
|
|
288
288
|
- test/test_library.rb
|
289
289
|
- test/test_scheduler.rb
|
290
290
|
- test/test_web.rb
|
291
|
-
has_rdoc:
|