runaway 1.0.0 → 1.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/runaway.rb +10 -2
- data/runaway.gemspec +3 -3
- data/spec/runaway_spec.rb +21 -6
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee88a2e47d1bf2847893a4b258d236efcfff3fae
|
4
|
+
data.tar.gz: f3edef5cc5fae9363f1d56978c0465b56faa0a24
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0489708f0657aeb6e7b91c7f23e2007974d22577afe01b9c04b2dca6d12a9fcdbdf68cdbb965b75970351333eab45ec6a1599f3d34a3727abda9f8daa47ab248
|
7
|
+
data.tar.gz: 34eeca38ad28dfb7b205a40b9517f3b3123683a9fdd466031b848bd1780f9b67e1b477c3a1d10104b412b36ee80df21c33e1ab2dfcf5af799e0b0f86963d3ede
|
data/lib/runaway.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'securerandom'
|
2
2
|
|
3
3
|
module Runaway
|
4
|
-
VERSION = '1.0.
|
4
|
+
VERSION = '1.0.1'
|
5
5
|
|
6
6
|
UncleanExit = Class.new(StandardError)
|
7
7
|
Child = Class.new(StandardError)
|
@@ -49,9 +49,12 @@ module Runaway
|
|
49
49
|
(Process.kill(sig, child_pid) rescue Errno::ESRCH) if !has_quit
|
50
50
|
}
|
51
51
|
|
52
|
+
last_heartbeat_sent = started_at
|
52
53
|
begin
|
53
54
|
loop do
|
54
|
-
sleep
|
55
|
+
sleep 0.5
|
56
|
+
|
57
|
+
break if has_quit
|
55
58
|
|
56
59
|
# First check if it has exceeded it's wall clock time allowance
|
57
60
|
running_for = Time.now - started_at
|
@@ -60,6 +63,11 @@ module Runaway
|
|
60
63
|
child_pid, running_for, must_quit_within])
|
61
64
|
end
|
62
65
|
|
66
|
+
# Then check if it is time to poke it with a heartbeat
|
67
|
+
at = Time.now
|
68
|
+
next if (at - last_heartbeat_sent) < heartbeat_interval
|
69
|
+
last_heartbeat_sent = at
|
70
|
+
|
63
71
|
# Then send it the USR2 as a "ping", and expect a "pong" in
|
64
72
|
# the form of a pipe write. If the pipe is still not readable
|
65
73
|
# after a certain time, we assume the process has hung.
|
data/runaway.gemspec
CHANGED
@@ -2,16 +2,16 @@
|
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
3
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
|
-
# stub: runaway 1.0.
|
5
|
+
# stub: runaway 1.0.1 ruby lib
|
6
6
|
|
7
7
|
Gem::Specification.new do |s|
|
8
8
|
s.name = "runaway"
|
9
|
-
s.version = "1.0.
|
9
|
+
s.version = "1.0.1"
|
10
10
|
|
11
11
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
12
12
|
s.require_paths = ["lib"]
|
13
13
|
s.authors = ["Julik Tarkhanov"]
|
14
|
-
s.date = "2016-
|
14
|
+
s.date = "2016-03-01"
|
15
15
|
s.description = "Spin off blocks in child processes and make sure they terminate on time"
|
16
16
|
s.email = "me@julik.nl"
|
17
17
|
s.extra_rdoc_files = [
|
data/spec/runaway_spec.rb
CHANGED
@@ -17,15 +17,17 @@ describe "Runaway" do
|
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
context 'with a process that
|
20
|
+
context 'with a process that exceeds the maximum runtime' do
|
21
21
|
it 'terminates the process' do
|
22
|
+
start_at = Time.now
|
22
23
|
expect {
|
23
24
|
Runaway.spin(must_quit_within: 3) do
|
24
|
-
sleep
|
25
|
+
sleep 30
|
25
26
|
end
|
26
27
|
}.to raise_error {|err|
|
27
28
|
expect(err).to be_kind_of(Runaway::RuntimeExceeded)
|
28
|
-
expect(err.message).to match(/\d+ did not terminate after
|
29
|
+
expect(err.message).to match(/\d+ did not terminate after \d+ secs \(limited to 3 secs\)/)
|
30
|
+
expect(Time.now - start_at).to be < 5 # Ensure it was killed quickly
|
29
31
|
}
|
30
32
|
end
|
31
33
|
end
|
@@ -41,13 +43,26 @@ describe "Runaway" do
|
|
41
43
|
end
|
42
44
|
end
|
43
45
|
|
46
|
+
context 'when a process terminates before the first heartbeat has to be dispatched' do
|
47
|
+
it 'just returns :done' do
|
48
|
+
t = Time.now
|
49
|
+
return_token = Runaway.spin(heartbeat_interval: 5) { sleep 0.1 }
|
50
|
+
expect(return_token).to eq(:done)
|
51
|
+
delta = Time.now - t
|
52
|
+
expect(delta).to be < 2
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
44
56
|
context 'when a process stops responding to heartbeats' do
|
45
|
-
it 'raises an error' do
|
57
|
+
it 'kills it quickly and raises an error' do
|
58
|
+
t = Time.now
|
46
59
|
expect {
|
47
|
-
|
60
|
+
# Delete, then override the USR2 trap so that heartbeats do not get handled at all
|
61
|
+
Runaway.spin(heartbeat_interval: 0.8) { trap('USR2', 'DEFAULT'); trap('USR2') {}; sleep 45 }
|
48
62
|
}.to raise_error {|err|
|
49
63
|
expect(err).to be_kind_of(Runaway::HeartbeatTimeout)
|
50
|
-
expect(err.message).to match(/\d+ did not reply to heartbeat after
|
64
|
+
expect(err.message).to match(/\d+ did not reply to heartbeat after \d+ secs/)
|
65
|
+
expect(Time.now - t).to be < 5 # should really ahve killed it fast
|
51
66
|
}
|
52
67
|
end
|
53
68
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: runaway
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Julik Tarkhanov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-03-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|