process-group 1.2.1 → 1.2.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/process/group/version.rb +1 -1
- data/lib/process/group.rb +9 -5
- data.tar.gz.sig +0 -0
- metadata +46 -58
- metadata.gz.sig +0 -0
- data/.gitignore +0 -12
- data/.rspec +0 -4
- data/.travis.yml +0 -14
- data/Gemfile +0 -8
- data/README.md +0 -219
- data/Rakefile +0 -6
- data/examples/terminal.rb +0 -43
- data/process-group.gemspec +0 -29
- data/spec/process/group/foreground_spec.rb +0 -34
- data/spec/process/group/fork_spec.rb +0 -60
- data/spec/process/group/interrupt_spec.rb +0 -146
- data/spec/process/group/io_spec.rb +0 -52
- data/spec/process/group/load_spec.rb +0 -42
- data/spec/process/group/process_spec.rb +0 -55
- data/spec/process/group/spawn_spec.rb +0 -99
- data/spec/process/group/wait_spec.rb +0 -85
- data/spec/spec_helper.rb +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 91f32e8039a65dede8fceb0bd2c5554142555ca7825f12d93d1329eb094789f0
|
4
|
+
data.tar.gz: 40d8f02f6f3ebd88cd5a4d5cbe8fb88e0e4fe54aefd5b3813c0b049f40415561
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9e9947d56c5bd3999f2f16ff3bf2df9b6d63cce82a2070adcaab0943637d3836ac3a4a1488ac388af72bac5c189fe9a78f26f259f7250b8a0bc6f36c48d3f0bf
|
7
|
+
data.tar.gz: c8dfd88cfba5f4a06fe00e41d725bd7eb91536e70ac34e40042225040d449cfdb2386a9f4eecdfedb30396b49301f8cadd5a2e536a4d0e4514e054e2cdd02c3f
|
checksums.yaml.gz.sig
ADDED
Binary file
|
data/lib/process/group.rb
CHANGED
@@ -25,7 +25,7 @@ module Process
|
|
25
25
|
# A group of tasks which can be run asynchrnously using fibers. Someone must call Group#wait to ensure that all fibers eventually resume.
|
26
26
|
class Group
|
27
27
|
def self.wait(**options, &block)
|
28
|
-
group = Group.new(options)
|
28
|
+
group = Group.new(**options)
|
29
29
|
|
30
30
|
group.wait(&block)
|
31
31
|
end
|
@@ -50,6 +50,10 @@ module Process
|
|
50
50
|
def resume(*arguments)
|
51
51
|
@fiber.resume(*arguments)
|
52
52
|
end
|
53
|
+
|
54
|
+
def kill(signal = :INT)
|
55
|
+
Process.kill(signal, @pid)
|
56
|
+
end
|
53
57
|
end
|
54
58
|
|
55
59
|
# Executes a command using Process.spawn with the given arguments and options.
|
@@ -123,7 +127,7 @@ module Process
|
|
123
127
|
|
124
128
|
# The maximum number of processes to run concurrently, or zero
|
125
129
|
attr_accessor :limit
|
126
|
-
|
130
|
+
|
127
131
|
# The id of the process group, only valid if processes are currently running.
|
128
132
|
def id
|
129
133
|
raise RuntimeError.new("No processes in group, no group id available.") if @running.size == 0
|
@@ -293,11 +297,11 @@ module Process
|
|
293
297
|
|
294
298
|
# Wait for processes in this group:
|
295
299
|
pid, status = Process.wait2(-@pgid, flags)
|
296
|
-
|
300
|
+
|
297
301
|
return if flags & Process::WNOHANG and pid == nil
|
298
|
-
|
302
|
+
|
299
303
|
process = @running.delete(pid)
|
300
|
-
|
304
|
+
|
301
305
|
# This should never happen unless something very odd has happened:
|
302
306
|
raise RuntimeError.new("Process id=#{pid} is not part of group!") unless process
|
303
307
|
|
data.tar.gz.sig
ADDED
Binary file
|
metadata
CHANGED
@@ -1,14 +1,44 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: process-group
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.2.
|
4
|
+
version: 1.2.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
8
|
-
|
8
|
+
- Dustin Zeisler
|
9
|
+
- Olle Jonsson
|
10
|
+
autorequire:
|
9
11
|
bindir: bin
|
10
|
-
cert_chain:
|
11
|
-
|
12
|
+
cert_chain:
|
13
|
+
- |
|
14
|
+
-----BEGIN CERTIFICATE-----
|
15
|
+
MIIEhDCCAuygAwIBAgIBATANBgkqhkiG9w0BAQsFADA3MTUwMwYDVQQDDCxzYW11
|
16
|
+
ZWwud2lsbGlhbXMvREM9b3Jpb250cmFuc2Zlci9EQz1jby9EQz1uejAeFw0yMTA4
|
17
|
+
MTYwNjMzNDRaFw0yMjA4MTYwNjMzNDRaMDcxNTAzBgNVBAMMLHNhbXVlbC53aWxs
|
18
|
+
aWFtcy9EQz1vcmlvbnRyYW5zZmVyL0RDPWNvL0RDPW56MIIBojANBgkqhkiG9w0B
|
19
|
+
AQEFAAOCAY8AMIIBigKCAYEAyXLSS/cw+fXJ5e7hi+U/TeChPWeYdwJojDsFY1xr
|
20
|
+
xvtqbTTL8gbLHz5LW3QD2nfwCv3qTlw0qI3Ie7a9VMJMbSvgVEGEfQirqIgJXWMj
|
21
|
+
eNMDgKsMJtC7u/43abRKx7TCURW3iWyR19NRngsJJmaR51yGGGm2Kfsr+JtKKLtL
|
22
|
+
L188Wm3f13KAx7QJU8qyuBnj1/gWem076hzdA7xi1DbrZrch9GCRz62xymJlrJHn
|
23
|
+
9iZEZ7AxrS7vokhMlzSr/XMUihx/8aFKtk+tMLClqxZSmBWIErWdicCGTULXCBNb
|
24
|
+
E/mljo4zEVKhlTWpJklMIhr55ZRrSarKFuW7en0+tpJrfsYiAmXMJNi4XAYJH7uL
|
25
|
+
rgJuJwSaa/dMz+VmUoo7VKtSfCoOI+6v5/z0sK3oT6sG6ZwyI47DBq2XqNC6tnAj
|
26
|
+
w+XmCywiTQrFzMMAvcA7rPI4F0nU1rZId51rOvvfxaONp+wgTi4P8owZLw0/j0m4
|
27
|
+
8C20DYi6EYx4AHDXiLpElWh3AgMBAAGjgZowgZcwCQYDVR0TBAIwADALBgNVHQ8E
|
28
|
+
BAMCBLAwHQYDVR0OBBYEFB6ZaeWKxQjGTI+pmz7cKRmMIywwMC4GA1UdEQQnMCWB
|
29
|
+
I3NhbXVlbC53aWxsaWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MC4GA1UdEgQnMCWB
|
30
|
+
I3NhbXVlbC53aWxsaWFtc0BvcmlvbnRyYW5zZmVyLmNvLm56MA0GCSqGSIb3DQEB
|
31
|
+
CwUAA4IBgQBVoM+pu3dpdUhZM1w051iw5GfiqclAr1Psypf16Tiod/ho//4oAu6T
|
32
|
+
9fj3DPX/acWV9P/FScvqo4Qgv6g4VWO5ZU7z2JmPoTXZtYMunRAmQPFL/gSUc6aK
|
33
|
+
vszMHIyhtyzRc6DnfW2AiVOjMBjaYv8xXZc9bduniRVPrLR4J7ozmGLh4o4uJp7w
|
34
|
+
x9KCFaR8Lvn/r0oJWJOqb/DMAYI83YeN2Dlt3jpwrsmsONrtC5S3gOUle5afSGos
|
35
|
+
bYt5ocnEpKSomR9ZtnCGljds/aeO1Xgpn2r9HHcjwnH346iNrnHmMlC7BtHUFPDg
|
36
|
+
Ts92S47PTOXzwPBDsrFiq3VLbRjHSwf8rpqybQBH9MfzxGGxTaETQYOd6b4e4Ag6
|
37
|
+
y92abGna0bmIEb4+Tx9rQ10Uijh1POzvr/VTH4bbIPy9FbKrRsIQ24qDbNJRtOpE
|
38
|
+
RAOsIl+HOBTb252nx1kIRN5hqQx272AJCbCjKx8egcUQKffFVVCI0nye09v5CK+a
|
39
|
+
HiLJ8VOFx6w=
|
40
|
+
-----END CERTIFICATE-----
|
41
|
+
date: 2022-05-23 00:00:00.000000000 Z
|
12
42
|
dependencies:
|
13
43
|
- !ruby/object:Gem::Dependency
|
14
44
|
name: process-terminal
|
@@ -25,7 +55,7 @@ dependencies:
|
|
25
55
|
- !ruby/object:Gem::Version
|
26
56
|
version: 0.2.0
|
27
57
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
58
|
+
name: bundler
|
29
59
|
requirement: !ruby/object:Gem::Requirement
|
30
60
|
requirements:
|
31
61
|
- - ">="
|
@@ -39,7 +69,7 @@ dependencies:
|
|
39
69
|
- !ruby/object:Gem::Version
|
40
70
|
version: '0'
|
41
71
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
72
|
+
name: covered
|
43
73
|
requirement: !ruby/object:Gem::Requirement
|
44
74
|
requirements:
|
45
75
|
- - ">="
|
@@ -58,61 +88,28 @@ dependencies:
|
|
58
88
|
requirements:
|
59
89
|
- - "~>"
|
60
90
|
- !ruby/object:Gem::Version
|
61
|
-
version: 3.
|
91
|
+
version: 3.9.0
|
62
92
|
type: :development
|
63
93
|
prerelease: false
|
64
94
|
version_requirements: !ruby/object:Gem::Requirement
|
65
95
|
requirements:
|
66
96
|
- - "~>"
|
67
97
|
- !ruby/object:Gem::Version
|
68
|
-
version: 3.
|
69
|
-
|
70
|
-
name: rake
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
description: "\tManages a unix process group for running multiple processes, keeps
|
84
|
-
track of multiple processes and leverages fibers to provide predictable behaviour
|
85
|
-
in complicated process-based scripts.\n"
|
98
|
+
version: 3.9.0
|
99
|
+
description:
|
86
100
|
email:
|
87
|
-
- samuel.williams@oriontransfer.co.nz
|
88
101
|
executables: []
|
89
102
|
extensions: []
|
90
103
|
extra_rdoc_files: []
|
91
104
|
files:
|
92
|
-
- ".gitignore"
|
93
|
-
- ".rspec"
|
94
|
-
- ".travis.yml"
|
95
|
-
- Gemfile
|
96
|
-
- README.md
|
97
|
-
- Rakefile
|
98
|
-
- examples/terminal.rb
|
99
105
|
- lib/process/group.rb
|
100
106
|
- lib/process/group/version.rb
|
101
|
-
- process-group.gemspec
|
102
|
-
- spec/process/group/foreground_spec.rb
|
103
|
-
- spec/process/group/fork_spec.rb
|
104
|
-
- spec/process/group/interrupt_spec.rb
|
105
|
-
- spec/process/group/io_spec.rb
|
106
|
-
- spec/process/group/load_spec.rb
|
107
|
-
- spec/process/group/process_spec.rb
|
108
|
-
- spec/process/group/spawn_spec.rb
|
109
|
-
- spec/process/group/wait_spec.rb
|
110
|
-
- spec/spec_helper.rb
|
111
107
|
homepage: https://github.com/ioquatix/process-group
|
112
108
|
licenses:
|
113
109
|
- MIT
|
114
|
-
metadata:
|
115
|
-
|
110
|
+
metadata:
|
111
|
+
funding_uri: https://github.com/sponsors/ioquatix/
|
112
|
+
post_install_message:
|
116
113
|
rdoc_options: []
|
117
114
|
require_paths:
|
118
115
|
- lib
|
@@ -127,17 +124,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
127
124
|
- !ruby/object:Gem::Version
|
128
125
|
version: '0'
|
129
126
|
requirements: []
|
130
|
-
rubygems_version: 3.
|
131
|
-
signing_key:
|
127
|
+
rubygems_version: 3.1.6
|
128
|
+
signing_key:
|
132
129
|
specification_version: 4
|
133
|
-
summary: Run processes
|
134
|
-
test_files:
|
135
|
-
- spec/process/group/foreground_spec.rb
|
136
|
-
- spec/process/group/fork_spec.rb
|
137
|
-
- spec/process/group/interrupt_spec.rb
|
138
|
-
- spec/process/group/io_spec.rb
|
139
|
-
- spec/process/group/load_spec.rb
|
140
|
-
- spec/process/group/process_spec.rb
|
141
|
-
- spec/process/group/spawn_spec.rb
|
142
|
-
- spec/process/group/wait_spec.rb
|
143
|
-
- spec/spec_helper.rb
|
130
|
+
summary: Run and manage multiple processes in separate fibers with predictable behaviour.
|
131
|
+
test_files: []
|
metadata.gz.sig
ADDED
Binary file
|
data/.gitignore
DELETED
data/.rspec
DELETED
data/.travis.yml
DELETED
data/Gemfile
DELETED
data/README.md
DELETED
@@ -1,219 +0,0 @@
|
|
1
|
-
# Process::Group
|
2
|
-
|
3
|
-
`Process::Group` allows for multiple fibers to run system processes concurrently with minimal overhead.
|
4
|
-
|
5
|
-
```ruby
|
6
|
-
Process::Group.wait do |group|
|
7
|
-
group.run("ls", "-lah") {|status| puts status.inspect}
|
8
|
-
group.run("echo", "Hello World") {|status| puts status.inspect}
|
9
|
-
end
|
10
|
-
```
|
11
|
-
|
12
|
-
[![Build Status](https://secure.travis-ci.com/socketry/process-group.svg)](http://travis-ci.com/socketry/process-group)
|
13
|
-
[![Coverage Status](https://coveralls.io/repos/socketry/process-group/badge.svg)](https://coveralls.io/r/socketry/process-group)
|
14
|
-
[![Documentation](http://img.shields.io/badge/yard-docs-blue.svg)](http://www.rubydoc.info/gems/process-group)
|
15
|
-
[![Code](http://img.shields.io/badge/github-code-blue.svg)](https://github.com/socketry/process-group)
|
16
|
-
|
17
|
-
## Installation
|
18
|
-
|
19
|
-
Add this line to your application's Gemfile:
|
20
|
-
|
21
|
-
gem 'process-group'
|
22
|
-
|
23
|
-
And then execute:
|
24
|
-
|
25
|
-
$ bundle
|
26
|
-
|
27
|
-
Or install it yourself as:
|
28
|
-
|
29
|
-
$ gem install process-group
|
30
|
-
|
31
|
-
## Usage
|
32
|
-
|
33
|
-
The simplest concurrent usage is as follows:
|
34
|
-
|
35
|
-
# Create a new process group:
|
36
|
-
Process::Group.wait do |group|
|
37
|
-
# Run the command (non-blocking):
|
38
|
-
group.run("sleep 1") do |exit_status|
|
39
|
-
# Running in a separate fiber, will execute this code once the process completes:
|
40
|
-
puts "Command finished with status: #{exit_status}"
|
41
|
-
end
|
42
|
-
|
43
|
-
# Do something else here:
|
44
|
-
sleep(1)
|
45
|
-
|
46
|
-
# Wait for all processes in group to finish.
|
47
|
-
end
|
48
|
-
|
49
|
-
The `group.wait` call is an explicit synchronization point, and if it completes successfully, all processes/fibers have finished successfully. If an error is raised in a fiber, it will be passed back out through `group.wait` and this is the only failure condition. Even if this occurs, all children processes are guaranteed to be cleaned up.
|
50
|
-
|
51
|
-
### Explicit Fibers
|
52
|
-
|
53
|
-
Items within a single fiber will execute sequentially. Processes (e.g. via `Group#spawn`) will run concurrently in multiple fibers.
|
54
|
-
|
55
|
-
```ruby
|
56
|
-
Process::Group.wait do |group|
|
57
|
-
# Explicity manage concurrency in this fiber:
|
58
|
-
Fiber.new do
|
59
|
-
# These processes will be run sequentially:
|
60
|
-
group.spawn("sleep 1")
|
61
|
-
group.spawn("sleep 1")
|
62
|
-
end.resume
|
63
|
-
|
64
|
-
# Implicitly run this task concurrently as the above fiber:
|
65
|
-
group.run("sleep 2")
|
66
|
-
end
|
67
|
-
```
|
68
|
-
|
69
|
-
`Group#spawn` is theoretically identical to `Process#spawn` except the processes are run concurrently if possible.
|
70
|
-
|
71
|
-
### Explicit Wait
|
72
|
-
|
73
|
-
The recommended approach to use process group is to call `Process::Group.wait` with a block which invokes tasks. This block is wrapped in appropriate `rescue Interrupt` and `ensure` blocks which guarantee that the process group is cleaned up:
|
74
|
-
|
75
|
-
```ruby
|
76
|
-
Process::Group.wait do |group|
|
77
|
-
group.run("sleep 10")
|
78
|
-
end
|
79
|
-
```
|
80
|
-
|
81
|
-
It is also possible to invoke this machinery and reuse the process group simply by instantiating the group and calling wait explicitly:
|
82
|
-
|
83
|
-
```ruby
|
84
|
-
group = Process::Group.new
|
85
|
-
|
86
|
-
group.wait do
|
87
|
-
group.run("sleep 10")
|
88
|
-
end
|
89
|
-
```
|
90
|
-
|
91
|
-
It is also possible to queue tasks for execution outside the wait block. But by design, it's only possible to execute tasks within the wait block. Tasks added outside a wait block will be queued up for execution when `#wait` is invoked:
|
92
|
-
|
93
|
-
```ruby
|
94
|
-
group = Process::Group.new
|
95
|
-
|
96
|
-
group.run("sleep 10")
|
97
|
-
|
98
|
-
# Run command here:
|
99
|
-
group.wait
|
100
|
-
```
|
101
|
-
|
102
|
-
### Specify Options
|
103
|
-
|
104
|
-
You can specify options to `Group#run` and `Group#spawn` just like `Process::spawn`:
|
105
|
-
|
106
|
-
```ruby
|
107
|
-
Process::Group.wait do |group|
|
108
|
-
env = {'FOO' => 'BAR'}
|
109
|
-
|
110
|
-
# Arguments are essentially the same as Process::spawn.
|
111
|
-
group.run(env, "sleep 1", chdir: "/tmp")
|
112
|
-
end
|
113
|
-
```
|
114
|
-
|
115
|
-
### Process Limit
|
116
|
-
|
117
|
-
The process group can be used as a way to spawn multiple processes, but sometimes you'd like to limit the number of parallel processes to something relating to the number of processors in the system. By default, there is no limit on the number of processes running concurrently.
|
118
|
-
|
119
|
-
```ruby
|
120
|
-
# limit based on the number of processors:
|
121
|
-
require 'etc'
|
122
|
-
group = Process::Group.new(limit: Etc.nprocessors)
|
123
|
-
|
124
|
-
# hardcoded - set to n (8 < n < 32) and let the OS scheduler worry about it:
|
125
|
-
group = Process::Group.new(limit: 32)
|
126
|
-
|
127
|
-
# unlimited - default:
|
128
|
-
group = Process::Group.new
|
129
|
-
```
|
130
|
-
|
131
|
-
### Kill Group
|
132
|
-
|
133
|
-
It is possible to send a signal (kill) to the entire process group:
|
134
|
-
|
135
|
-
```ruby
|
136
|
-
group.kill(:TERM)
|
137
|
-
```
|
138
|
-
|
139
|
-
If there are no running processes, this is a no-op (rather than an error). [Proper handling of SIGINT/SIGQUIT](http://www.cons.org/cracauer/sigint.html) explains how to use signals correctly.
|
140
|
-
|
141
|
-
#### Handling Interrupts
|
142
|
-
|
143
|
-
`Process::Group` transparently handles `Interrupt` when raised within a `Fiber`. If `Interrupt` is raised, all children processes will be sent `kill(:INT)` and we will wait for all children to complete, but without resuming the controlling fibers. If `Interrupt` is raised during this process, children will be sent `kill(:TERM)`. After calling `Interrupt`, the fibers will not be resumed.
|
144
|
-
|
145
|
-
### Process Timeout
|
146
|
-
|
147
|
-
You can run a process group with a time limit by using a separate child process:
|
148
|
-
|
149
|
-
```ruby
|
150
|
-
group = Process::Group.new
|
151
|
-
|
152
|
-
class Timeout < StandardError
|
153
|
-
end
|
154
|
-
|
155
|
-
Fiber.new do
|
156
|
-
# Wait for 2 seconds, let other processes run:
|
157
|
-
group.fork { sleep 2 }
|
158
|
-
|
159
|
-
# If no other processes are running, we are done:
|
160
|
-
Fiber.yield unless group.running?
|
161
|
-
|
162
|
-
# Send SIGINT to currently running processes:
|
163
|
-
group.kill(:INT)
|
164
|
-
|
165
|
-
# Wait for 2 seconds, let other processes run:
|
166
|
-
group.fork { sleep 2 }
|
167
|
-
|
168
|
-
# If no other processes are running, we are done:
|
169
|
-
Fiber.yield unless group.running?
|
170
|
-
|
171
|
-
# Send SIGTERM to currently running processes:
|
172
|
-
group.kill(:TERM)
|
173
|
-
|
174
|
-
# Raise an Timeout exception which is based back out:
|
175
|
-
raise Timeout
|
176
|
-
end.resume
|
177
|
-
|
178
|
-
# Run some other long task:
|
179
|
-
group.run("sleep 10")
|
180
|
-
|
181
|
-
# Wait for fiber to complete:
|
182
|
-
begin
|
183
|
-
group.wait
|
184
|
-
rescue Timeout
|
185
|
-
puts "Process group was terminated forcefully."
|
186
|
-
end
|
187
|
-
```
|
188
|
-
|
189
|
-
## Contributing
|
190
|
-
|
191
|
-
1. Fork it
|
192
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
193
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
194
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
195
|
-
5. Create new Pull Request
|
196
|
-
|
197
|
-
## License
|
198
|
-
|
199
|
-
Released under the MIT license.
|
200
|
-
|
201
|
-
Copyright, 2014, by [Samuel G. D. Williams](http://www.codeotaku.com/samuel-williams).
|
202
|
-
|
203
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy
|
204
|
-
of this software and associated documentation files (the "Software"), to deal
|
205
|
-
in the Software without restriction, including without limitation the rights
|
206
|
-
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
207
|
-
copies of the Software, and to permit persons to whom the Software is
|
208
|
-
furnished to do so, subject to the following conditions:
|
209
|
-
|
210
|
-
The above copyright notice and this permission notice shall be included in
|
211
|
-
all copies or substantial portions of the Software.
|
212
|
-
|
213
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
214
|
-
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
215
|
-
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
216
|
-
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
217
|
-
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
218
|
-
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
219
|
-
THE SOFTWARE.
|
data/Rakefile
DELETED
data/examples/terminal.rb
DELETED
@@ -1,43 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
#
|
3
|
-
# Copyright, 2014, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
4
|
-
#
|
5
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
-
# of this software and associated documentation files (the "Software"), to deal
|
7
|
-
# in the Software without restriction, including without limitation the rights
|
8
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
-
# copies of the Software, and to permit persons to whom the Software is
|
10
|
-
# furnished to do so, subject to the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be included in
|
13
|
-
# all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
-
# THE SOFTWARE.
|
22
|
-
|
23
|
-
require_relative '../lib/process/group'
|
24
|
-
|
25
|
-
group = Process::Group.new
|
26
|
-
|
27
|
-
5.times do
|
28
|
-
Fiber.new do
|
29
|
-
result = group.fork do
|
30
|
-
begin
|
31
|
-
sleep 1 while true
|
32
|
-
rescue Interrupt
|
33
|
-
puts "Interrupted in child #{Process.pid}"
|
34
|
-
end
|
35
|
-
end
|
36
|
-
end.resume
|
37
|
-
end
|
38
|
-
|
39
|
-
begin
|
40
|
-
group.wait
|
41
|
-
rescue Interrupt
|
42
|
-
puts "Interrupted in parent #{Process.pid}"
|
43
|
-
end
|
data/process-group.gemspec
DELETED
@@ -1,29 +0,0 @@
|
|
1
|
-
|
2
|
-
require_relative 'lib/process/group/version'
|
3
|
-
|
4
|
-
Gem::Specification.new do |spec|
|
5
|
-
spec.name = "process-group"
|
6
|
-
spec.version = Process::Group::VERSION
|
7
|
-
spec.authors = ["Samuel Williams"]
|
8
|
-
spec.email = ["samuel.williams@oriontransfer.co.nz"]
|
9
|
-
spec.description = <<-EOF
|
10
|
-
Manages a unix process group for running multiple processes, keeps track of multiple processes and leverages fibers to provide predictable behaviour in complicated process-based scripts.
|
11
|
-
EOF
|
12
|
-
spec.summary = %q{Run processes concurrently in separate fibers with predictable behaviour.}
|
13
|
-
spec.homepage = "https://github.com/ioquatix/process-group"
|
14
|
-
spec.license = "MIT"
|
15
|
-
|
16
|
-
spec.files = `git ls-files`.split($/)
|
17
|
-
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
-
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
-
spec.require_paths = ["lib"]
|
20
|
-
|
21
|
-
spec.required_ruby_version = '>= 2.0'
|
22
|
-
|
23
|
-
spec.add_dependency "process-terminal", "~> 0.2.0"
|
24
|
-
|
25
|
-
spec.add_development_dependency "covered"
|
26
|
-
spec.add_development_dependency "bundler"
|
27
|
-
spec.add_development_dependency "rspec", "~> 3.4.0"
|
28
|
-
spec.add_development_dependency "rake"
|
29
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
# Copyright, 2015, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
# of this software and associated documentation files (the "Software"), to deal
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
20
|
-
|
21
|
-
require 'process/group'
|
22
|
-
|
23
|
-
RSpec.describe Process::Group do
|
24
|
-
it "can run a process in the foreground" do
|
25
|
-
output, input = IO.pipe
|
26
|
-
|
27
|
-
subject.wait do
|
28
|
-
subject.run("irb", foreground: true, in: output)
|
29
|
-
|
30
|
-
input.puts("exit")
|
31
|
-
input.close
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
@@ -1,60 +0,0 @@
|
|
1
|
-
# Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
# of this software and associated documentation files (the "Software"), to deal
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
20
|
-
|
21
|
-
require 'process/group'
|
22
|
-
|
23
|
-
RSpec.describe Process::Group do
|
24
|
-
it "should fork and write to pipe" do
|
25
|
-
input, output = IO.pipe
|
26
|
-
|
27
|
-
Fiber.new do
|
28
|
-
result = subject.fork do
|
29
|
-
output.puts "Hello World"
|
30
|
-
|
31
|
-
exit(1)
|
32
|
-
end
|
33
|
-
|
34
|
-
# We need to close output so that input.read will encounter end of stream.
|
35
|
-
output.close
|
36
|
-
|
37
|
-
expect(result.exitstatus).to be == 1
|
38
|
-
end.resume
|
39
|
-
|
40
|
-
subject.wait
|
41
|
-
|
42
|
-
expect(input.read).to be == "Hello World\n"
|
43
|
-
end
|
44
|
-
|
45
|
-
it "should not throw interrupt from fork" do
|
46
|
-
Fiber.new do
|
47
|
-
result = subject.fork do
|
48
|
-
# Don't print out a backtrace when Ruby invariably exits due to the execption below:
|
49
|
-
$stderr.reopen('/dev/null', 'w')
|
50
|
-
|
51
|
-
raise Interrupt
|
52
|
-
end
|
53
|
-
|
54
|
-
expect(result.exitstatus).not_to be == 0
|
55
|
-
end.resume
|
56
|
-
|
57
|
-
# Shouldn't raise any errors:
|
58
|
-
subject.wait
|
59
|
-
end
|
60
|
-
end
|
@@ -1,146 +0,0 @@
|
|
1
|
-
# Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
# of this software and associated documentation files (the "Software"), to deal
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
20
|
-
|
21
|
-
require 'process/group'
|
22
|
-
|
23
|
-
RSpec.describe Process::Group do
|
24
|
-
it "should raise interrupt exception" do
|
25
|
-
checkpoint = ""
|
26
|
-
|
27
|
-
Fiber.new do
|
28
|
-
checkpoint += 'X'
|
29
|
-
|
30
|
-
result = subject.fork { sleep 0.1 }
|
31
|
-
|
32
|
-
expect(result).to be == 0
|
33
|
-
|
34
|
-
checkpoint += 'Y'
|
35
|
-
|
36
|
-
# Simulate the user pressing Ctrl-C after a short time:
|
37
|
-
raise Interrupt
|
38
|
-
end.resume
|
39
|
-
|
40
|
-
Fiber.new do
|
41
|
-
checkpoint += 'A'
|
42
|
-
|
43
|
-
# This never returns:
|
44
|
-
result = subject.fork do
|
45
|
-
# We do this to exit immediately.. otherwise Ruby will print a backtrace and that's a bit confusing.
|
46
|
-
trap(:INT) { exit!(0) }
|
47
|
-
sleep(0.2)
|
48
|
-
end
|
49
|
-
|
50
|
-
checkpoint += 'B'
|
51
|
-
end.resume
|
52
|
-
|
53
|
-
expect(subject).to receive(:kill).with(:INT).once.and_call_original
|
54
|
-
expect(subject).to receive(:kill).with(:TERM).once.and_call_original
|
55
|
-
|
56
|
-
expect do
|
57
|
-
subject.wait
|
58
|
-
end.to raise_error(Interrupt)
|
59
|
-
|
60
|
-
expect(checkpoint).to be == 'XAY'
|
61
|
-
end
|
62
|
-
|
63
|
-
it "should raise an exception" do
|
64
|
-
checkpoint = ""
|
65
|
-
|
66
|
-
Fiber.new do
|
67
|
-
checkpoint += 'X'
|
68
|
-
|
69
|
-
result = subject.fork { sleep 0.1 }
|
70
|
-
expect(result).to be == 0
|
71
|
-
|
72
|
-
checkpoint += 'Y'
|
73
|
-
|
74
|
-
# Raises a RuntimeError
|
75
|
-
fail "Error"
|
76
|
-
end.resume
|
77
|
-
|
78
|
-
Fiber.new do
|
79
|
-
checkpoint += 'A'
|
80
|
-
|
81
|
-
# This never returns:
|
82
|
-
result = subject.fork { sleep 0.2 }
|
83
|
-
|
84
|
-
checkpoint += 'B'
|
85
|
-
end.resume
|
86
|
-
|
87
|
-
expect do
|
88
|
-
expect(subject).to receive(:kill).with(:TERM).once
|
89
|
-
|
90
|
-
subject.wait
|
91
|
-
end.to raise_error(RuntimeError)
|
92
|
-
|
93
|
-
expect(checkpoint).to be == 'XAY'
|
94
|
-
end
|
95
|
-
|
96
|
-
it "should pass back out exceptions" do
|
97
|
-
checkpoint = ""
|
98
|
-
|
99
|
-
Fiber.new do
|
100
|
-
# Wait for 2 seconds, let other processes run:
|
101
|
-
subject.fork { sleep 2 }
|
102
|
-
checkpoint += 'A'
|
103
|
-
#puts "Finished waiting #1..."
|
104
|
-
|
105
|
-
# If no other processes are running, we are done:
|
106
|
-
Fiber.yield unless subject.running?
|
107
|
-
checkpoint += 'B'
|
108
|
-
#puts "Sending SIGINT..."
|
109
|
-
|
110
|
-
# Send SIGINT to currently running processes:
|
111
|
-
subject.kill(:INT)
|
112
|
-
|
113
|
-
# Wait for 2 seconds, let other processes run:
|
114
|
-
subject.fork { sleep 2 }
|
115
|
-
checkpoint += 'C'
|
116
|
-
#puts "Finished waiting #2..."
|
117
|
-
|
118
|
-
# If no other processes are running, we are done:
|
119
|
-
Fiber.yield unless subject.running?
|
120
|
-
checkpoint += 'D'
|
121
|
-
#puts "Sending SIGTERM..."
|
122
|
-
|
123
|
-
# Send SIGTERM to currently running processes:
|
124
|
-
subject.kill(:TERM)
|
125
|
-
|
126
|
-
# Raise an Timeout exception which is pased back out:
|
127
|
-
raise StandardError.new("Should never get here!")
|
128
|
-
end.resume
|
129
|
-
|
130
|
-
# Run some other long task:
|
131
|
-
subject.run("sleep 10")
|
132
|
-
|
133
|
-
start_time = Time.now
|
134
|
-
|
135
|
-
# Wait for fiber to complete:
|
136
|
-
expect do
|
137
|
-
subject.wait
|
138
|
-
checkpoint += 'E'
|
139
|
-
end.not_to raise_error
|
140
|
-
|
141
|
-
end_time = Time.now
|
142
|
-
|
143
|
-
expect(checkpoint).to be == 'ABCE'
|
144
|
-
expect(end_time - start_time).to be_within(0.2).of 4.0
|
145
|
-
end
|
146
|
-
end
|
@@ -1,52 +0,0 @@
|
|
1
|
-
# Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
# of this software and associated documentation files (the "Software"), to deal
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
20
|
-
|
21
|
-
require 'process/group'
|
22
|
-
|
23
|
-
RSpec.describe Process::Group do
|
24
|
-
it "should read line on separate thread" do
|
25
|
-
input, output = IO.pipe
|
26
|
-
|
27
|
-
Fiber.new do
|
28
|
-
result = subject.fork do
|
29
|
-
3.times do
|
30
|
-
output.puts "Hello World"
|
31
|
-
sleep 0.1
|
32
|
-
end
|
33
|
-
|
34
|
-
exit(0)
|
35
|
-
end
|
36
|
-
|
37
|
-
output.close
|
38
|
-
|
39
|
-
expect(result).to be == 0
|
40
|
-
end.resume
|
41
|
-
|
42
|
-
lines = nil
|
43
|
-
io_thread = Thread.new do
|
44
|
-
lines = input.read
|
45
|
-
end
|
46
|
-
|
47
|
-
subject.wait
|
48
|
-
|
49
|
-
io_thread.join
|
50
|
-
expect(lines).to be == ("Hello World\n" * 3)
|
51
|
-
end
|
52
|
-
end
|
@@ -1,42 +0,0 @@
|
|
1
|
-
# Copyright, 2015, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
# of this software and associated documentation files (the "Software"), to deal
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
20
|
-
|
21
|
-
require 'process/group'
|
22
|
-
|
23
|
-
RSpec.describe Process::Group.new(limit: 5) do
|
24
|
-
it "should only run a limited number of processes" do
|
25
|
-
expect(subject.available?).to be_truthy
|
26
|
-
expect(subject.blocking?).to be_falsey
|
27
|
-
|
28
|
-
5.times do
|
29
|
-
Fiber.new do
|
30
|
-
result = subject.fork do
|
31
|
-
exit(0)
|
32
|
-
end
|
33
|
-
|
34
|
-
expect(result.exitstatus).to be == 0
|
35
|
-
end.resume
|
36
|
-
end
|
37
|
-
|
38
|
-
subject.wait do
|
39
|
-
expect(subject.blocking?).to be_truthy
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
@@ -1,55 +0,0 @@
|
|
1
|
-
# Copyright, 2015, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
# of this software and associated documentation files (the "Software"), to deal
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
20
|
-
|
21
|
-
RSpec.describe Process do
|
22
|
-
it "default fork exit status should be 0" do
|
23
|
-
pid = fork do
|
24
|
-
end
|
25
|
-
|
26
|
-
Process.waitpid(pid)
|
27
|
-
|
28
|
-
expect($?.exitstatus).to be == 0
|
29
|
-
end
|
30
|
-
|
31
|
-
it "should fork and return exit status correctly" do
|
32
|
-
pid = fork do
|
33
|
-
exit(1)
|
34
|
-
end
|
35
|
-
|
36
|
-
Process.waitpid(pid)
|
37
|
-
|
38
|
-
expect($?.exitstatus).to be == 1
|
39
|
-
end
|
40
|
-
|
41
|
-
# This is currently broken on Rubinius.
|
42
|
-
it "should be okay to use fork within a fiber" do
|
43
|
-
pid = nil
|
44
|
-
|
45
|
-
Fiber.new do
|
46
|
-
pid = fork do
|
47
|
-
exit(2)
|
48
|
-
end
|
49
|
-
end.resume
|
50
|
-
|
51
|
-
Process.waitpid(pid)
|
52
|
-
|
53
|
-
expect($?.exitstatus).to be == 2
|
54
|
-
end
|
55
|
-
end
|
@@ -1,99 +0,0 @@
|
|
1
|
-
# Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
# of this software and associated documentation files (the "Software"), to deal
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
20
|
-
|
21
|
-
require 'process/group'
|
22
|
-
|
23
|
-
RSpec.describe Process::Group do
|
24
|
-
it "should execute fibers concurrently" do
|
25
|
-
start_time = Time.now
|
26
|
-
|
27
|
-
Fiber.new do
|
28
|
-
result = subject.fork { sleep 1.0 }
|
29
|
-
|
30
|
-
expect(result).to be == 0
|
31
|
-
end.resume
|
32
|
-
|
33
|
-
Fiber.new do
|
34
|
-
result = subject.fork { sleep 2.0 }
|
35
|
-
|
36
|
-
expect(result).to be == 0
|
37
|
-
end.resume
|
38
|
-
|
39
|
-
subject.wait
|
40
|
-
|
41
|
-
end_time = Time.now
|
42
|
-
|
43
|
-
# Check that the execution time was roughly 2 seconds:
|
44
|
-
expect(end_time - start_time).to be_within(0.1).of(2.0)
|
45
|
-
end
|
46
|
-
|
47
|
-
it "should kill commands" do
|
48
|
-
start_time = Time.now
|
49
|
-
|
50
|
-
subject.run("sleep 1") do |exit_status|
|
51
|
-
expect(exit_status).to_not be 0
|
52
|
-
end
|
53
|
-
|
54
|
-
subject.run("sleep 2") do |exit_status|
|
55
|
-
expect(exit_status).to_not be 0
|
56
|
-
end
|
57
|
-
|
58
|
-
subject.wait do
|
59
|
-
subject.kill(:KILL)
|
60
|
-
end
|
61
|
-
|
62
|
-
end_time = Time.now
|
63
|
-
|
64
|
-
# Check that processes killed almost immediately:
|
65
|
-
expect(end_time - start_time).to be < 0.2
|
66
|
-
end
|
67
|
-
|
68
|
-
it "should pass environment to child process" do
|
69
|
-
env = {'FOO' => 'BAR'}
|
70
|
-
|
71
|
-
# Make a pipe to receive output from child process:
|
72
|
-
input, output = IO.pipe
|
73
|
-
|
74
|
-
subject.run(env, "echo $FOO", out: output) do |exit_status|
|
75
|
-
output.close
|
76
|
-
end
|
77
|
-
|
78
|
-
subject.wait
|
79
|
-
|
80
|
-
expect(input.read).to be == "BAR\n"
|
81
|
-
end
|
82
|
-
|
83
|
-
it "should yield exit status" do
|
84
|
-
start_time = Time.now
|
85
|
-
|
86
|
-
subject.run("sleep 1")
|
87
|
-
|
88
|
-
subject.run("sleep 1") do |exit_status|
|
89
|
-
expect(exit_status).to be == 0
|
90
|
-
end
|
91
|
-
|
92
|
-
subject.wait
|
93
|
-
|
94
|
-
end_time = Time.now
|
95
|
-
|
96
|
-
# Check that the execution time was roughly 1 second:
|
97
|
-
expect(end_time - start_time).to be_within(0.1).of(1.0)
|
98
|
-
end
|
99
|
-
end
|
@@ -1,85 +0,0 @@
|
|
1
|
-
# Copyright, 2012, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
# of this software and associated documentation files (the "Software"), to deal
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
20
|
-
|
21
|
-
require 'process/group'
|
22
|
-
|
23
|
-
RSpec.describe Process::Group do
|
24
|
-
it "should invoke child task normally" do
|
25
|
-
start_time = Time.now
|
26
|
-
|
27
|
-
child_exit_status = nil
|
28
|
-
|
29
|
-
subject.wait do
|
30
|
-
subject.run("exit 0") do |exit_status|
|
31
|
-
child_exit_status = exit_status
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
expect(child_exit_status).to be == 0
|
36
|
-
end
|
37
|
-
|
38
|
-
it "should kill child task if process is interrupted" do
|
39
|
-
start_time = Time.now
|
40
|
-
|
41
|
-
child_exit_status = nil
|
42
|
-
|
43
|
-
expect do
|
44
|
-
subject.wait do
|
45
|
-
subject.run("sleep 10") do |exit_status|
|
46
|
-
child_exit_status = exit_status
|
47
|
-
end
|
48
|
-
|
49
|
-
# Simulate the parent (controlling) process receiving an interrupt.
|
50
|
-
raise Interrupt
|
51
|
-
end
|
52
|
-
end.to raise_error(Interrupt)
|
53
|
-
|
54
|
-
expect(child_exit_status).to_not be == 0
|
55
|
-
end
|
56
|
-
|
57
|
-
it "should propagate Interrupt" do
|
58
|
-
expect(Process::Group).to receive(:new).once.and_call_original
|
59
|
-
|
60
|
-
expect do
|
61
|
-
Process::Group.wait do |group|
|
62
|
-
raise Interrupt
|
63
|
-
end
|
64
|
-
end.to raise_error(Interrupt)
|
65
|
-
end
|
66
|
-
|
67
|
-
it "should clear queue after wait" do
|
68
|
-
subject.limit = 1
|
69
|
-
|
70
|
-
subject.run("sleep 10")
|
71
|
-
subject.run("sleep 10")
|
72
|
-
|
73
|
-
expect(subject.running?).to be_falsey
|
74
|
-
expect(subject.queued?).to be_truthy
|
75
|
-
|
76
|
-
expect do
|
77
|
-
subject.wait do
|
78
|
-
raise Interrupt
|
79
|
-
end
|
80
|
-
end.to raise_error(Interrupt)
|
81
|
-
|
82
|
-
expect(subject.running?).to be_falsey
|
83
|
-
expect(subject.queued?).to be_falsey
|
84
|
-
end
|
85
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
# Copyright, 2019, by Samuel G. D. Williams. <http://www.codeotaku.com>
|
2
|
-
#
|
3
|
-
# Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
-
# of this software and associated documentation files (the "Software"), to deal
|
5
|
-
# in the Software without restriction, including without limitation the rights
|
6
|
-
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
-
# copies of the Software, and to permit persons to whom the Software is
|
8
|
-
# furnished to do so, subject to the following conditions:
|
9
|
-
#
|
10
|
-
# The above copyright notice and this permission notice shall be included in
|
11
|
-
# all copies or substantial portions of the Software.
|
12
|
-
#
|
13
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
-
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
-
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
-
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
-
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
-
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
-
# THE SOFTWARE.
|
20
|
-
|
21
|
-
require "bundler/setup"
|
22
|
-
require 'covered/rspec'
|
23
|
-
|
24
|
-
RSpec.configure do |config|
|
25
|
-
# Enable flags like --only-failures and --next-failure
|
26
|
-
config.example_status_persistence_file_path = ".rspec_status"
|
27
|
-
|
28
|
-
# Disable RSpec exposing methods globally on `Module` and `main`
|
29
|
-
config.disable_monkey_patching!
|
30
|
-
|
31
|
-
config.expect_with :rspec do |c|
|
32
|
-
c.syntax = :expect
|
33
|
-
end
|
34
|
-
end
|