async-container 0.20.0 → 0.21.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/forked.rb +7 -0
- data/lib/async/container/generic.rb +5 -3
- data/lib/async/container/hybrid.rb +4 -2
- data/lib/async/container/threaded.rb +12 -1
- data/lib/async/container/version.rb +1 -1
- data/readme.md +22 -1
- data/releases.md +46 -1
- data.tar.gz.sig +0 -0
- metadata +2 -2
- metadata.gz.sig +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6dd27e02912c5f1258419c9821da1bd97d58f4fd68b4a58512b3ebd5291c5b6b
|
4
|
+
data.tar.gz: 36fc9d2d0ce94a0e2591beac3384d2fba288094a93c1ada7a9000841c1e78a59
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 162f3604bbaa973b486fc271ccf61106008a5d2259f114134535188349267ee3dfb81cbe857ce7edc49dd2037b5d1f5581dd531955ddbfba264a113638e300cd
|
7
|
+
data.tar.gz: b1ba5f8e3b96976a97b6f81e20a62efbcbde89e4e2f0be43c754954a44924e2553c447cf275121ce74894d0044e7677a144c7f43df5f77d7a55b263f6442eb96
|
checksums.yaml.gz.sig
CHANGED
Binary file
|
@@ -39,7 +39,7 @@ module Async
|
|
39
39
|
UNNAMED = "Unnamed"
|
40
40
|
|
41
41
|
def initialize(**options)
|
42
|
-
@group = Group.new
|
42
|
+
@group = Group.new(**options)
|
43
43
|
@running = true
|
44
44
|
|
45
45
|
@state = {}
|
@@ -48,8 +48,10 @@ module Async
|
|
48
48
|
@keyed = {}
|
49
49
|
end
|
50
50
|
|
51
|
+
# @attribute [Group] The group of running children instances.
|
51
52
|
attr :group
|
52
53
|
|
54
|
+
# @attribute [Hash(Child, Hash)] The state of each child instance.
|
53
55
|
attr :state
|
54
56
|
|
55
57
|
# A human readable representation of the container.
|
@@ -170,8 +172,8 @@ module Async
|
|
170
172
|
when :health_check!
|
171
173
|
if health_check_timeout&.<(age_clock.total)
|
172
174
|
Console.warn(self, "Child failed health check!", child: child, age: age_clock.total, health_check_timeout: health_check_timeout)
|
173
|
-
# If the child has failed the health check, we assume the worst and
|
174
|
-
child.
|
175
|
+
# If the child has failed the health check, we assume the worst and kill it immediately:
|
176
|
+
child.kill!
|
175
177
|
end
|
176
178
|
else
|
177
179
|
state.update(message)
|
@@ -15,7 +15,8 @@ module Async
|
|
15
15
|
# @parameter count [Integer] The number of instances to start.
|
16
16
|
# @parameter forks [Integer] The number of processes to fork.
|
17
17
|
# @parameter threads [Integer] the number of threads to start.
|
18
|
-
|
18
|
+
# @parameter health_check_timeout [Numeric] The timeout for health checks, in seconds. Passed into the child {Threaded} containers.
|
19
|
+
def run(count: nil, forks: nil, threads: nil, health_check_timeout: nil, **options, &block)
|
19
20
|
processor_count = Container.processor_count
|
20
21
|
count ||= processor_count ** 2
|
21
22
|
forks ||= [processor_count, count].min
|
@@ -25,7 +26,7 @@ module Async
|
|
25
26
|
self.spawn(**options) do |instance|
|
26
27
|
container = Threaded.new
|
27
28
|
|
28
|
-
container.run(count: threads, **options, &block)
|
29
|
+
container.run(count: threads, health_check_timeout: health_check_timeout, **options, &block)
|
29
30
|
|
30
31
|
container.wait_until_ready
|
31
32
|
instance.ready!
|
@@ -34,6 +35,7 @@ module Async
|
|
34
35
|
rescue Async::Container::Terminate
|
35
36
|
# Stop it immediately:
|
36
37
|
container.stop(false)
|
38
|
+
raise
|
37
39
|
ensure
|
38
40
|
# Stop it gracefully (also code path for Interrupt):
|
39
41
|
container.stop
|
@@ -11,6 +11,9 @@ module Async
|
|
11
11
|
module Container
|
12
12
|
# A multi-thread container which uses {Thread.fork}.
|
13
13
|
class Threaded < Generic
|
14
|
+
class Kill < Exception
|
15
|
+
end
|
16
|
+
|
14
17
|
# Indicates that this is not a multi-process container.
|
15
18
|
def self.multiprocess?
|
16
19
|
false
|
@@ -178,6 +181,14 @@ module Async
|
|
178
181
|
@thread.raise(Terminate)
|
179
182
|
end
|
180
183
|
|
184
|
+
# Invoke {Thread#kill} on the child thread.
|
185
|
+
def kill!
|
186
|
+
# Killing a thread does not raise an exception in the thread, so we need to handle the status here:
|
187
|
+
@status = Status.new(:killed)
|
188
|
+
|
189
|
+
@thread.kill
|
190
|
+
end
|
191
|
+
|
181
192
|
# Raise {Restart} in the child thread.
|
182
193
|
def restart!
|
183
194
|
@thread.raise(Restart)
|
@@ -230,7 +241,7 @@ module Async
|
|
230
241
|
Console.error(self) {error}
|
231
242
|
end
|
232
243
|
|
233
|
-
@status
|
244
|
+
@status ||= Status.new(error)
|
234
245
|
self.close_write
|
235
246
|
end
|
236
247
|
end
|
data/readme.md
CHANGED
@@ -14,7 +14,28 @@ Provides containers which implement parallelism for clients and servers.
|
|
14
14
|
|
15
15
|
## Usage
|
16
16
|
|
17
|
-
Please see the [project documentation](https://socketry.github.io/async-container/).
|
17
|
+
Please see the [project documentation](https://socketry.github.io/async-container/) for more details.
|
18
|
+
|
19
|
+
- [Getting Started](https://socketry.github.io/async-container/guides/getting-started/index) - This guide explains how to use `async-container` to build basic scalable systems.
|
20
|
+
|
21
|
+
## Releases
|
22
|
+
|
23
|
+
Please see the [project releases](https://socketry.github.io/async-container/releases/index) for all releases.
|
24
|
+
|
25
|
+
### v0.21.0
|
26
|
+
|
27
|
+
- Use `SIGKILL`/`Thread#kill` when the health check fails. In some cases, `SIGTERM` may not be sufficient to terminate a process because the signal can be ignored or the process may be in an uninterruptible state.
|
28
|
+
|
29
|
+
### v0.20.1
|
30
|
+
|
31
|
+
- Fix compatibility between <code class="language-ruby">Async::Container::Hybrid</code> and the health check.
|
32
|
+
- <code class="language-ruby">Async::Container::Generic\#initialize</code> passes unused arguments through to <code class="language-ruby">Async::Container::Group</code>.
|
33
|
+
|
34
|
+
### v0.20.0
|
35
|
+
|
36
|
+
- Improve container signal handling reliability by using `Thread.handle_interrupt` except at known safe points.
|
37
|
+
- Improved logging when child process fails and container startup.
|
38
|
+
- [Add `health_check_timeout` for detecting hung processes.](https://socketry.github.io/async-container/releases/index#add-health_check_timeout-for-detecting-hung-processes.)
|
18
39
|
|
19
40
|
## Contributing
|
20
41
|
|
data/releases.md
CHANGED
@@ -1,6 +1,51 @@
|
|
1
1
|
# Releases
|
2
2
|
|
3
|
-
##
|
3
|
+
## v0.21.0
|
4
|
+
|
5
|
+
- Use `SIGKILL`/`Thread#kill` when the health check fails. In some cases, `SIGTERM` may not be sufficient to terminate a process because the signal can be ignored or the process may be in an uninterruptible state.
|
6
|
+
|
7
|
+
## v0.20.1
|
8
|
+
|
9
|
+
- Fix compatibility between {ruby Async::Container::Hybrid} and the health check.
|
10
|
+
- {ruby Async::Container::Generic\#initialize} passes unused arguments through to {ruby Async::Container::Group}.
|
11
|
+
|
12
|
+
## v0.20.0
|
4
13
|
|
5
14
|
- Improve container signal handling reliability by using `Thread.handle_interrupt` except at known safe points.
|
6
15
|
- Improved logging when child process fails and container startup.
|
16
|
+
|
17
|
+
### Add `health_check_timeout` for detecting hung processes.
|
18
|
+
|
19
|
+
In order to detect hung processes, a `health_check_timeout` can be specified when spawning children workers. If the health check does not complete within the specified timeout, the child process is killed.
|
20
|
+
|
21
|
+
``` ruby
|
22
|
+
require "async/container"
|
23
|
+
|
24
|
+
container = Async::Container.new
|
25
|
+
|
26
|
+
container.run(count: 1, restart: true, health_check_timeout: 1) do |instance|
|
27
|
+
while true
|
28
|
+
# This example will fail sometimes:
|
29
|
+
sleep(0.5 + rand)
|
30
|
+
instance.ready!
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
container.wait
|
35
|
+
```
|
36
|
+
|
37
|
+
If the health check does not complete within the specified timeout, the child process is killed:
|
38
|
+
|
39
|
+
```
|
40
|
+
3.01s warn: Async::Container::Forked [oid=0x1340] [ec=0x1348] [pid=27100] [2025-02-20 13:24:55 +1300]
|
41
|
+
| Child failed health check!
|
42
|
+
| {
|
43
|
+
| "child": {
|
44
|
+
| "name": "Unnamed",
|
45
|
+
| "pid": 27101,
|
46
|
+
| "status": null
|
47
|
+
| },
|
48
|
+
| "age": 1.0612829999881797,
|
49
|
+
| "health_check_timeout": 1
|
50
|
+
| }
|
51
|
+
```
|
data.tar.gz.sig
CHANGED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: async-container
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.21.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Samuel Williams
|
@@ -40,7 +40,7 @@ cert_chain:
|
|
40
40
|
Q2K9NVun/S785AP05vKkXZEFYxqG6EW012U4oLcFl5MySFajYXRYbuUpH6AY+HP8
|
41
41
|
voD0MPg1DssDLKwXyt1eKD/+Fq0bFWhwVM/1XiAXL7lyYUyOq24KHgQ2Csg=
|
42
42
|
-----END CERTIFICATE-----
|
43
|
-
date: 2025-02-
|
43
|
+
date: 2025-02-20 00:00:00.000000000 Z
|
44
44
|
dependencies:
|
45
45
|
- !ruby/object:Gem::Dependency
|
46
46
|
name: async
|
metadata.gz.sig
CHANGED
Binary file
|