async-container 0.18.2 → 0.19.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 +4 -4
- checksums.yaml.gz.sig +0 -0
- data/lib/async/container/best.rb +4 -4
- data/lib/async/container/channel.rb +2 -2
- data/lib/async/container/controller.rb +57 -44
- data/lib/async/container/error.rb +4 -4
- data/lib/async/container/forked.rb +186 -4
- data/lib/async/container/generic.rb +23 -16
- data/lib/async/container/group.rb +21 -10
- data/lib/async/container/hybrid.rb +3 -3
- data/lib/async/container/notify/console.rb +4 -4
- data/lib/async/container/notify/pipe.rb +5 -5
- data/lib/async/container/notify/server.rb +14 -7
- data/lib/async/container/notify/socket.rb +8 -4
- data/lib/async/container/notify.rb +4 -4
- data/lib/async/container/statistics.rb +2 -2
- data/lib/async/container/threaded.rb +196 -4
- data/lib/async/container/version.rb +1 -1
- data/lib/async/container.rb +2 -2
- data/license.md +1 -1
- data/readme.md +3 -3
- data/releases.md +6 -0
- data.tar.gz.sig +0 -0
- metadata +4 -10
- metadata.gz.sig +0 -0
- data/lib/async/container/process.rb +0 -173
- data/lib/async/container/thread.rb +0 -200
@@ -1,200 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Released under the MIT License.
|
4
|
-
# Copyright, 2020-2022, by Samuel Williams.
|
5
|
-
# Copyright, 2020, by Olle Jonsson.
|
6
|
-
|
7
|
-
require_relative 'channel'
|
8
|
-
require_relative 'error'
|
9
|
-
require_relative 'notify/pipe'
|
10
|
-
|
11
|
-
module Async
|
12
|
-
module Container
|
13
|
-
# Represents a running child thread from the point of view of the parent container.
|
14
|
-
class Thread < Channel
|
15
|
-
# Used to propagate the exit status of a child process invoked by {Instance#exec}.
|
16
|
-
class Exit < Exception
|
17
|
-
# Initialize the exit status.
|
18
|
-
# @parameter status [::Process::Status] The process exit status.
|
19
|
-
def initialize(status)
|
20
|
-
@status = status
|
21
|
-
end
|
22
|
-
|
23
|
-
# The process exit status.
|
24
|
-
# @attribute [::Process::Status]
|
25
|
-
attr :status
|
26
|
-
|
27
|
-
# The process exit status if it was an error.
|
28
|
-
# @returns [::Process::Status | Nil]
|
29
|
-
def error
|
30
|
-
unless status.success?
|
31
|
-
status
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
# Represents a running child thread from the point of view of the child thread.
|
37
|
-
class Instance < Notify::Pipe
|
38
|
-
# Wrap an instance around the {Thread} instance from within the threaded child.
|
39
|
-
# @parameter thread [Thread] The thread intance to wrap.
|
40
|
-
def self.for(thread)
|
41
|
-
instance = self.new(thread.out)
|
42
|
-
|
43
|
-
return instance
|
44
|
-
end
|
45
|
-
|
46
|
-
def initialize(io)
|
47
|
-
@name = nil
|
48
|
-
@thread = ::Thread.current
|
49
|
-
|
50
|
-
super
|
51
|
-
end
|
52
|
-
|
53
|
-
# Set the name of the thread.
|
54
|
-
# @parameter value [String] The name to set.
|
55
|
-
def name= value
|
56
|
-
@thread.name = value
|
57
|
-
end
|
58
|
-
|
59
|
-
# Get the name of the thread.
|
60
|
-
# @returns [String]
|
61
|
-
def name
|
62
|
-
@thread.name
|
63
|
-
end
|
64
|
-
|
65
|
-
# Execute a child process using {::Process.spawn}. In order to simulate {::Process.exec}, an {Exit} instance is raised to propagage exit status.
|
66
|
-
# This creates the illusion that this method does not return (normally).
|
67
|
-
def exec(*arguments, ready: true, **options)
|
68
|
-
if ready
|
69
|
-
self.ready!(status: "(spawn)") if ready
|
70
|
-
else
|
71
|
-
self.before_spawn(arguments, options)
|
72
|
-
end
|
73
|
-
|
74
|
-
begin
|
75
|
-
# TODO prefer **options... but it doesn't support redirections on < 2.7
|
76
|
-
pid = ::Process.spawn(*arguments, options)
|
77
|
-
ensure
|
78
|
-
_, status = ::Process.wait2(pid)
|
79
|
-
|
80
|
-
raise Exit, status
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
def self.fork(**options)
|
86
|
-
self.new(**options) do |thread|
|
87
|
-
::Thread.new do
|
88
|
-
yield Instance.for(thread)
|
89
|
-
end
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
|
-
# Initialize the thread.
|
94
|
-
# @parameter name [String] The name to use for the child thread.
|
95
|
-
def initialize(name: nil)
|
96
|
-
super()
|
97
|
-
|
98
|
-
@status = nil
|
99
|
-
|
100
|
-
@thread = yield(self)
|
101
|
-
@thread.report_on_exception = false
|
102
|
-
@thread.name = name
|
103
|
-
|
104
|
-
@waiter = ::Thread.new do
|
105
|
-
begin
|
106
|
-
@thread.join
|
107
|
-
rescue Exit => exit
|
108
|
-
finished(exit.error)
|
109
|
-
rescue Interrupt
|
110
|
-
# Graceful shutdown.
|
111
|
-
finished
|
112
|
-
rescue Exception => error
|
113
|
-
finished(error)
|
114
|
-
else
|
115
|
-
finished
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
# Set the name of the thread.
|
121
|
-
# @parameter value [String] The name to set.
|
122
|
-
def name= value
|
123
|
-
@thread.name = value
|
124
|
-
end
|
125
|
-
|
126
|
-
# Get the name of the thread.
|
127
|
-
# @returns [String]
|
128
|
-
def name
|
129
|
-
@thread.name
|
130
|
-
end
|
131
|
-
|
132
|
-
# A human readable representation of the thread.
|
133
|
-
# @returns [String]
|
134
|
-
def to_s
|
135
|
-
"\#<#{self.class} #{@thread.name}>"
|
136
|
-
end
|
137
|
-
|
138
|
-
# Invoke {#terminate!} and then {#wait} for the child thread to exit.
|
139
|
-
def close
|
140
|
-
self.terminate!
|
141
|
-
self.wait
|
142
|
-
ensure
|
143
|
-
super
|
144
|
-
end
|
145
|
-
|
146
|
-
# Raise {Interrupt} in the child thread.
|
147
|
-
def interrupt!
|
148
|
-
@thread.raise(Interrupt)
|
149
|
-
end
|
150
|
-
|
151
|
-
# Raise {Terminate} in the child thread.
|
152
|
-
def terminate!
|
153
|
-
@thread.raise(Terminate)
|
154
|
-
end
|
155
|
-
|
156
|
-
# Wait for the thread to exit and return he exit status.
|
157
|
-
# @returns [Status]
|
158
|
-
def wait
|
159
|
-
if @waiter
|
160
|
-
@waiter.join
|
161
|
-
@waiter = nil
|
162
|
-
end
|
163
|
-
|
164
|
-
return @status
|
165
|
-
end
|
166
|
-
|
167
|
-
# A pseudo exit-status wrapper.
|
168
|
-
class Status
|
169
|
-
# Initialise the status.
|
170
|
-
# @parameter error [::Process::Status] The exit status of the child thread.
|
171
|
-
def initialize(error = nil)
|
172
|
-
@error = error
|
173
|
-
end
|
174
|
-
|
175
|
-
# Whether the status represents a successful outcome.
|
176
|
-
# @returns [Boolean]
|
177
|
-
def success?
|
178
|
-
@error.nil?
|
179
|
-
end
|
180
|
-
|
181
|
-
# A human readable representation of the status.
|
182
|
-
def to_s
|
183
|
-
"\#<#{self.class} #{success? ? "success" : "failure"}>"
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
protected
|
188
|
-
|
189
|
-
# Invoked by the @waiter thread to indicate the outcome of the child thread.
|
190
|
-
def finished(error = nil)
|
191
|
-
if error
|
192
|
-
Console.logger.error(self) {error}
|
193
|
-
end
|
194
|
-
|
195
|
-
@status = Status.new(error)
|
196
|
-
self.close_write
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|