serial_scheduler 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/serial_scheduler/version.rb +1 -1
- data/lib/serial_scheduler.rb +49 -14
- metadata +18 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a3176f9491c9ca41665e74892f0ec5cca612b2590ef5d259eb595f03e3a80c1a
|
4
|
+
data.tar.gz: 182974bb8a089dc7c229eaa9a23294f88cea9d17b5eaca68f8a98cc9b0fe6bc6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4f33dd9831bea10233bac83fb3dfec909ef297f5f78254dea7e87babd6191210da35c81e572762292238258d0a95faf161d957c70d6cca688bedda3e5b8cb461
|
7
|
+
data.tar.gz: 5210390830383771b3fdcc69756116fd644f452e58b2c41ac6cfe3ef981329ac09c5792f3a6b0faefb8599652051dcfe4bbee4c5802ad5ab059a240509a80cfd
|
data/lib/serial_scheduler.rb
CHANGED
@@ -5,6 +5,44 @@ require 'json'
|
|
5
5
|
require 'logger'
|
6
6
|
|
7
7
|
class SerialScheduler
|
8
|
+
class Producer
|
9
|
+
attr_reader :name, :next, :timeout, :block
|
10
|
+
|
11
|
+
def initialize(name, interval: nil, timeout:, cron: nil, &block)
|
12
|
+
if cron
|
13
|
+
cron = Fugit.do_parse_cron(cron)
|
14
|
+
elsif !interval || interval < 1 || !interval.is_a?(Integer)
|
15
|
+
raise ArgumentError
|
16
|
+
end
|
17
|
+
|
18
|
+
@name = name
|
19
|
+
@interval = interval
|
20
|
+
@cron = cron
|
21
|
+
@timeout = timeout
|
22
|
+
@block = block
|
23
|
+
@next = nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def start(now)
|
27
|
+
@next =
|
28
|
+
if @cron
|
29
|
+
@cron.next_time(Time.at(now)).to_i
|
30
|
+
else
|
31
|
+
# interval 1s: do not wait
|
32
|
+
# interval 1d: if we are 1 hour into the day next execution is in 23 hours
|
33
|
+
now + (@interval - (now % @interval) - 1)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def next!
|
38
|
+
if @cron
|
39
|
+
@next = @cron.next_time(Time.at(@next)).to_i
|
40
|
+
else
|
41
|
+
@next += @interval
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
8
46
|
def initialize(logger: Logger.new(STDOUT), error_handler: ->(e) { raise e })
|
9
47
|
@logger = logger
|
10
48
|
@error_handler = error_handler
|
@@ -14,24 +52,21 @@ class SerialScheduler
|
|
14
52
|
end
|
15
53
|
|
16
54
|
# start a new thread that enqueues an execution at given interval
|
17
|
-
def add(
|
18
|
-
|
19
|
-
|
20
|
-
@producers << { name: name, interval: interval, timeout: timeout, block: block, next: 0 }
|
55
|
+
def add(*args, &block)
|
56
|
+
@producers << Producer.new(*args, &block)
|
21
57
|
end
|
22
58
|
|
23
59
|
def run
|
24
|
-
# interval 1s: do not wait
|
25
|
-
# interval 1d: if we are 1 hour into the day next execution is in 23 hours
|
26
60
|
now = Time.now.to_i
|
27
|
-
@producers.each { |p| p
|
61
|
+
@producers.each { |p| p.start now }
|
28
62
|
|
29
63
|
loop do
|
30
|
-
|
31
|
-
|
64
|
+
now = Time.now.to_i
|
65
|
+
earliest = @producers.min_by(&:next)
|
66
|
+
wait = [earliest.next - now, 0].max # do not wait when overdue
|
32
67
|
|
33
68
|
if wait > 0
|
34
|
-
@logger.info message: "Waiting to start job", job: earliest
|
69
|
+
@logger.info message: "Waiting to start job", job: earliest.name, time: wait, at: Time.at(now).to_s
|
35
70
|
wait.times do
|
36
71
|
break if @stopped
|
37
72
|
|
@@ -40,7 +75,7 @@ class SerialScheduler
|
|
40
75
|
end
|
41
76
|
break if @stopped
|
42
77
|
|
43
|
-
earliest
|
78
|
+
earliest.next!
|
44
79
|
execute_in_fork earliest
|
45
80
|
end
|
46
81
|
end
|
@@ -52,12 +87,12 @@ class SerialScheduler
|
|
52
87
|
private
|
53
88
|
|
54
89
|
def execute_in_fork(producer)
|
55
|
-
@logger.info message: "Executing job", job: producer
|
90
|
+
@logger.info message: "Executing job", job: producer.name
|
56
91
|
pid = fork do
|
57
92
|
begin
|
58
|
-
Timeout.timeout producer
|
93
|
+
Timeout.timeout producer.timeout, &producer.block
|
59
94
|
rescue StandardError => e # do not rescue `Exception` so it can be `Interrupt`-ed
|
60
|
-
@logger.error message: "Error in job", job: producer
|
95
|
+
@logger.error message: "Error in job", job: producer.name, error: e.message
|
61
96
|
@error_handler.call(e)
|
62
97
|
end
|
63
98
|
end
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: serial_scheduler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Grosser
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
11
|
+
date: 2020-03-14 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: fugit
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
description:
|
14
28
|
email: michael@grosser.it
|
15
29
|
executables: []
|
@@ -38,8 +52,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
38
52
|
- !ruby/object:Gem::Version
|
39
53
|
version: '0'
|
40
54
|
requirements: []
|
41
|
-
|
42
|
-
rubygems_version: 2.7.6
|
55
|
+
rubygems_version: 3.0.3
|
43
56
|
signing_key:
|
44
57
|
specification_version: 4
|
45
58
|
summary: Simple scheduler for long-running and infrequent tasks, no threads, always
|