in-parallel 0.1.15 → 0.1.16

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 0b5dc6a05d28155a49a6c5d07c3be8385583ef58
4
- data.tar.gz: 6eb5ddb93219985c1513a3a5f1abe23391d5590b
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ NGJlY2ZkMDkyMjM3MGE4NGIxNjljNDU1YTE1NGRkYWY2OWE2NjZkZA==
5
+ data.tar.gz: !binary |-
6
+ ZmQ4NmExZGJmYmZiNDM5NjM1MWQ1OGM5MTMwMGMwMjYzMDdjY2ViOQ==
5
7
  SHA512:
6
- metadata.gz: 5f36a6e1b63a18514c9e17713d95d29725c5b6ddfb7cd91074a8e8b25c3bc8004dbcd272fad00c82ac4e155931673bc494d83497b8310e54dca074dabe384d39
7
- data.tar.gz: 2a1d6707489ebe47beec5c6959394b66c57926843f377ff5cf24bad66124935afe35a1f171e84c2266e6ab2c229d2085168c8ceb6244c0846977fb534c11330a
8
+ metadata.gz: !binary |-
9
+ MGFjZTBkNGUzYTEwYWFkMDY0YWVhNGIxNjc2MzhkOWUwNTg5Y2NjNmQxOTAy
10
+ ZjAwNTliZWJmZTU4NjU1ODg0OGExNmRkZTljMzk0OWQyZGU2ODFhOWQ3ZTUw
11
+ ZWQzNTRkMjY5YzM5MGYyZGViNGY4MjVhMjQwMDExYjE5MTQ3ZWY=
12
+ data.tar.gz: !binary |-
13
+ OWEyOGQ2MWJiY2RiZTVhNTMxM2VhNDllM2MwNmM2ZTVjNWVhNjljMjcxZDU4
14
+ NWIxNTAxNzMyZDM1YWZlYjhhOWQ2Y2I0NzRmNGZmOWJlN2EzOTlhYTA5ZTk2
15
+ NDZlZGVhYmYyYzFkOTcwN2E0MWY4NjQ1NTEzOGZmMGE0OGE0MWM=
data/HISTORY.md CHANGED
@@ -1,10 +1,65 @@
1
1
  # experimental_in-parallel_bump_and_tag_master - History
2
2
  ## Tags
3
- * [LATEST - 8 Aug, 2016 (d026c624)](#LATEST)
3
+ * [LATEST - 6 Feb, 2017 (27b497ea)](#LATEST)
4
+ * [0.1.15 - 3 Feb, 2017 (ff16929c)](#0.1.15)
5
+ * [0.1.14 - 8 Aug, 2016 (ce331dbd)](#0.1.14)
4
6
  * [0.1.13 - 8 Aug, 2016 (26d19934)](#0.1.13)
5
7
 
6
8
  ## Details
7
- ### <a name = "LATEST">LATEST - 8 Aug, 2016 (d026c624)
9
+ ### <a name = "LATEST">LATEST - 6 Feb, 2017 (27b497ea)
10
+
11
+ * (GEM) update in-parallel version to 0.1.16 (27b497ea)
12
+
13
+ ### <a name = "0.1.15">0.1.15 - 3 Feb, 2017 (ff16929c)
14
+
15
+ * (HISTORY) update in-parallel history for gem release 0.1.15 (ff16929c)
16
+
17
+ * (GEM) update in-parallel version to 0.1.15 (206a62fe)
18
+
19
+ * Merge pull request #16 from nicklewis/support-large-results (4d644d88)
20
+
21
+
22
+ ```
23
+ Merge pull request #16 from nicklewis/support-large-results
24
+
25
+ (maint) Avoid deadlock with large results
26
+ ```
27
+ * (maint) Avoid deadlock with large results (a5a9c174)
28
+
29
+
30
+ ```
31
+ (maint) Avoid deadlock with large results
32
+
33
+ Previously, if the result of a process was larger than the IO buffer
34
+ size (commonly 64k), execution would deadlock until the timeout.
35
+
36
+ In this scenario, the writer would fill the buffer and block until the
37
+ reader had cleared the buffer by reading. However, the reader will only
38
+ try to read once (to get the whole result) and will only attempt to read
39
+ after the child process has exited. This causes a deadlock, as the child
40
+ can't exit because it can't finish writing, but the the reader won't
41
+ read because the child hasn't exited.
42
+
43
+ This commit fixes the watcher loop to instead IO.select() from the
44
+ available result readers and read a partial result into a buffer whenever it's
45
+ available. This ensures that the writer will never remain blocked by a
46
+ full buffer. The reader now uses IO#eof? to determine whether the child
47
+ process has exited, at which point it will process the whole result as
48
+ before.
49
+ ```
50
+ * Merge pull request #15 from samwoods1/add_jjb_pipelines (72d32635)
51
+
52
+
53
+ ```
54
+ Merge pull request #15 from samwoods1/add_jjb_pipelines
55
+
56
+ (maint) Revert name change of in_parallel.rb
57
+ ```
58
+ * (maint) Revert name change of in_parallel.rb (327c8fd5)
59
+
60
+ ### <a name = "0.1.14">0.1.14 - 8 Aug, 2016 (ce331dbd)
61
+
62
+ * (HISTORY) update in-parallel history for gem release 0.1.14 (ce331dbd)
8
63
 
9
64
  * (GEM) update in-parallel version to 0.1.14 (d026c624)
10
65
 
@@ -1,3 +1,3 @@
1
1
  module InParallel
2
- VERSION = '0.1.15'
2
+ VERSION = '0.1.16'
3
3
  end
@@ -126,34 +126,37 @@ module InParallel
126
126
  kill_child_processes
127
127
  raise_error = ::RuntimeError.new("Child process ran longer than timeout of #{timeout}")
128
128
  end
129
- @@process_infos.each do |process_info|
130
- # wait up to half a second for each thread to see if it is complete, if not, check the next thread.
131
- # returns immediately if the process has completed.
132
- thr = process_info[:wait_thread].join(0.5)
133
- unless thr.nil?
134
- # the process completed, get the result and rethrow on error.
135
- begin
136
- # Print the STDOUT and STDERR for each process with signals for start and end
137
- @@logger.info "------ Begin output for #{process_info[:method_sym]} - #{process_info[:pid]}"
138
- # Content from the other thread will already be pre-pended with log stuff (info, warn, date/time, etc)
139
- # So don't use logger, just use puts.
140
- puts " " + File.new(process_info[:std_out], 'r').readlines.join(" ")
141
- @@logger.info "------ Completed output for #{process_info[:method_sym]} - #{process_info[:pid]}"
142
- result = process_info[:result].read
143
- marshalled_result = (result.nil? || result.empty?) ? result : Marshal.load(result)
144
- # Kill all other processes and let them log their stdout before re-raising
145
- # if a child process raised an error.
146
- if marshalled_result.is_a?(Exception)
147
- raise_error = marshalled_result.dup
148
- kill_child_processes if kill_all_on_error
149
- marshalled_result = nil
129
+
130
+ if result = IO.select(@@process_infos.map {|p| p[:result]}, nil, nil, 0.5)
131
+ read_ios = result.first
132
+ read_ios.each do |reader|
133
+ process_info = @@process_infos.find {|p| p[:result] == reader}
134
+ process_info[:result_buffer] << reader.read
135
+ if reader.eof?
136
+ result = process_info[:result_buffer].string
137
+ # the process completed, get the result and rethrow on error.
138
+ begin
139
+ # Print the STDOUT and STDERR for each process with signals for start and end
140
+ @@logger.info "------ Begin output for #{process_info[:method_sym]} - #{process_info[:pid]}"
141
+ # Content from the other thread will already be pre-pended with log stuff (info, warn, date/time, etc)
142
+ # So don't use logger, just use puts.
143
+ puts " " + File.new(process_info[:std_out], 'r').readlines.join(" ")
144
+ @@logger.info "------ Completed output for #{process_info[:method_sym]} - #{process_info[:pid]}"
145
+ marshalled_result = (result.nil? || result.empty?) ? result : Marshal.load(result)
146
+ # Kill all other processes and let them log their stdout before re-raising
147
+ # if a child process raised an error.
148
+ if marshalled_result.is_a?(Exception)
149
+ raise_error = marshalled_result.dup
150
+ kill_child_processes if kill_all_on_error
151
+ marshalled_result = nil
152
+ end
153
+ results_map[process_info[:index]] = { process_info[:tmp_result] => marshalled_result }
154
+ ensure
155
+ File.delete(process_info[:std_out]) if File.exists?(process_info[:std_out])
156
+ # close the read end pipe
157
+ process_info[:result].close unless process_info[:result].closed?
158
+ @@process_infos.delete(process_info)
150
159
  end
151
- results_map[process_info[:index]] = { process_info[:tmp_result] => marshalled_result }
152
- ensure
153
- File.delete(process_info[:std_out]) if File.exists?(process_info[:std_out])
154
- # close the read end pipe
155
- process_info[:result].close unless process_info[:result].closed?
156
- @@process_infos.delete(process_info)
157
160
  end
158
161
  end
159
162
  end
@@ -235,6 +238,7 @@ module InParallel
235
238
  :std_out => "tmp/pp_#{pid}",
236
239
  :result => read_result,
237
240
  :tmp_result => "unresolved_parallel_result_#{@@result_id}",
241
+ :result_buffer => StringIO.new,
238
242
  :index => @@process_infos.count }
239
243
  @@process_infos.push(process_info)
240
244
  @@result_id += 1
@@ -101,6 +101,19 @@ describe '.run_in_parallel' do
101
101
  expect(@result_2).to eq({ :foo => "bar" })
102
102
  end
103
103
 
104
+ it "should return large results" do
105
+ # 2**16 = 64k is typical buffer size
106
+ long_string = 'a' * (2**16+1)
107
+
108
+ expect do
109
+ run_in_parallel(timeout=1) do
110
+ @result = method_with_param(long_string)
111
+ end
112
+ end.not_to raise_error
113
+
114
+ expect(@result).to eq "bar + #{long_string}"
115
+ end
116
+
104
117
  it "should return a singleton class value" do
105
118
 
106
119
  run_in_parallel { @result = get_singleton_class }
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: in-parallel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.15
4
+ version: 0.1.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - samwoods1
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-08-08 00:00:00.000000000 Z
11
+ date: 2017-02-06 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: Many other Ruby libraries that simplify parallel execution support one
14
14
  primary use case - crunching through a large queue of small, similar tasks as quickly
@@ -26,7 +26,6 @@ extra_rdoc_files: []
26
26
  files:
27
27
  - CONTRIBUTING.md
28
28
  - Gemfile
29
- - Gemfile.lock
30
29
  - HISTORY.md
31
30
  - LICENSE
32
31
  - MAINTAINERS.md
@@ -47,20 +46,19 @@ require_paths:
47
46
  - lib
48
47
  required_ruby_version: !ruby/object:Gem::Requirement
49
48
  requirements:
50
- - - ">="
49
+ - - ! '>='
51
50
  - !ruby/object:Gem::Version
52
51
  version: '0'
53
52
  required_rubygems_version: !ruby/object:Gem::Requirement
54
53
  requirements:
55
- - - ">="
54
+ - - ! '>='
56
55
  - !ruby/object:Gem::Version
57
56
  version: '0'
58
57
  requirements: []
59
58
  rubyforge_project:
60
- rubygems_version: 2.5.1
59
+ rubygems_version: 2.4.6
61
60
  signing_key:
62
61
  specification_version: 4
63
62
  summary: A lightweight library to execute a handful of tasks in parallel with simple
64
63
  syntax
65
64
  test_files: []
66
- has_rdoc:
@@ -1,68 +0,0 @@
1
- PATH
2
- remote: .
3
- specs:
4
- in-parallel (0.1.12)
5
-
6
- GEM
7
- remote: https://rubygems.org/
8
- specs:
9
- activesupport (4.2.6)
10
- i18n (~> 0.7)
11
- json (~> 1.7, >= 1.7.7)
12
- minitest (~> 5.1)
13
- thread_safe (~> 0.3, >= 0.3.4)
14
- tzinfo (~> 1.1)
15
- diff-lcs (1.2.5)
16
- docile (1.1.5)
17
- i18n (0.7.0)
18
- json (1.8.3)
19
- kramdown (1.11.1)
20
- logutils (0.6.1)
21
- markdown (0.4.0)
22
- kramdown (>= 0.13.7)
23
- props (>= 0.2.0)
24
- textutils (>= 0.2.0)
25
- minitest (5.9.0)
26
- props (1.1.2)
27
- rake (10.5.0)
28
- rspec (3.1.0)
29
- rspec-core (~> 3.1.0)
30
- rspec-expectations (~> 3.1.0)
31
- rspec-mocks (~> 3.1.0)
32
- rspec-core (3.1.7)
33
- rspec-support (~> 3.1.0)
34
- rspec-expectations (3.1.2)
35
- diff-lcs (>= 1.2.0, < 2.0)
36
- rspec-support (~> 3.1.0)
37
- rspec-mocks (3.1.3)
38
- rspec-support (~> 3.1.0)
39
- rspec-support (3.1.2)
40
- rubyzip (1.2.0)
41
- simplecov (0.11.2)
42
- docile (~> 1.1.0)
43
- json (~> 1.8)
44
- simplecov-html (~> 0.10.0)
45
- simplecov-html (0.10.0)
46
- textutils (1.4.0)
47
- activesupport
48
- logutils (>= 0.6.1)
49
- props (>= 1.1.2)
50
- rubyzip (>= 1.0.0)
51
- thread_safe (0.3.5)
52
- tzinfo (1.2.2)
53
- thread_safe (~> 0.1)
54
- yard (0.9.0)
55
-
56
- PLATFORMS
57
- ruby
58
-
59
- DEPENDENCIES
60
- in-parallel!
61
- markdown (~> 0)
62
- rake (>= 0.9.0)
63
- rspec (~> 3.1.0)
64
- simplecov
65
- yard (~> 0)
66
-
67
- BUNDLED WITH
68
- 1.12.3