in-parallel 0.1.12 → 0.1.15

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 71e83d885d72ee9199c9012d190f11c0e4fb7a23
4
- data.tar.gz: 62274a9de6e81cd4772ce775904e49e9340b0346
3
+ metadata.gz: 0b5dc6a05d28155a49a6c5d07c3be8385583ef58
4
+ data.tar.gz: 6eb5ddb93219985c1513a3a5f1abe23391d5590b
5
5
  SHA512:
6
- metadata.gz: a21762fb62f58b8a4b4eda90123bbefb41ed0dc078c07239b18a2ec2ba33b43ca5aadc10d99a8d7034ce31ffa662da081c8dbfc9a5030c45614160433c6a1a0e
7
- data.tar.gz: dae9561fa380ebcfcbac4ea677fb44878b30d7248f389180578a089243fa3731e9ed815e666ae64bd4337edbf30fbd1e9475b6ffe52c26dd21ba4bf0922a709d
6
+ metadata.gz: 5f36a6e1b63a18514c9e17713d95d29725c5b6ddfb7cd91074a8e8b25c3bc8004dbcd272fad00c82ac4e155931673bc494d83497b8310e54dca074dabe384d39
7
+ data.tar.gz: 2a1d6707489ebe47beec5c6959394b66c57926843f377ff5cf24bad66124935afe35a1f171e84c2266e6ab2c229d2085168c8ceb6244c0846977fb534c11330a
@@ -0,0 +1,55 @@
1
+ # How To Contribute To in-parallel
2
+
3
+ ## Getting Started
4
+
5
+ * Make sure you have a [GitHub account](https://github.com/signup/free)
6
+ * Fork the [in-parallel repository on GitHub](https://github.com/puppetlabs/in-parallel)
7
+
8
+ ## Making Changes
9
+
10
+ * Create a topic branch from where you want to base your work.
11
+ * This is the `master` branch in the case of in-parallel
12
+ * To quickly create a topic branch based on master use `git checkout -b my_contribution master`. Do not work directly on the `master` branch.
13
+ * Make commits of logical _working_ and _functional_ units.
14
+ * Check for unnecessary whitespace with `git diff --check` before committing.
15
+ * Make sure your commit messages are in the proper format.
16
+
17
+ (BKR-1234) Make the example in CONTRIBUTING imperative and concrete
18
+
19
+ Without this patch applied the example commit message in the CONTRIBUTING
20
+ document is not a concrete example. This is a problem because the
21
+ contributor is left to imagine what the commit message should look like
22
+ based on a description rather than an example. This patch fixes the
23
+ problem by making the example concrete and imperative.
24
+
25
+ The first line is a real life imperative statement with a ticket number
26
+ from our issue tracker. The body describes the behavior without the patch,
27
+ why this is a problem, and how the patch fixes the problem when applied.
28
+
29
+ * Make sure you have added [RSpec](http://rspec.info/) tests that exercise your new code. These test should be located in the appropriate `in-parallel/spec/` subdirectory. The addition of new methods/classes or the addition of code paths to existing methods/classes requires additional RSpec coverage.
30
+ * One should **NOT USE** the deprecated `should`/`stub` methods - **USE** `expect`/`allow`. Use of deprecated RSpec methods will result in your patch being rejected. See a nice blog post from 2013 on [RSpec's new message expectation syntax](http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/).
31
+ * Run the spec unit tests to assure nothing else was accidentally broken, using `rake test`
32
+ * **Bonus**: if possible ensure that `rake test` runs without failures for additional Ruby versions (1.9, 2.0, etc). in-parallel supports Ruby 1.9+, and breakage of support for other rubies will cause a patch to be rejected.
33
+ * Make sure that if you have added new functionality of sufficiently high risk, and it can not be covered adequately via unit tests (mocking, requires disk, other classes, etc), you also include acceptance tests in your PR.
34
+ * Make sure that you have added documentation using [Yard](http://yardoc.org/), new methods/classes without apporpriate documentation will be rejected.
35
+ * Run the yardoc tool to ensure that your yard documentation is properly formatted and complete
36
+ * `[bundle exec] yard doc`
37
+ * Yard docs are great for other developers, but often are difficult to read for users. If your change impacts user-facing functionality, please include changes to the human-readable markdown docs starting at README.md
38
+ * During the time that you are working on your patch the master in-parallel branch may have changed - you'll want to [rebase](http://git-scm.com/book/en/Git-Branching-Rebasing) before you submit your PR with `git rebase master`. A successful rebase ensures that your patch will cleanly merge into in-parallel.
39
+ * Submitted patches will be smoke tested through a series of acceptance level tests that ensures basic in-parallel functionality - the results of these tests will be evaluated by a in-parallel team member. Failures associated with the submitted patch will result in the patch being rejected.
40
+
41
+ ## Submitting Changes
42
+
43
+ * Sign the [Contributor License Agreement](http://links.puppet.com/cla).
44
+ * Push your changes to a topic branch in _your_ fork of the repository.
45
+ * Submit a pull request to [in-parallel](https://github.com/puppetlabs/in-parallel)
46
+ * PRs are reviewed as time permits.
47
+
48
+ # Additional Resources
49
+
50
+ * [More information on contributing](http://links.puppet.com/contribute-to-puppet)
51
+ * [Contributor License Agreement](http://links.puppet.com/cla)
52
+ * [General GitHub documentation](http://help.github.com/)
53
+ * [GitHub pull request documentation](http://help.github.com/send-pull-requests/)
54
+ * Questions? Comments? Contact the in-parallel team at qa-team@puppet.com
55
+ * The keyword `in-parallel` is monitored and we'll get back to you as quick as we can.
data/Gemfile CHANGED
@@ -1,4 +1,15 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ # in the Rakefile, so we require it in all groups
4
+ gem 'rspec' ,'~> 3.1.0'
5
+
6
+ group :development do
7
+ gem 'simplecov'
8
+ gem 'rake', '>= 0.9.0'
9
+ #Documentation dependencies
10
+ gem 'yard' ,'~> 0'
11
+ gem 'markdown' ,'~> 0'
12
+ end
13
+
3
14
  # Specify your gem's dependencies in in_parallel.gemspec
4
15
  gemspec
@@ -0,0 +1,68 @@
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
@@ -0,0 +1,23 @@
1
+ # experimental_in-parallel_bump_and_tag_master - History
2
+ ## Tags
3
+ * [LATEST - 8 Aug, 2016 (d026c624)](#LATEST)
4
+ * [0.1.13 - 8 Aug, 2016 (26d19934)](#0.1.13)
5
+
6
+ ## Details
7
+ ### <a name = "LATEST">LATEST - 8 Aug, 2016 (d026c624)
8
+
9
+ * (GEM) update in-parallel version to 0.1.14 (d026c624)
10
+
11
+ * Merge pull request #14 from samwoods1/add_jjb_pipelines (269bc350)
12
+
13
+
14
+ ```
15
+ Merge pull request #14 from samwoods1/add_jjb_pipelines
16
+
17
+ (maint) Consistent naming of in-parallel
18
+ ```
19
+ * (maint) Consistent naming of in-parallel (6fbb442d)
20
+
21
+ ### <a name = "0.1.13">0.1.13 - 8 Aug, 2016 (26d19934)
22
+
23
+ * Initial release.
@@ -6,3 +6,4 @@ will be reviewing & merging PRs to the project.
6
6
  | Name | Github | Email |
7
7
  |:--------------:|:---------------------------------------------------:|:---------------------------:|
8
8
  | Sam Woods | [samwoods1](https://github.com/samwoods1) | <sam.woods@puppet.com> |
9
+ | Zach Reichert | [zreichert](https://github.com/zreichert) | <zach.reichert@puppet.com> |
data/README.md CHANGED
@@ -1,20 +1,33 @@
1
- # in-parallel
1
+
2
2
  A lightweight Ruby library with very simple syntax, making use of Process.fork to execute code in parallel.
3
3
 
4
- Other popular Ruby libraries that do parallel execution support one primary use case - crunching through a large queue of small tasks as quickly and efficiently as possible. This library primarily supports the use case of executing a few larger tasks in parallel and managing the stdout and return values to make it easy to understand which processes are logging what, and what the outcome of the execution was. This library was created to be used by Puppet's Beaker test framework to enable parallel execution of some of the framework's tasks, and allow users to execute code in parallel within their tests. This solution does not check to see how many processors you have, it just forks as many processes as you ask for. That means that it will handle a handful of parallel processes well, but could definitely overload your system with ruby processes if you try to spin up a LOT of processes. If you're looking for something intuitive and simple, but with a slight memory and processing overhead, and are on either Linux or Mac (forking processes is not supported on Windows), then this solution is what you want.
4
+ # Use Cases
5
+ Many other Ruby libraries that simplify parallel execution support one primary use case - crunching through a large queue of small, similar tasks as quickly and efficiently as possible. This library primarily supports the use case of executing a few larger and unrelated tasks in parallel, automatically managing the stdout and passing return values back to the main process. This library was created to be used by Puppet's Beaker test framework to enable parallel execution of some of the framework's tasks, and allow users to execute code in parallel within their tests.
5
6
 
6
7
  If you are looking for something that excels at executing a large queue of tasks in parallel as efficiently as possible, you should take a look at the [parallel](https://github.com/grosser/parallel) project.
7
8
 
8
- ## Methods:
9
+ # Install
10
+ ```gem install in-parallel```
11
+
12
+ # Usage
13
+ ```include InParallel``` to use as a mix-in
14
+
15
+ The methods below allow you to fork processes to execute multiple methods or blocks within an enumerable in parallel. They all have this common behavior:
9
16
 
17
+ 1. STDOUT is captured for each forked process and logged all at once when the process completes or is terminated.
18
+ 1. By default execution of processes in parallel will wait until execution of all processes are complete before continuing (with the exception of run_in_background).
19
+ 1. You can specify the parameter kill_all_on_error=true if you want to immediately exit all forked processes when an error executing any of the forked processes occurs.
20
+ 1. When the forked process raises an exception or exits with a non zero exit code, an exception will be raised in the main process.
21
+ 1. Terminating the main process with 'ctrl-c' or killing the process in some other way will immediately cause all forked processes to be killed and log their STDOUT up to that point.
22
+ 1. If the result of the method or block can be marshalled, it will be returned as though it was executed within the same process. If the result cannot be marshalled a warning is produced and the return value will be nil.
23
+ 1. NOTE: results of methods within run_in_parallel can be assigned to instance or class variables, but not local variables. See examples below.
24
+ 1. Will timeout (stop execution and raise an exception) based on a global timeout value, or timeout parameter.
25
+
26
+ ## Methods
10
27
  ### run_in_parallel(timeout=nil, kill_all_on_error = false, &block)
11
28
  1. Each method in a block will be executed in parallel (unless the method is defined in Kernel or BaseObject).
12
29
  1. Any methods further down the stack won't be affected, only the ones directly within the block.
13
- 2. You can assign return values to instance variables and it 'just works'.
14
- 3. Log STDOUT and STDERR chunked per process to the console so that it is easy to see what happened in which process.
15
- 4. Waits for each process in realtime and logs immediately upon completion of each process
16
- 5. If an exception is raised by a child process, it will optionally (kill_all_on_error) be re-raised in the primary process and kill all other still running child processes. The default will wait for all processes to complete execution before re-raising any unhandled exception from the child processes.
17
- 6. Times out by default at 30 minutes. Timeout default can be changed with InParallel::InParallelExecutor.parallel_default_timeout=X, or you can set the timeout param when calling the method
30
+ 1. Waits for each process in realtime and logs immediately upon completion of each process
18
31
 
19
32
  ```ruby
20
33
  def method_with_param(name)
@@ -40,8 +53,7 @@ If you are looking for something that excels at executing a large queue of tasks
40
53
 
41
54
  puts "#{@result_1}, #{@result_2[:foo]}"
42
55
  ```
43
-
44
- STDOUT would be:
56
+ stdout:
45
57
  ```
46
58
  Forked process for 'method_with_param' - PID = '49398'
47
59
  Forked process for 'method_without_param' - PID = '49399'
@@ -55,41 +67,19 @@ hello world
55
67
  ------ Completed output for method_without_param - 49399
56
68
  hello world, bar
57
69
  ```
58
-
59
70
  ### Enumerable.each_in_parallel(identifier=nil, timeout=(InParallel::InParallelExecutor.timeout), kill_all_on_error = false, &block)
60
71
  1. This is very similar to other solutions, except that it directly extends the Enumerable class with an each_in_parallel method, giving you the ability to pretty simply spawn a process for any item in an array or map.
61
- 2. Identifies the block location (or caller location if the block does not have a source_location) in the console log to make it clear which block is being executed
62
- 3. identifier param is only for logging, otherwise it will use the block source location.
63
- 4. If an exception is raised by a child process, it will optionally (kill_all_on_error) be re-raised in the primary process and kill all other still running child processes. The default will wait for all processes to complete execution before re-raising any unhandled exception from the child processes.
64
- 5. Times out by default at 30 minutes. Timeout default can be changed with InParallel::InParallelExecutor.parallel_default_timeout=X, or you can set the timeout param when calling the method
72
+ 1. Identifies the block location (or caller location if the block does not have a source_location) in the console log to make it clear which block is being executed
73
+ 1. Identifier param is only for logging, otherwise it will use the block source location.
65
74
 
66
75
  ```ruby
67
76
  ["foo", "bar", "baz"].each_in_parallel { |item| puts item }
68
-
69
- ```
70
- STDOUT:
71
- ```
72
- 'each_in_parallel' spawned process for '/Users/samwoods/parallel_test/test.rb:77:in `block (2 levels) in <top (required)>'' - PID = '51600'
73
- 'each_in_parallel' spawned process for '/Users/samwoods/parallel_test/test.rb:77:in `block (2 levels) in <top (required)>'' - PID = '51601'
74
- 'each_in_parallel' spawned process for '/Users/samwoods/parallel_test/test.rb:77:in `block (2 levels) in <top (required)>'' - PID = '51602'
75
-
76
- ------ Begin output for /Users/samwoods/parallel_test/test.rb:77:in `block (2 levels) in <top (required)>' - 51600
77
- foo
78
- ------ Completed output for /Users/samwoods/parallel_test/test.rb:77:in `block (2 levels) in <top (required)>' - 51600
79
-
80
- ------ Begin output for /Users/samwoods/parallel_test/test.rb:77:in `block (2 levels) in <top (required)>' - 51601
81
- bar
82
- ------ Completed output for /Users/samwoods/parallel_test/test.rb:77:in `block (2 levels) in <top (required)>' - 51601
83
-
84
- ------ Begin output for /Users/samwoods/parallel_test/test.rb:77:in `block (2 levels) in <top (required)>' - 51602
85
- baz
86
- ------ Completed output for /Users/samwoods/parallel_test/test.rb:77:in `block (2 levels) in <top (required)>' - 51602
87
77
  ```
88
78
 
89
79
  ### run_in_background(ignore_results = true, &block)
90
80
  1. This does basically the same thing as run_in_parallel, except it does not wait for execution of all processes to complete, it returns immediately.
91
- 2. You can optionally ignore results completely (default) or delay evaluating the results until later
92
- 3. You can run multiple blocks in the background and then at some later point evaluate all of the results
81
+ 1. You can optionally ignore results completely (default) or delay evaluating the results until later
82
+ 1. You can run multiple blocks in the background and then at some later point evaluate all of the results
93
83
 
94
84
  ```ruby
95
85
  TMP_FILE = '/tmp/test_file.txt'
@@ -108,7 +98,8 @@ baz
108
98
  sleep(3)
109
99
  # Should exist once the delay from create_file_with_delay is done
110
100
  puts(File.exists?(TMP_FILE)) # true
111
-
101
+ ```
102
+ ```ruby
112
103
  # Example 2 - delay results
113
104
  run_in_background(false) { @result = create_file_with_delay(TMP_FILE) }
114
105
 
@@ -128,5 +119,21 @@ baz
128
119
 
129
120
  ### wait_for_processes(timeout=nil, kill_all_on_error = false)
130
121
  1. Used only after run_in_background with ignore_results=false
131
- 2. Optional args for timeout and kill_all_on_error
132
- 3. See run_in_background for examples
122
+ 1. Optional args for timeout and kill_all_on_error
123
+ 1. See run_in_background for examples
124
+
125
+ ## Global Options
126
+ You can get or set the following values to set global defaults. These defaults can also be specified per execution by supplying the values as parameters to the parallel methods.
127
+ ```
128
+ # How many seconds to wait between logging a 'Waiting for child processes.' message. Defaults to 30 seconds
129
+ parallel_signal_interval
130
+
131
+ # How many seconds to wait before timing out a forked child process and raising an exception. Defaults to 30 minutes.
132
+ parallel_default_timeout
133
+
134
+ # The log level to log output.
135
+ # NOTE: The entire contents of STDOUT for forked processes will be printed to console regardless of
136
+ # the log level set here.
137
+ @logger.log_level
138
+ ```
139
+
data/Rakefile CHANGED
@@ -1,2 +1,10 @@
1
1
  require "bundler/gem_tasks"
2
- task :default => :spec
2
+ require 'rspec/core/rake_task'
3
+
4
+ task :default => :test
5
+
6
+ desc "Run spec tests"
7
+ RSpec::Core::RakeTask.new(:test) do |t|
8
+ t.rspec_opts = ['--color']
9
+ t.pattern = 'spec/'
10
+ end
@@ -0,0 +1,3 @@
1
+ module InParallel
2
+ VERSION = '0.1.15'
3
+ end
@@ -313,7 +313,7 @@ module InParallel
313
313
  # All methods within the block should show up as missing (unless defined in :Kernel)
314
314
  def method_missing(method_sym, *args, &block)
315
315
  if InParallelExecutor.main_pid == ::Process.pid
316
- out = InParallelExecutor._execute_in_parallel("'#{method_sym.to_s}' #{caller_locations[0].to_s}",
316
+ out = InParallelExecutor._execute_in_parallel("'#{method_sym.to_s}' #{caller[0].to_s}",
317
317
  @object.eval('self')) { send(method_sym, *args, &block) }
318
318
  out[:tmp_result]
319
319
  end
@@ -10,7 +10,7 @@ module Enumerable
10
10
  # @return [Array<Object>] results - the return value of each block execution.
11
11
  def each_in_parallel(identifier=nil, timeout=(InParallel::InParallelExecutor.parallel_default_timeout), kill_all_on_error = false, &block)
12
12
  if InParallel::InParallelExecutor.fork_supported? && count > 1
13
- identifier ||= "#{caller_locations[0]}"
13
+ identifier ||= "#{caller[0]}"
14
14
  each do |item|
15
15
  InParallel::InParallelExecutor._execute_in_parallel(identifier) { block.call(item) }
16
16
  end
@@ -0,0 +1,251 @@
1
+ require 'rspec'
2
+ require_relative('../lib/in_parallel')
3
+ include InParallel
4
+ TMP_FILE = Dir.mktmpdir + 'test_file.txt'
5
+
6
+ class SingletonTest
7
+ def initialize
8
+ @test_data = [1, 2, 3]
9
+ end
10
+
11
+ def get_test_data
12
+ @test_data
13
+ end
14
+ end
15
+
16
+ class SingletonWrapper
17
+ def initialize
18
+ @instance_var = get_singleton_class
19
+ singleton_class.class_eval do
20
+ @@x = "foo"
21
+ @x = 'bar'
22
+ end
23
+ end
24
+
25
+ def get_instance_var
26
+ @instance_var
27
+ end
28
+ end
29
+
30
+ def get_wrapper
31
+ SingletonWrapper.new
32
+ end
33
+
34
+ def get_singleton_class
35
+ test = SingletonTest.new
36
+
37
+ def test.someval
38
+ "someval"
39
+ end
40
+
41
+ return test
42
+ end
43
+
44
+ # Helper functions for the unit tests
45
+ def method_with_param(param)
46
+ puts "foo"
47
+ puts "bar + #{param} \n"
48
+ return "bar + #{param}"
49
+ end
50
+
51
+ def method_without_param
52
+ ret_val = { :foo => "bar" }
53
+ puts ret_val
54
+ return ret_val
55
+ end
56
+
57
+ def simple_puts(my_string)
58
+ puts my_string
59
+ end
60
+
61
+ def create_file_with_delay(file_path, wait=2)
62
+ sleep wait
63
+ File.open(file_path, 'w') { |f| f.write('contents') }
64
+ return true
65
+ end
66
+
67
+ def get_pid
68
+ return Process.pid
69
+ end
70
+
71
+ def raise_an_error
72
+ raise StandardError.new('An error occurred')
73
+ end
74
+
75
+ #Tests
76
+ describe '.run_in_parallel' do
77
+ before do
78
+ File.delete(TMP_FILE) if File.exists?(TMP_FILE)
79
+ end
80
+
81
+ it 'should run methods in another process' do
82
+ run_in_parallel do
83
+ @result = get_pid
84
+ @result2 = get_pid
85
+ end
86
+
87
+ expect(@result).to_not eq(Process.pid)
88
+ expect(@result2).to_not eq(Process.pid)
89
+ expect(@result).to_not eq(@result2)
90
+ end
91
+ it 'should return correct values' do
92
+ start_time = Time.now
93
+
94
+ run_in_parallel do
95
+ @result_from_test = method_with_param('blah')
96
+ @result_2 = method_without_param
97
+ end
98
+ # return values for instance variables should be set correctly
99
+ expect(@result_from_test).to eq 'bar + blah'
100
+ # should be able to return objects (not just strings)
101
+ expect(@result_2).to eq({ :foo => "bar" })
102
+ end
103
+
104
+ it "should return a singleton class value" do
105
+
106
+ run_in_parallel { @result = get_singleton_class }
107
+
108
+ expect(@result.get_test_data).to eq([1, 2, 3])
109
+ end
110
+
111
+ it "should return an object with an instance variable set to an object containing singleton methods" do
112
+ run_in_parallel { @result = get_wrapper }
113
+ expect(@result.get_instance_var.get_test_data).to eq([1, 2, 3])
114
+ end
115
+
116
+ it "should raise an exception and return immediately with kill_all_on_error and one of the processes errors." do
117
+ expect { run_in_parallel(nil, true) do
118
+ @result = get_singleton_class
119
+ @result_2 = raise_an_error
120
+ @result_3 = create_file_with_delay(TMP_FILE)
121
+ end }.to raise_error StandardError
122
+
123
+ expect(@result_3).to_not eq(true)
124
+ end
125
+
126
+ it "should raise an exception and let all processes complete when one of the processes errors." do
127
+ expect { run_in_parallel(nil, false) do
128
+ @result = get_singleton_class
129
+ @result_2 = raise_an_error
130
+ @result_3 = create_file_with_delay(TMP_FILE)
131
+ end }.to raise_error StandardError
132
+
133
+ expect(@result_3).to eq(true)
134
+ end
135
+
136
+ it "should not run in parallel if forking is not supported" do
137
+ InParallel::InParallelExecutor.class_variable_set(:@@supported, nil)
138
+ expect(Process).to receive(:respond_to?).with(:fork).and_return(false).once
139
+ expect(InParallel::InParallelExecutor.logger).to receive(:warn).with("Warning: Fork is not supported on this OS, executing block normally")
140
+
141
+ run_in_parallel do
142
+ @result_from_test = method_with_param('blah')
143
+ @result_2 = get_pid
144
+ end
145
+
146
+ expect(@result_from_test).to eq 'bar + blah'
147
+ expect(@result_2).to eq Process.pid
148
+ end
149
+
150
+ # it "should chunk stdout per process" do
151
+ # expect {run_in_parallel {
152
+ # simple_puts('foobar')
153
+ # }}.to output(/------ Begin output for simple_puts.*foobar.*------ Completed output for simple_puts/).to_stdout
154
+ # end
155
+ end
156
+
157
+ describe '.run_in_background' do
158
+ before do
159
+ File.delete(TMP_FILE) if File.exists?(TMP_FILE)
160
+ end
161
+
162
+ it 'should run in the background' do
163
+ run_in_background { @result = create_file_with_delay(TMP_FILE) }
164
+
165
+ start = Time.now
166
+ # Should not exist immediately upon block completion
167
+ expect(File.exists? TMP_FILE).to eq false
168
+ # Give this some time to complete since it takes longer on the vmpooler vms
169
+ file_exists = false
170
+ while Time.now < start + 10 do
171
+ if File.exists? TMP_FILE
172
+ file_exists = true
173
+ break
174
+ end
175
+ end
176
+ # Should exist once the delay in create_file_with_delay is done
177
+ expect(file_exists).to eq true
178
+ end
179
+
180
+ it 'should allow you to get results if ignore_results is false' do
181
+ @block_result = run_in_background(false) { @result = create_file_with_delay(TMP_FILE) }
182
+ wait_for_processes
183
+ # We should get the correct value assigned for the method result
184
+ expect(@result).to eq true
185
+ end
186
+
187
+ end
188
+
189
+ describe '.wait_for_processes' do
190
+ after do
191
+ InParallel::InParallelExecutor.parallel_default_timeout = 1200
192
+ end
193
+ it 'should timeout when the default timeout value is hit' do
194
+ @block_result = run_in_background(false) do
195
+ @result = create_file_with_delay(TMP_FILE, 30)
196
+ end
197
+ InParallel::InParallelExecutor.parallel_default_timeout = 0.1
198
+ expect { wait_for_processes }.to raise_error RuntimeError
199
+ end
200
+
201
+ it 'should timeout when a specified timeout value is hit' do
202
+ @block_result = run_in_background(false) do
203
+ @result = create_file_with_delay(TMP_FILE, 30)
204
+ @result2 = method_without_param
205
+ end
206
+ expect { wait_for_processes(0.1) }.to raise_error RuntimeError
207
+ end
208
+ end
209
+
210
+ describe '.each_in_parallel' do
211
+ it 'should run each iteration in a separate process' do
212
+ pids = [1, 2, 3].each_in_parallel { Process.pid }
213
+ expect(pids.detect { |pid| pids.count(pid) > 1 }).to be_nil
214
+ end
215
+
216
+ it 'should return correct values' do
217
+ start_time = Time.now
218
+ items = ['foo', 'bar', 'baz', 'blah', 'foobar'].each_in_parallel do |item|
219
+ sleep(Random.rand(1.0))
220
+ item
221
+ end
222
+ # return values should be an array of the returned items in the last line of the block, in correct order
223
+ expect(['foo', 'bar', 'baz', 'blah', 'foobar']).to eq(items)
224
+ # time should be less than combined delay in the 3 block calls
225
+ expect(expect(Time.now - start_time).to be < 5)
226
+ end
227
+
228
+ it 'should run each iteration of a map in parallel' do
229
+ items = ['foo', 'bar', 'baz'].map.each_in_parallel do |item|
230
+ puts item
231
+ item
232
+ end
233
+ # return values should be an array of the returned items in the last line of the block, in correct order
234
+ expect(items).to eq(['foo', 'bar', 'baz'])
235
+ end
236
+
237
+ it 'should not run in parallel if there is only 1 item in the enumerator' do
238
+ expect(InParallel::InParallelExecutor.logger).to_not receive(:info).with(/Forked process for/)
239
+ expect(["foo"].map.each_in_parallel { Process.pid }[0]).to eq(Process.pid)
240
+ end
241
+
242
+ it 'should allow you to specify the method_sym' do
243
+ allow(InParallel::InParallelExecutor.logger).to receive(:info).with(anything())
244
+ expect(InParallel::InParallelExecutor.logger).to receive(:info).with(/Forked process for my_method/).exactly(3).times
245
+
246
+ [1, 2, 3].each_in_parallel('my_method') { |item|
247
+ puts item
248
+ }
249
+ end
250
+
251
+ end
metadata CHANGED
@@ -1,72 +1,42 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: in-parallel
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.12
4
+ version: 0.1.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - samwoods1
8
8
  autorequire:
9
- bindir: exe
9
+ bindir: bin
10
10
  cert_chain: []
11
- date: 2016-07-14 00:00:00.000000000 Z
12
- dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: bundler
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - "~>"
18
- - !ruby/object:Gem::Version
19
- version: '1.11'
20
- type: :development
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - "~>"
25
- - !ruby/object:Gem::Version
26
- version: '1.11'
27
- - !ruby/object:Gem::Dependency
28
- name: rake
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '10.0'
34
- type: :development
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '10.0'
41
- description: The other Ruby librarys that do parallel execution all support one primary
42
- use case - crunching through a large queue of small tasks as quickly and efficiently
43
- as possible. This library primarily supports the use case of needing to run a few
44
- larger tasks in parallel and managing the stdout to make it easy to understand which
45
- processes are logging what. This library was created to be used by the Beaker test
46
- framework to enable parallel execution of some of the framework's tasks, and allow
47
- people within thier tests to execute code in parallel when wanted. This solution
48
- does not check to see how many processors you have, it just forks as many processes
49
- as you ask for. That means that it will handle a handful of parallel processes well,
50
- but could definitely overload your system with ruby processes if you try to spin
51
- up a LOT of processes. If you're looking for something simple and light-weight and
52
- on either linux or mac (forking processes is not supported on Windows), then this
53
- solution could be what you want.
11
+ date: 2016-08-08 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: Many other Ruby libraries that simplify parallel execution support one
14
+ primary use case - crunching through a large queue of small, similar tasks as quickly
15
+ and efficiently as possible. This library primarily supports the use case of executing
16
+ a few larger and unrelated tasks in parallel, automatically managing the stdout
17
+ and passing return values back to the main process. This library was created to
18
+ be used by Puppet's Beaker test framework to enable parallel execution of some of
19
+ the framework's tasks, and allow users to execute code in parallel within their
20
+ tests.
54
21
  email:
55
22
  - sam.woods@puppetlabs.com
56
23
  executables: []
57
24
  extensions: []
58
25
  extra_rdoc_files: []
59
26
  files:
27
+ - CONTRIBUTING.md
60
28
  - Gemfile
29
+ - Gemfile.lock
30
+ - HISTORY.md
61
31
  - LICENSE
62
32
  - MAINTAINERS.md
63
33
  - README.md
64
34
  - Rakefile
65
- - in_parallel.gemspec
66
- - in_parallel/version.rb
35
+ - lib/in-parallel/version.rb
67
36
  - lib/in_parallel.rb
68
37
  - lib/parallel_enumerable.rb
69
38
  - lib/parallel_logger.rb
39
+ - spec/in-paralell_spec.rb
70
40
  homepage: https://github.com/puppetlabs/in-parallel
71
41
  licenses:
72
42
  - MIT
@@ -1,34 +0,0 @@
1
- # coding: utf-8
2
- lib = File.expand_path('../lib', __FILE__)
3
- $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
- require_relative 'in_parallel/version'
5
-
6
- Gem::Specification.new do |spec|
7
- spec.name = "in-parallel"
8
- spec.version = InParallel::VERSION
9
- spec.authors = ["samwoods1"]
10
- spec.email = ["sam.woods@puppetlabs.com"]
11
-
12
- spec.summary = "A lightweight library to execute a handful of tasks in parallel with simple syntax"
13
- spec.description = "The other Ruby librarys that do parallel execution all support one primary use case " +
14
- "- crunching through a large queue of small tasks as quickly and efficiently as possible. This library " +
15
- "primarily supports the use case of needing to run a few larger tasks in parallel and managing the " +
16
- "stdout to make it easy to understand which processes are logging what. This library was created to be " +
17
- "used by the Beaker test framework to enable parallel execution of some of the framework's tasks, and " +
18
- "allow people within thier tests to execute code in parallel when wanted. This solution does not check " +
19
- "to see how many processors you have, it just forks as many processes as you ask for. That means that it " +
20
- "will handle a handful of parallel processes well, but could definitely overload your system with ruby " +
21
- "processes if you try to spin up a LOT of processes. If you're looking for something simple and " +
22
- "light-weight and on either linux or mac (forking processes is not supported on Windows), then this " +
23
- "solution could be what you want."
24
- spec.homepage = "https://github.com/puppetlabs/in-parallel"
25
- spec.license = "MIT"
26
-
27
- spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
28
- spec.bindir = "exe"
29
- spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
30
- spec.require_paths = ["lib"]
31
-
32
- spec.add_development_dependency "bundler", "~> 1.11"
33
- spec.add_development_dependency "rake", "~> 10.0"
34
- end
@@ -1,3 +0,0 @@
1
- module InParallel
2
- VERSION = Version = '0.1.12'
3
- end