runaway 1.0.1 → 2.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ee88a2e47d1bf2847893a4b258d236efcfff3fae
4
- data.tar.gz: f3edef5cc5fae9363f1d56978c0465b56faa0a24
3
+ metadata.gz: 8140c09b38d805e869821a9e25fcc4807de4931f
4
+ data.tar.gz: 44fe561135e1fb3b8abb21094f20fc2435ecdea4
5
5
  SHA512:
6
- metadata.gz: 0489708f0657aeb6e7b91c7f23e2007974d22577afe01b9c04b2dca6d12a9fcdbdf68cdbb965b75970351333eab45ec6a1599f3d34a3727abda9f8daa47ab248
7
- data.tar.gz: 34eeca38ad28dfb7b205a40b9517f3b3123683a9fdd466031b848bd1780f9b67e1b477c3a1d10104b412b36ee80df21c33e1ab2dfcf5af799e0b0f86963d3ede
6
+ metadata.gz: d46f84a99dd4e7e84ccab8779c67e67264bd6bb4e35ce56d3418d0115d0e9617001faabe1224b5ed26455c7d3e14777fb8982b487c95e64579b780ccedc82180
7
+ data.tar.gz: 8dd7da8f9d6f8fc92c886d68d4b2c6be7bb8f785140ef82f215d47751465100baaa009a69d2542d1529b2a14af2de258d55ed2bf5b738dccc51f917ddff6e0e6
data/README.md CHANGED
@@ -1,18 +1,9 @@
1
1
  # runaway
2
2
 
3
- Spin off work into child processes and terminate it on time
3
+ Spin off work into child processes and terminate it on time. If you need the process to be done
4
+ within a certain time period (and if it takes longer it probably is hanging):
4
5
 
5
- To simply ensure the process keeps responding (the Ruby runtime still can do context-switching
6
- and can respond to Unix signals):
7
-
8
- Runaway.spin do
9
- ActiveRAMGobbler.load_many_things(num_things: 10_000_000)
10
- end
11
-
12
- If you need the process to be done within a certain time period (and if it takes longer
13
- it probably is hanging):
14
-
15
- Runaway.spin(must_quite_within: 15) do # ensures termination within 15 seconds
6
+ Runaway.spin(must_quit_within: 15) do # ensures termination within 15 seconds
16
7
  `/bin/proprietary_render_server/bin/render --put-server-on-fire=yes`
17
8
  end
18
9
 
@@ -1,14 +1,10 @@
1
- require 'securerandom'
2
-
3
1
  module Runaway
4
- VERSION = '1.0.1'
2
+ VERSION = '2.0.0'
5
3
 
6
4
  UncleanExit = Class.new(StandardError)
7
5
  Child = Class.new(StandardError)
8
- HeartbeatTimeout = Class.new(Child)
9
6
  RuntimeExceeded = Class.new(Child)
10
7
 
11
- DEFAULT_HEARTBEAT_INTERVAL = 2
12
8
  TERM = 'TERM'.freeze
13
9
  KILL = 'KILL'.freeze
14
10
  USR2 = 'USR2'.freeze
@@ -18,20 +14,12 @@ module Runaway
18
14
  # Acts as a substitute for a Logger
19
15
  module NullLogger; def self.warn(*); end; end
20
16
 
21
- def self.spin(must_quit_within: INF, heartbeat_interval: DEFAULT_HEARTBEAT_INTERVAL,
22
- logger: NullLogger, &block_to_run_in_child)
23
- cookie = SecureRandom.hex(1)
24
- r, w = IO.pipe
17
+ def self.spin(must_quit_within: INF, logger: NullLogger, &block_to_run_in_child)
25
18
  child_pid = fork do
26
- r.close_read
27
19
  # Remove anything that was there from the parent
28
- [USR2, TERM, KILL].each { |reset_sig| trap(reset_sig, DEFAULT) }
29
-
30
- # When the parent asks us for a heartbeat, send the cookie back
31
- trap(USR2) { w.write(cookie); w.flush }
20
+ [TERM, KILL].each { |reset_sig| trap(reset_sig, DEFAULT) }
32
21
  block_to_run_in_child.call
33
22
  end
34
- w.close_write
35
23
 
36
24
  started_at = Time.now
37
25
 
@@ -49,10 +37,9 @@ module Runaway
49
37
  (Process.kill(sig, child_pid) rescue Errno::ESRCH) if !has_quit
50
38
  }
51
39
 
52
- last_heartbeat_sent = started_at
53
40
  begin
54
41
  loop do
55
- sleep 0.5
42
+ sleep 1
56
43
 
57
44
  break if has_quit
58
45
 
@@ -62,22 +49,6 @@ module Runaway
62
49
  raise RuntimeExceeded.new('%d did not terminate after %d secs (limited to %d secs)' % [
63
50
  child_pid, running_for, must_quit_within])
64
51
  end
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
-
71
- # Then send it the USR2 as a "ping", and expect a "pong" in
72
- # the form of a pipe write. If the pipe is still not readable
73
- # after a certain time, we assume the process has hung.
74
- Process.kill(USR2, child_pid)
75
- select_timeout = (heartbeat_interval * 2)
76
- ready_read = IO.select([r], [], [], select_timeout)
77
- if ready_read.nil?
78
- raise HeartbeatTimeout.new('%d did not reply to heartbeat after %d secs' % [child_pid, select_timeout])
79
- end
80
- r.read(cookie.bytesize)
81
52
  end
82
53
  rescue Runaway => terminating_error
83
54
  logger.error "Terminating %d - %s: %s" % [child_pid, terminating_error.class, terminating_error.message]
@@ -97,7 +68,5 @@ module Runaway
97
68
  raise unclean_exit_error if unclean_exit_error
98
69
 
99
70
  :done
100
- ensure
101
- r.close_read
102
71
  end
103
72
  end
@@ -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.1 ruby lib
5
+ # stub: runaway 2.0.0 ruby lib
6
6
 
7
7
  Gem::Specification.new do |s|
8
8
  s.name = "runaway"
9
- s.version = "1.0.1"
9
+ s.version = "2.0.0"
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-03-01"
14
+ s.date = "2016-04-07"
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 = [
@@ -5,7 +5,7 @@ describe "Runaway" do
5
5
 
6
6
  it 'supports all the options' do
7
7
  require 'logger'
8
- Runaway.spin(must_quit_within: 2, heartbeat_interval: 0.3, logger: Logger.new($stdout)) {} # just do nothing
8
+ Runaway.spin(must_quit_within: 2, logger: Logger.new($stdout)) {} # just do nothing
9
9
  end
10
10
 
11
11
  context 'with a process that quits cleanly' do
@@ -42,28 +42,4 @@ describe "Runaway" do
42
42
  }
43
43
  end
44
44
  end
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
-
56
- context 'when a process stops responding to heartbeats' do
57
- it 'kills it quickly and raises an error' do
58
- t = Time.now
59
- expect {
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 }
62
- }.to raise_error {|err|
63
- expect(err).to be_kind_of(Runaway::HeartbeatTimeout)
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
66
- }
67
- end
68
- end
69
45
  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.1
4
+ version: 2.0.0
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-03-01 00:00:00.000000000 Z
11
+ date: 2016-04-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec