async-signals 0.2.0 → 0.3.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/context/getting-started.md +10 -0
- data/guides/getting-started/readme.md +10 -0
- data/lib/async/signals/context.rb +25 -0
- data/lib/async/signals/controller.rb +11 -8
- data/lib/async/signals/handlers.rb +1 -0
- data/lib/async/signals/version.rb +1 -1
- data/lib/async/signals.rb +1 -0
- data/readme.md +4 -0
- data/releases.md +4 -0
- data.tar.gz.sig +0 -0
- metadata +2 -1
- 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: 892b6d001f6a23c4190ecb71cd652d63aea1a7331932a68f3b0f057f8cdf762e
|
|
4
|
+
data.tar.gz: fd8a403c5abfe0a943ce0ec4c684ea5b6ba390f6c76006ed6772d0e12532d903
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: cc9458635104d6f45cdcde03512d1e5e3dcaf09f21fa345bad891f678e2a5f6d80177c5dd7f84bc11e0a2d2b4b0c4582bba5cea9871bae6aafefaf320b05b124
|
|
7
|
+
data.tar.gz: f885189f0ae71ef8c529bf17ae23c9ad080c22641716fd30e4c54c11bc0659786c030536b6448472ac9fb66667ed0736e180e0e746bfe3972cd9ad26589a8022
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/context/getting-started.md
CHANGED
|
@@ -55,6 +55,14 @@ end
|
|
|
55
55
|
|
|
56
56
|
When the block exits, the handler set is removed and any previous signal trap is restored.
|
|
57
57
|
|
|
58
|
+
Handlers may also accept the context that installed the handler set. This is useful when a signal should interrupt the component that installed the handlers, regardless of which thread dispatches the signal trap.
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
handlers.trap(:INT) do |signal, context|
|
|
62
|
+
context.raise(Interrupt)
|
|
63
|
+
end
|
|
64
|
+
```
|
|
65
|
+
|
|
58
66
|
### Multiple Consumers
|
|
59
67
|
|
|
60
68
|
Multiple parts of an application can listen for the same signal. This is useful when a service, supervisor, and application component each need to observe shutdown signals without taking ownership of the process-wide trap.
|
|
@@ -169,6 +177,8 @@ Avoid calling `Signal.trap` for the same signals while `async-signals` handlers
|
|
|
169
177
|
|
|
170
178
|
Keep signal handlers thread safe. Ruby implementations may dispatch signal traps from an implementation-specific thread, so handlers should avoid mutating shared state directly. Prefer doing minimal work in the handler and forwarding the event to a thread-safe mechanism such as `Thread::Queue`.
|
|
171
179
|
|
|
180
|
+
Handler exceptions propagate from dispatch. If multiple handler sets observe the same signal and one handler raises, later handlers may not run.
|
|
181
|
+
|
|
172
182
|
## Troubleshooting
|
|
173
183
|
|
|
174
184
|
If a handler is not invoked, check that the handler set is installed at the time the signal is delivered. Handler sets are only active inside the `Async::Signals.install` block, or until the returned registration is closed.
|
|
@@ -55,6 +55,14 @@ end
|
|
|
55
55
|
|
|
56
56
|
When the block exits, the handler set is removed and any previous signal trap is restored.
|
|
57
57
|
|
|
58
|
+
Handlers may also accept the context that installed the handler set. This is useful when a signal should interrupt the component that installed the handlers, regardless of which thread dispatches the signal trap.
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
handlers.trap(:INT) do |signal, context|
|
|
62
|
+
context.raise(Interrupt)
|
|
63
|
+
end
|
|
64
|
+
```
|
|
65
|
+
|
|
58
66
|
### Multiple Consumers
|
|
59
67
|
|
|
60
68
|
Multiple parts of an application can listen for the same signal. This is useful when a service, supervisor, and application component each need to observe shutdown signals without taking ownership of the process-wide trap.
|
|
@@ -169,6 +177,8 @@ Avoid calling `Signal.trap` for the same signals while `async-signals` handlers
|
|
|
169
177
|
|
|
170
178
|
Keep signal handlers thread safe. Ruby implementations may dispatch signal traps from an implementation-specific thread, so handlers should avoid mutating shared state directly. Prefer doing minimal work in the handler and forwarding the event to a thread-safe mechanism such as `Thread::Queue`.
|
|
171
179
|
|
|
180
|
+
Handler exceptions propagate from dispatch. If multiple handler sets observe the same signal and one handler raises, later handlers may not run.
|
|
181
|
+
|
|
172
182
|
## Troubleshooting
|
|
173
183
|
|
|
174
184
|
If a handler is not invoked, check that the handler set is installed at the time the signal is delivered. Handler sets are only active inside the `Async::Signals.install` block, or until the returned registration is closed.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Released under the MIT License.
|
|
4
|
+
# Copyright, 2026, by Samuel Williams.
|
|
5
|
+
|
|
6
|
+
module Async
|
|
7
|
+
module Signals
|
|
8
|
+
# Represents the execution context that installed a signal handler set.
|
|
9
|
+
class Context
|
|
10
|
+
# Initialize the context.
|
|
11
|
+
def initialize
|
|
12
|
+
# Capture both primitives so the public interface can evolve without
|
|
13
|
+
# changing the handler arguments.
|
|
14
|
+
@thread = ::Thread.current
|
|
15
|
+
@fiber = ::Fiber.current
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Raise an exception in the thread that installed the handler set.
|
|
19
|
+
# @parameter arguments [Array] The arguments to pass to {Thread#raise}.
|
|
20
|
+
def raise(*arguments)
|
|
21
|
+
@thread.raise(*arguments)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
require "thread"
|
|
7
7
|
|
|
8
8
|
require_relative "handlers"
|
|
9
|
+
require_relative "context"
|
|
9
10
|
|
|
10
11
|
module Async
|
|
11
12
|
module Signals
|
|
@@ -74,9 +75,11 @@ module Async
|
|
|
74
75
|
end
|
|
75
76
|
|
|
76
77
|
# The active callable signal handlers.
|
|
77
|
-
# @returns [Array(Proc)] The active handlers.
|
|
78
|
+
# @returns [Array(Array(Proc, Context))] The active handlers and the contexts that installed them.
|
|
78
79
|
def callbacks
|
|
79
|
-
@handlers.
|
|
80
|
+
@handlers.map do |registration, handler|
|
|
81
|
+
[handler, registration.context]
|
|
82
|
+
end.freeze
|
|
80
83
|
end
|
|
81
84
|
end
|
|
82
85
|
|
|
@@ -88,8 +91,12 @@ module Async
|
|
|
88
91
|
def initialize(controller, handlers)
|
|
89
92
|
@controller = controller
|
|
90
93
|
@handlers = handlers
|
|
94
|
+
@context = Context.new
|
|
91
95
|
end
|
|
92
96
|
|
|
97
|
+
# @attribute [Context] The context that installed this registration.
|
|
98
|
+
attr :context
|
|
99
|
+
|
|
93
100
|
# Remove this registration from the controller.
|
|
94
101
|
def close
|
|
95
102
|
if handlers = @handlers
|
|
@@ -138,12 +145,8 @@ module Async
|
|
|
138
145
|
def dispatch(signal)
|
|
139
146
|
number = ::Signal.list.fetch(signal)
|
|
140
147
|
|
|
141
|
-
@dispatch[signal]&.each do |handler|
|
|
142
|
-
|
|
143
|
-
handler.call(number)
|
|
144
|
-
rescue Exception => error
|
|
145
|
-
warn "Async::Signals handler failed: #{error.class}: #{error.message}"
|
|
146
|
-
end
|
|
148
|
+
@dispatch[signal]&.each do |handler, context|
|
|
149
|
+
handler.call(number, context)
|
|
147
150
|
end
|
|
148
151
|
end
|
|
149
152
|
|
|
@@ -16,6 +16,7 @@ module Async
|
|
|
16
16
|
|
|
17
17
|
# Trap a signal while these handlers are installed.
|
|
18
18
|
# @parameter signal [Symbol | String | Integer] The signal to trap.
|
|
19
|
+
# @yields {|signal, context| ...} The signal number and the context that installed the handler set.
|
|
19
20
|
def trap(signal, &block)
|
|
20
21
|
@signals[normalize(signal)] = block
|
|
21
22
|
end
|
data/lib/async/signals.rb
CHANGED
data/readme.md
CHANGED
|
@@ -24,6 +24,10 @@ Please see the [project documentation](https://socketry.github.io/async-signals/
|
|
|
24
24
|
|
|
25
25
|
Please see the [project releases](https://socketry.github.io/async-signals/releases/index) for all releases.
|
|
26
26
|
|
|
27
|
+
### v0.3.0
|
|
28
|
+
|
|
29
|
+
- Pass the installing context as the second signal handler argument and allow handler exceptions to propagate.
|
|
30
|
+
|
|
27
31
|
### v0.2.0
|
|
28
32
|
|
|
29
33
|
- Add `Async::Signals.default` and `Async::Signals::Ignore` for selecting process signal handling based on the current thread.
|
data/releases.md
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
# Releases
|
|
2
2
|
|
|
3
|
+
## v0.3.0
|
|
4
|
+
|
|
5
|
+
- Pass the installing context as the second signal handler argument and allow handler exceptions to propagate.
|
|
6
|
+
|
|
3
7
|
## v0.2.0
|
|
4
8
|
|
|
5
9
|
- Add `Async::Signals.default` and `Async::Signals::Ignore` for selecting process signal handling based on the current thread.
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: async-signals
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Samuel Williams
|
|
@@ -47,6 +47,7 @@ files:
|
|
|
47
47
|
- guides/getting-started/readme.md
|
|
48
48
|
- guides/links.yaml
|
|
49
49
|
- lib/async/signals.rb
|
|
50
|
+
- lib/async/signals/context.rb
|
|
50
51
|
- lib/async/signals/controller.rb
|
|
51
52
|
- lib/async/signals/handlers.rb
|
|
52
53
|
- lib/async/signals/ignore.rb
|
metadata.gz.sig
CHANGED
|
Binary file
|