multi_process 0.5.0 → 1.1.1

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
- SHA1:
3
- metadata.gz: b79dfed9809a87ffa684f477aa18f52ab0874998
4
- data.tar.gz: a2499bf8685aaa502893af7848d7de805e104e5a
2
+ SHA256:
3
+ metadata.gz: ea43e9440c1ed8b4e62d74a24514447389c104eddc20df1870f14ef8316f90e7
4
+ data.tar.gz: 52de1eb70c9832e2ef8e0fcd53fe247905342bf45a28b40b852365d413a68136
5
5
  SHA512:
6
- metadata.gz: 12f8ae434f79b4168460722d3cff268ae2b230084e89ff000e9c758a3d8f625d47bf3a7d0a8169db4e2e6df36e61e1e0920f8192c89cdb526a814f4d3789d07d
7
- data.tar.gz: 10e081ebeb820e7563fd9c91c50c962216283c7cee939da51b8adbcc74e49d72d983e6df9e4415c71f6b383e4ebaa5e8069b3968fdbff76b9e17e2a1fce19f0a
6
+ metadata.gz: 2ed3835793ff96ab2696b4521f93961f46267c4e75d5baa44c5bc45082c888bfbd691ac7d730596377727863c3b9f6b8d33943cdbaf55f49c560979c6affe0be
7
+ data.tar.gz: 95f65e1e3e3c2afb26ca37e99706271774bd949111260a02468036b86fe6e51ddf4cedfa58089154b626217d58e7e72b0affae12f60b4d17424cefffb096b716
@@ -0,0 +1,20 @@
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
+ ### Fixed
9
+ - Replaced deprecated `#with_clean_env` method
10
+
11
+ ## [1.1.0] - 2020-11-19
12
+ ### Added
13
+ - Add support for IPv6 by using the hostname instead of the loopback IPv4 address (#2)
14
+
15
+ ## 1.0.0 - 2019-05-13
16
+ ### Fixed
17
+ - Possible concurrent hash modification while iterating (#1)
18
+
19
+ [Unreleased]: https://github.com/jgraichen/multi_process/compare/v1.1.0...HEAD
20
+ [1.1.0]: https://github.com/jgraichen/multi_process/compare/v1.0.0...v1.1.0
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'
@@ -35,8 +35,8 @@ module MultiProcess
35
35
  #
36
36
  # @param process [Process, Array<Process>] New process or processes.
37
37
  #
38
- def <<(processes)
39
- Array(processes).flatten.each do |process|
38
+ def <<(procs)
39
+ Array(procs).flatten.each do |process|
40
40
  processes << process
41
41
  process.receiver = receiver
42
42
 
@@ -95,7 +95,7 @@ module MultiProcess
95
95
  # If timeout is given process will be terminated using {#stop}
96
96
  # when timeout error is raised.
97
97
  #
98
- def run(**kwargs)
98
+ def run(delay: nil, timeout: nil)
99
99
  if partition > 0
100
100
  partition.times.map do
101
101
  Thread.new do
@@ -105,8 +105,8 @@ module MultiProcess
105
105
  end
106
106
  end.each(&:join)
107
107
  else
108
- start(**kwargs)
109
- wait(**kwargs)
108
+ start delay: delay
109
+ wait timeout: timeout
110
110
  end
111
111
  ensure
112
112
  stop
@@ -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
@@ -190,7 +190,7 @@ module MultiProcess
190
190
  childprocess.cwd = dir
191
191
 
192
192
  if clean_env?
193
- Bundler.with_clean_env { childprocess.start }
193
+ Bundler.with_original_env { childprocess.start }
194
194
  else
195
195
  childprocess.start
196
196
  end
@@ -44,7 +44,7 @@ class MultiProcess::Process
44
44
  def available?
45
45
  fail ArgumentError.new "Cannot check availability for port #{port}." if port == 0
46
46
 
47
- TCPSocket.new('127.0.0.1', port).close
47
+ TCPSocket.new('localhost', port).close
48
48
  true
49
49
  rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
50
50
  false
@@ -67,7 +67,7 @@ class MultiProcess::Process
67
67
 
68
68
  def free_port
69
69
  socket = Socket.new(:INET, :STREAM, 0)
70
- socket.bind(Addrinfo.tcp('127.0.0.1', 0))
70
+ socket.bind(Addrinfo.tcp('localhost', 0))
71
71
  socket.local_address.ip_port
72
72
  ensure
73
73
  socket.close if socket
@@ -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 = 0
3
+ MAJOR = 1
4
+ MINOR = 1
5
+ PATCH = 1
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.0
4
+ version: 1.1.1
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: 2020-12-21 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.2.1
104
119
  signing_key:
105
120
  specification_version: 4
106
121
  summary: Handle multiple child processes.