multi_process 0.5.2 → 1.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
- SHA1:
3
- metadata.gz: 550774b3bb8c3f49060efc3d508f1d55a0c70924
4
- data.tar.gz: e8bfbfe219cd440b5c7163db8cf81c8e8c1f0470
2
+ SHA256:
3
+ metadata.gz: 9f71381653129f6aa7bf31441102ce950a28ce3d39da4bf7b4542ac1401b1ee3
4
+ data.tar.gz: 98146cfa10d5530f03b11d1d80679417d6820dd2764ec9161751f77bdad309f6
5
5
  SHA512:
6
- metadata.gz: 098592026b269f5afcee611ab82bc06863eba7795e1f7afd446d314d6f44584e14901518ff9b18e12e1b85a435d9a8238d21ac0471de0f65af10f64fd5851cdf
7
- data.tar.gz: 87be05c69577bac776b30dcd4a009029e7591a1d9512771ce885939769340a5e79baf5d1fbc5f2c23d851a80e5c5dbfa35dbdaa4b6cc4ba47bc2f949663b19ce
6
+ metadata.gz: 331cf8cb96d54d265fecaa6750b9c71d9e11231385d6d778ffde6a664d636478b855e525cbe2d3bd474127308ab615b2f90e8599f80159af01041dae3117506a
7
+ data.tar.gz: dde0d89ada0985a2188edb4ec9a169d595d609580370c9e1f1f2b818897c7ed9b2c88420b5608f002b281c9c93c45c8d800cba4adcbaeaac652d8cbd01f16938
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+ All notable changes to this project will be documented in this file.
3
+
4
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
5
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ## 1.0.0 - 2019-05-13
10
+ ### Fixed
11
+ - Possible concurrent hash modification while iterating (#1)
12
+
13
+ [Unreleased]: https://github.com/jgraichen/multi_process/compare/v1.0.0...HEAD
data/README.md CHANGED
@@ -39,7 +39,7 @@ group.stop # Stop processes
39
39
  (23314) rubyC | Output from C
40
40
  (23311) rubyB | Output from B
41
41
  (23308) rubyA | Output from A
42
- ``
42
+ ```
43
43
 
44
44
  ## Contributing
45
45
 
@@ -51,7 +51,7 @@ group.stop # Stop processes
51
51
 
52
52
  ## License
53
53
 
54
- Copyright (C) 2014 Jan Graichen
54
+ Copyright (C) 2019 Jan Graichen
55
55
 
56
56
  This program is free software: you can redistribute it and/or modify
57
57
  it under the terms of the GNU General Public License as published by
@@ -4,6 +4,7 @@ require 'childprocess'
4
4
  module MultiProcess
5
5
  DEFAULT_TIMEOUT = 60
6
6
 
7
+ require 'multi_process/loop'
7
8
  require 'multi_process/group'
8
9
  require 'multi_process/receiver'
9
10
  require 'multi_process/nil_receiver'
@@ -16,6 +16,8 @@ module MultiProcess
16
16
  @out = args[0] || $stdout
17
17
  @err = args[1] || $stderr
18
18
 
19
+ @colwidth = 0
20
+
19
21
  super()
20
22
  end
21
23
 
@@ -32,6 +34,10 @@ module MultiProcess
32
34
  end
33
35
  end
34
36
 
37
+ def connected(process, _)
38
+ @colwidth = [process.title.to_s.length, @colwidth].max
39
+ end
40
+
35
41
  def read(pipe)
36
42
  pipe.gets
37
43
  end
@@ -43,26 +49,27 @@ module MultiProcess
43
49
  private
44
50
 
45
51
  def output(process, line, opts = {})
46
- @mutex.synchronize do
47
- opts[:delimiter] ||= ' |'
48
- name = if opts[:name]
49
- opts[:name].to_s.dup
52
+ opts[:delimiter] ||= ' |'
53
+ name = if opts[:name]
54
+ opts[:name].to_s.dup
55
+ else
56
+ if process
57
+ process.title.to_s.rjust(@colwidth, ' ')
50
58
  else
51
- max = @readers.values.map { |h| h[:process] ? h[:process].title.length : 0 }.max
52
- process ? process.title.to_s.rjust(max, ' ') : (' ' * max)
53
- end
59
+ (' ' * @colwidth)
60
+ end
61
+ end
54
62
 
55
- io = opts[:io] || @out
56
- if @last_name == name && collapse?
57
- io.print " #{' ' * name.length} #{opts[:delimiter]} "
58
- else
59
- io.print " #{name} #{opts[:delimiter]} "
60
- end
61
- io.puts line
62
- io.flush
63
-
64
- @last_name = name
63
+ io = opts[:io] || @out
64
+ if @last_name == name && collapse?
65
+ io.print " #{' ' * name.length} #{opts[:delimiter]} "
66
+ else
67
+ io.print " #{name} #{opts[:delimiter]} "
65
68
  end
69
+ io.puts line
70
+ io.flush
71
+
72
+ @last_name = name
66
73
  end
67
74
 
68
75
  class << self
@@ -0,0 +1,39 @@
1
+ require 'nio'
2
+
3
+ module MultiProcess
4
+ class Loop
5
+ def initialize
6
+ @selector = ::NIO::Selector.new
7
+
8
+ Thread.new do
9
+ loop do
10
+ @selector.select(30.0) do |monitor|
11
+ if monitor.io.eof?
12
+ @selector.deregister(monitor.io)
13
+ monitor.value.call(:eof, monitor)
14
+ else
15
+ monitor.value.call(:ready, monitor)
16
+ end
17
+ end
18
+
19
+ # Wait very short time to allow scheduling another thread
20
+ sleep(0.001)
21
+ end
22
+ end
23
+ end
24
+
25
+ def watch(io, &block)
26
+ @selector.wakeup
27
+ @selector.register(io, :r).tap do |monitor|
28
+ monitor.value = block
29
+ monitor.value.call(:registered, monitor)
30
+ end
31
+ end
32
+
33
+ class << self
34
+ def instance
35
+ @instance ||= new
36
+ end
37
+ end
38
+ end
39
+ end
@@ -3,36 +3,6 @@ module MultiProcess
3
3
  # actions on event and output.
4
4
  #
5
5
  class Receiver
6
- # Mutex to synchronize operations.
7
- #
8
- attr_reader :mutex
9
-
10
- def initialize
11
- @mutex = Mutex.new
12
- @readers = {}
13
-
14
- Thread.new do
15
- begin
16
- loop do
17
- io = IO.select(@readers.keys, nil, nil, 0.1)
18
- (io.nil? ? [] : io.first).each do |reader|
19
- op = @readers[reader]
20
-
21
- if reader.eof?
22
- @readers.delete_if { |key, _value| key == reader }
23
- removed op[:process], op[:name]
24
- else
25
- received op[:process], op[:name], read(reader)
26
- end
27
- end
28
- end
29
- rescue Exception => ex
30
- puts ex.message
31
- puts ex.backtrace
32
- end
33
- end
34
- end
35
-
36
6
  # Request a new pipe writer for given process and name.
37
7
  #
38
8
  # @param process [ Process ] Process requesting pipe.
@@ -41,8 +11,18 @@ module MultiProcess
41
11
  #
42
12
  def pipe(process, name)
43
13
  reader, writer = IO.pipe
44
- @readers[reader] = { name: name, process: process }
45
- connected process, name
14
+
15
+ Loop.instance.watch(reader) do |action, monitor|
16
+ case action
17
+ when :registered
18
+ connected(process, name)
19
+ when :ready
20
+ received(process, name, read(monitor.io))
21
+ when :eof
22
+ removed(process, name)
23
+ end
24
+ end
25
+
46
26
  writer
47
27
  end
48
28
 
@@ -1,8 +1,8 @@
1
1
  module MultiProcess
2
2
  module VERSION
3
- MAJOR = 0
4
- MINOR = 5
5
- PATCH = 2
3
+ MAJOR = 1
4
+ MINOR = 0
5
+ PATCH = 0
6
6
  STAGE = nil
7
7
  STRING = [MAJOR, MINOR, PATCH, STAGE].reject(&:nil?).join('.')
8
8
 
@@ -20,6 +20,7 @@ Gem::Specification.new do |spec|
20
20
 
21
21
  spec.add_runtime_dependency 'activesupport', '>= 3.1'
22
22
  spec.add_runtime_dependency 'childprocess'
23
+ spec.add_runtime_dependency 'nio4r', '~> 2.0'
23
24
 
24
- spec.add_development_dependency 'bundler', '~> 1.5'
25
+ spec.add_development_dependency 'bundler'
25
26
  end
@@ -7,17 +7,17 @@ describe MultiProcess do
7
7
  logger = MultiProcess::Logger.new writer, collapse: false
8
8
  group = MultiProcess::Group.new receiver: logger
9
9
  group << MultiProcess::Process.new(%w(ruby spec/files/test.rb A), title: 'rubyA')
10
- group << MultiProcess::Process.new(%w(ruby spec/files/test.rb B), title: 'rubyB')
11
- group << MultiProcess::Process.new(%w(ruby spec/files/test.rb C), title: 'rubyC')
10
+ group << MultiProcess::Process.new(%w(ruby spec/files/test.rb B), title: 'rubyBB')
11
+ group << MultiProcess::Process.new(%w(ruby spec/files/test.rb C), title: 'rubyCCC')
12
12
  group.run
13
13
 
14
- expect(reader.read_nonblock(4096).split("\n")).to match_array <<-EOF.gsub(/^\s+/, ' ').split("\n")
15
- rubyB | Output from B
16
- rubyA | Output from A
17
- rubyA | Output from A
18
- rubyC | Output from C
19
- rubyC | Output from C
20
- rubyB | Output from B
14
+ expect(reader.read_nonblock(4096).split("\n")).to match_array <<-EOF.gsub(/^\s+\./, '').split("\n")
15
+ . rubyBB | Output from B
16
+ . rubyA | Output from A
17
+ . rubyA | Output from A
18
+ . rubyCCC | Output from C
19
+ . rubyCCC | Output from C
20
+ . rubyBB | Output from B
21
21
  EOF
22
22
  end
23
23
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: multi_process
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.2
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jan Graichen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-30 00:00:00.000000000 Z
11
+ date: 2019-05-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -39,19 +39,33 @@ dependencies:
39
39
  - !ruby/object:Gem::Version
40
40
  version: '0'
41
41
  - !ruby/object:Gem::Dependency
42
- name: bundler
42
+ name: nio4r
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
45
  - - "~>"
46
46
  - !ruby/object:Gem::Version
47
- version: '1.5'
48
- type: :development
47
+ version: '2.0'
48
+ type: :runtime
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
- version: '1.5'
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: bundler
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  description: Handle multiple child processes.
56
70
  email:
57
71
  - jg@altimos.de
@@ -60,6 +74,7 @@ extensions: []
60
74
  extra_rdoc_files: []
61
75
  files:
62
76
  - ".gitignore"
77
+ - CHANGELOG.md
63
78
  - Gemfile
64
79
  - LICENSE.txt
65
80
  - README.md
@@ -67,6 +82,7 @@ files:
67
82
  - lib/multi_process.rb
68
83
  - lib/multi_process/group.rb
69
84
  - lib/multi_process/logger.rb
85
+ - lib/multi_process/loop.rb
70
86
  - lib/multi_process/nil_receiver.rb
71
87
  - lib/multi_process/process.rb
72
88
  - lib/multi_process/process/bundle_exec.rb
@@ -99,8 +115,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
99
115
  - !ruby/object:Gem::Version
100
116
  version: '0'
101
117
  requirements: []
102
- rubyforge_project:
103
- rubygems_version: 2.4.6
118
+ rubygems_version: 3.0.3
104
119
  signing_key:
105
120
  specification_version: 4
106
121
  summary: Handle multiple child processes.