serial_scheduler 0.1.0 → 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/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
|