schedulero 0.1.1 → 0.2.3
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/.version +1 -1
- data/lib/schedulero.rb +112 -63
- data/lib/utils.rb +30 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2cfd26c98933e9a712a4352b8bae35e58e352389584db91bea451744d2b1ecb2
|
4
|
+
data.tar.gz: 8f3781c8e20b9b054711de0f22531e047807565d21749ad94c69597f7b7df0e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dcf894b27957183ccdeb7d2ca2a37902cfbe7a5093e5ecd752adc599e14e46ad13da55f66f0ffcef194d754ed01e43cb9d214f778528f48376830bf840b8584b
|
7
|
+
data.tar.gz: 1e0d99eb6a9cafc56b40a7b88ceb479900f9e1aee3ac29cc487bbc2bf4062dc376d625c4a5a4cd6c9917886748f1945dd70659e4978597ba773d45fee8b8c94f
|
data/.version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.3
|
data/lib/schedulero.rb
CHANGED
@@ -3,110 +3,159 @@ require 'json'
|
|
3
3
|
require 'logger'
|
4
4
|
require 'colorize'
|
5
5
|
require 'as-duration'
|
6
|
+
require 'pp'
|
7
|
+
|
8
|
+
require_relative './utils'
|
6
9
|
|
7
10
|
class Schedulero
|
11
|
+
include Schedulero::Utils
|
12
|
+
|
13
|
+
attr_reader :tasks, :logger
|
14
|
+
|
8
15
|
def initialize state_file: nil, log_file: true
|
16
|
+
init_log log_file
|
17
|
+
init_state state_file
|
9
18
|
|
19
|
+
@tasks = {}
|
20
|
+
@running = {}
|
21
|
+
@count = 0
|
22
|
+
end
|
23
|
+
|
24
|
+
def init_state state_file
|
25
|
+
# state file
|
26
|
+
state_file ||= "./tmp/schedulero.json"
|
27
|
+
puts 'State file: %s' % state_file
|
28
|
+
|
29
|
+
@state_file = Pathname.new state_file
|
30
|
+
@state_file.write '{}' unless @state_file.exist?
|
31
|
+
end
|
32
|
+
|
33
|
+
def init_log log_file
|
10
34
|
# log file
|
11
35
|
log_file = case log_file
|
12
36
|
when String
|
13
37
|
log_file
|
14
|
-
when true
|
15
|
-
'./log/schedulero.log'
|
16
38
|
when false
|
17
39
|
nil
|
40
|
+
else
|
41
|
+
"./log/schedulero.log'"
|
18
42
|
end
|
19
43
|
|
20
|
-
|
21
|
-
@logger.datetime_format = "%Y-%m-%d %H:%M:%S"
|
44
|
+
puts 'Log file : %s' % log_file
|
22
45
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
end
|
28
|
-
|
29
|
-
@state_file = Pathname.new state_file
|
30
|
-
|
31
|
-
if @state_file.exist?
|
32
|
-
@state = JSON.load @state_file.read
|
33
|
-
else
|
34
|
-
@state = {}
|
46
|
+
@logger = Logger.new log_file
|
47
|
+
@logger.formatter = proc do |severity, datetime, progname, msg|
|
48
|
+
severity = severity == 'INFO' ? '' : "(#{severity}) "
|
49
|
+
"[#{datetime.strftime('%Y-%m-%d %H:%M:%S')}]: #{severity}#{msg}\n"
|
35
50
|
end
|
36
51
|
end
|
37
52
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
53
|
+
# add task
|
54
|
+
def every name, seconds, proc=nil, &block
|
55
|
+
proc ||= block
|
56
|
+
@tasks[name] = { interval: seconds , func: proc, name: name }
|
57
|
+
end
|
42
58
|
|
43
|
-
|
59
|
+
# run task at specific hours
|
60
|
+
def at name, hours, proc=nil, &block
|
61
|
+
proc ||= block
|
62
|
+
@tasks[name] = { at: hours , func: proc, name: name }
|
44
63
|
end
|
45
64
|
|
46
|
-
def
|
47
|
-
|
65
|
+
def run_forever interval: 3
|
66
|
+
Thread.new do
|
67
|
+
loop do
|
68
|
+
puts 'looping ...'
|
69
|
+
run
|
70
|
+
sleep interval
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
48
74
|
|
49
|
-
|
50
|
-
|
75
|
+
# run all tasks once, safe
|
76
|
+
def run
|
77
|
+
state = JSON.load @state_file.read
|
51
78
|
|
52
|
-
|
53
|
-
|
79
|
+
state['_pid'] ||= Process.pid
|
80
|
+
state['_last_run'] ||= Time.now.to_i
|
81
|
+
diff = Time.now.to_i - state['_last_run']
|
54
82
|
|
55
|
-
|
83
|
+
# if another process is controlling state, exit
|
84
|
+
if state['_pid'] != Process.pid && diff < 10
|
85
|
+
puts "Another process [#{state['_pid']}] is controlling state before #{diff} sec, skipping. I am (#{Process.pid})".red
|
86
|
+
return
|
87
|
+
end
|
56
88
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
89
|
+
for name, block in @tasks
|
90
|
+
state[name] ||= 0
|
91
|
+
now = Time.now.to_i
|
92
|
+
|
93
|
+
if block[:at]
|
94
|
+
# run at specific times
|
95
|
+
hour_now = Time.now.hour
|
96
|
+
hours = block[:at].class == Array ? block[:at] : [block[:at]]
|
97
|
+
|
98
|
+
if hours.include?(hour_now) && (Time.now.to_i - state[name] > 3700)
|
99
|
+
state[name] = now
|
100
|
+
safe_run block
|
101
|
+
end
|
102
|
+
else
|
103
|
+
# run in intervals
|
104
|
+
seconds = block[:interval]
|
105
|
+
diff = (state[name].to_i + seconds.to_i) - now
|
106
|
+
|
107
|
+
if diff < 0
|
108
|
+
state[name] = now
|
109
|
+
safe_run block
|
110
|
+
else
|
111
|
+
puts 'skipping "%s" for %s' % [name, humanize_seconds(diff)]
|
112
|
+
end
|
62
113
|
end
|
63
|
-
else
|
64
|
-
puts 'skipping "%s" for %s' % [name, humanize_seconds(diff)]
|
65
114
|
end
|
115
|
+
|
116
|
+
state['_last_run'] = Time.now.to_i
|
117
|
+
state['_pid'] = Process.pid
|
118
|
+
|
119
|
+
@state_file.write state.to_json
|
66
120
|
end
|
67
121
|
|
68
|
-
|
69
|
-
|
122
|
+
# run in rescue mode, kill if still running
|
123
|
+
def safe_run block
|
124
|
+
name = block[:name]
|
70
125
|
|
71
|
-
|
72
|
-
|
126
|
+
puts 'Running "%s"' % name.green
|
127
|
+
@logger.info 'Run: %s' % name
|
73
128
|
|
74
|
-
if
|
75
|
-
|
129
|
+
if block[:running]
|
130
|
+
log_errror "Task [#{block[:name]}] is still running, killing..."
|
131
|
+
Thread.kill(block[:running])
|
132
|
+
end
|
76
133
|
|
77
|
-
|
134
|
+
thread = Thread.start(block) do |b|
|
135
|
+
block[:running] = thread
|
78
136
|
|
79
137
|
begin
|
80
|
-
@
|
81
|
-
|
138
|
+
@count += 1
|
139
|
+
b[:func].call @count
|
82
140
|
rescue
|
83
|
-
log_errror name
|
141
|
+
log_errror b[:name]
|
84
142
|
end
|
85
|
-
|
86
|
-
|
143
|
+
|
144
|
+
b[:running] = false
|
87
145
|
end
|
88
146
|
end
|
89
147
|
|
148
|
+
# show and log error
|
90
149
|
def log_errror name
|
91
|
-
msg =
|
92
|
-
|
150
|
+
msg = if $!
|
151
|
+
'%s: %s (%s)' % [name, $!.message, $!.class]
|
152
|
+
else
|
153
|
+
name
|
154
|
+
end
|
93
155
|
|
94
|
-
|
156
|
+
puts msg.red
|
95
157
|
|
96
158
|
@logger.error(msg)
|
97
159
|
end
|
98
|
-
|
99
|
-
def humanize_seconds secs
|
100
|
-
return '-' unless secs
|
101
|
-
|
102
|
-
secs = secs.to_i
|
103
|
-
|
104
|
-
[[60, :sec], [60, :min], [24, :h], [356, :days], [1000, :years]].map{ |count, name|
|
105
|
-
if secs > 0
|
106
|
-
secs, n = secs.divmod(count)
|
107
|
-
"#{n.to_i} #{name}"
|
108
|
-
end
|
109
|
-
}.compact.reverse.slice(0,2).join(' ')
|
110
|
-
end
|
111
160
|
end
|
112
161
|
|
data/lib/utils.rb
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
class Schedulero
|
2
|
+
module Utils
|
3
|
+
def humanize_seconds secs
|
4
|
+
return '-' unless secs
|
5
|
+
|
6
|
+
secs = secs.to_i
|
7
|
+
|
8
|
+
[[60, :sec], [60, :min], [24, :h], [356, :days], [1000, :years]].map{ |count, name|
|
9
|
+
if secs > 0
|
10
|
+
secs, n = secs.divmod(count)
|
11
|
+
"#{n.to_i} #{name}"
|
12
|
+
end
|
13
|
+
}.compact.reverse.slice(0,2).join(' ')
|
14
|
+
end
|
15
|
+
|
16
|
+
def quick_overview lines: 100
|
17
|
+
data = ['Tasks:']
|
18
|
+
|
19
|
+
for name, task in tasks
|
20
|
+
data.push '- %s, every %s' % [name, humanize_seconds(task[:interval])]
|
21
|
+
end
|
22
|
+
|
23
|
+
data.push ['','###', '']
|
24
|
+
|
25
|
+
data.push `tail -#{lines} ./log/schedulero.log`.split($/).reverse
|
26
|
+
|
27
|
+
data.join($/)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: schedulero
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dino Reic
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-03-
|
11
|
+
date: 2018-03-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: as-duration
|
@@ -46,6 +46,7 @@ extra_rdoc_files: []
|
|
46
46
|
files:
|
47
47
|
- "./.version"
|
48
48
|
- "./lib/schedulero.rb"
|
49
|
+
- "./lib/utils.rb"
|
49
50
|
homepage: https://github.com/dux/schedulero
|
50
51
|
licenses:
|
51
52
|
- MIT
|