async-container 0.27.7 → 0.28.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
2
  SHA256:
3
- metadata.gz: 4e0f77eb0f6eb3e7e8f8971af4d653e5ff2c3243ecc12f8dd06b27ae27e09d45
4
- data.tar.gz: 869aaa117d285f6f407b482b5fcd5b3bb19edcba215202d2faefe159195eed38
3
+ metadata.gz: b600b0cd62cf8c6ba832a6022ba2e2aeca1709264b696277fe11055074d36ea3
4
+ data.tar.gz: 456e1cfb343619036dfb70ac693f302b3a0dc61c0a1e3d698544c5632fabb7f8
5
5
  SHA512:
6
- metadata.gz: f1eb59fda7b292a5ca70b15ea0b70af9d6f41551d9a4818f5820dbc9b078f3008d37f646e8cbcdc74428d3c359c9ec9e731b3b0b008a74922f379b700eda32e4
7
- data.tar.gz: 301401ff8bcd736d2e41d1816110625ce038ff65b0a675d11e0ec900feb5550c73e6e754af9e5123dd12b692e4980deac1d197cbdad38e3a48213b38dd938171
6
+ metadata.gz: e72593aa02a1ad84c7223d178cf6f89bd9dbd8387539a0c77c50bcec9ac03a118a978cc3e87544b850cdeebb6a1d3925ddcee01e3866129cd8a395aae586f056
7
+ data.tar.gz: 24e370fbd183a791179cb7fbd6089e513bbdf1767af8fc955cf3e6690c937f075a2cb255915172bb46d1dc08d6995595deaf3e6d3fc39cf643a558d21e14bd7d
checksums.yaml.gz.sig CHANGED
Binary file
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2018-2025, by Samuel Williams.
4
+ # Copyright, 2018-2026, by Samuel Williams.
5
5
 
6
6
  require_relative "error"
7
7
  require_relative "best"
@@ -160,7 +160,7 @@ module Async
160
160
  def reload
161
161
  @notify&.reloading!
162
162
 
163
- Console.info(self) {"Reloading container: #{@container}..."}
163
+ Console.info(self){"Reloading container: #{@container}..."}
164
164
 
165
165
  begin
166
166
  self.setup(@container)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2017-2025, by Samuel Williams.
4
+ # Copyright, 2017-2026, by Samuel Williams.
5
5
 
6
6
  require_relative "error"
7
7
 
@@ -101,9 +101,9 @@ module Async
101
101
  self.new(**options) do |process|
102
102
  ::Process.fork do
103
103
  # We use `Thread.current.raise(...)` so that exceptions are filtered through `Thread.handle_interrupt` correctly.
104
- Signal.trap(:INT) {::Thread.current.raise(Interrupt)}
105
- Signal.trap(:TERM) {::Thread.current.raise(Terminate)}
106
- Signal.trap(:HUP) {::Thread.current.raise(Restart)}
104
+ Signal.trap(:INT){::Thread.current.raise(Interrupt)}
105
+ Signal.trap(:TERM){::Thread.current.raise(Terminate)}
106
+ Signal.trap(:HUP){::Thread.current.raise(Restart)}
107
107
 
108
108
  # This could be a configuration option:
109
109
  ::Thread.handle_interrupt(SignalException => :immediate) do
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2019-2025, by Samuel Williams.
4
+ # Copyright, 2019-2026, by Samuel Williams.
5
5
  # Copyright, 2025, by Marc-André Cournoyer.
6
6
 
7
7
  require "etc"
@@ -163,12 +163,20 @@ module Async
163
163
  child.kill!
164
164
  end
165
165
 
166
+ protected def startup_failed!(child, age_clock, startup_timeout)
167
+ Console.warn(self, "Child failed startup!", child: child, age: age_clock.total, startup_timeout: startup_timeout)
168
+
169
+ # If the child has failed the startup, we assume the worst and kill it immediately:
170
+ child.kill!
171
+ end
172
+
166
173
  # Spawn a child instance into the container.
167
174
  # @parameter name [String] The name of the child instance.
168
175
  # @parameter restart [Boolean] Whether to restart the child instance if it fails.
169
176
  # @parameter key [Symbol] A key used for reloading child instances.
170
177
  # @parameter health_check_timeout [Numeric | Nil] The maximum time a child instance can run without updating its state, before it is terminated as unhealthy.
171
- def spawn(name: nil, restart: false, key: nil, health_check_timeout: nil, &block)
178
+ # @parameter startup_timeout [Numeric | Nil] The maximum time a child instance can run without becoming ready, before it is terminated as unhealthy.
179
+ def spawn(name: nil, restart: false, key: nil, health_check_timeout: nil, startup_timeout: nil, &block)
172
180
  name ||= UNNAMED
173
181
 
174
182
  if mark?(key)
@@ -187,8 +195,8 @@ module Async
187
195
 
188
196
  Console.debug(self, "Started child.", child: child, spawn: {key: key, restart: restart, health_check_timeout: health_check_timeout}, statistics: @statistics)
189
197
 
190
- # If a health check is specified, we will monitor the child process and terminate it if it does not update its state within the specified time.
191
- if health_check_timeout
198
+ # If a health check or startup timeout is specified, we will monitor the child process and terminate it if it does not update its state within the specified time.
199
+ if health_check_timeout || startup_timeout
192
200
  age_clock = state[:age] = Clock.start
193
201
  end
194
202
 
@@ -198,12 +206,28 @@ module Async
198
206
  status = @group.wait_for(child) do |message|
199
207
  case message
200
208
  when :health_check!
201
- if health_check_timeout&.<(age_clock.total)
202
- health_check_failed!(child, age_clock, health_check_timeout)
209
+ if state[:ready]
210
+ # If a health check timeout is specified, we will monitor the child process and terminate it if it does not update its state within the specified time.
211
+ if health_check_timeout
212
+ if health_check_timeout < age_clock.total
213
+ health_check_failed!(child, age_clock, health_check_timeout)
214
+ end
215
+ end
216
+ else
217
+ # If a startup timeout is specified, we will monitor the child process and terminate it if it does not become ready within the specified time.
218
+ if startup_timeout
219
+ if startup_timeout < age_clock.total
220
+ startup_failed!(child, age_clock, startup_timeout)
221
+ end
222
+ end
203
223
  end
204
224
  else
205
225
  state.update(message)
206
- age_clock&.reset!
226
+
227
+ # Reset the age clock if the child has become ready:
228
+ if state[:ready]
229
+ age_clock&.reset!
230
+ end
207
231
  end
208
232
  end
209
233
  rescue => error
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2020-2024, by Samuel Williams.
4
+ # Copyright, 2020-2026, by Samuel Williams.
5
5
 
6
6
  require_relative "client"
7
7
 
@@ -25,7 +25,7 @@ module Async
25
25
 
26
26
  # Send a message to the console.
27
27
  def send(level: :info, **message)
28
- @logger.public_send(level, self) {message}
28
+ @logger.public_send(level, self){message}
29
29
  end
30
30
 
31
31
  # Send an error message to the console.
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2020-2025, by Samuel Williams.
4
+ # Copyright, 2020-2026, by Samuel Williams.
5
5
  # Copyright, 2020, by Juan Antonio Martín Lucas.
6
6
 
7
7
  require_relative "client"
@@ -22,7 +22,7 @@ module Async
22
22
  self.new(::IO.for_fd(descriptor.to_i))
23
23
  end
24
24
  rescue Errno::EBADF => error
25
- Console.error(self) {error}
25
+ Console.error(self){error}
26
26
 
27
27
  return nil
28
28
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  # Released under the MIT License.
4
- # Copyright, 2017-2025, by Samuel Williams.
4
+ # Copyright, 2017-2026, by Samuel Williams.
5
5
 
6
6
  require_relative "generic"
7
7
  require_relative "channel"
@@ -274,7 +274,7 @@ module Async
274
274
  # Invoked by the @waiter thread to indicate the outcome of the child thread.
275
275
  def finished(error = nil)
276
276
  if error
277
- Console.error(self) {error}
277
+ Console.error(self){error}
278
278
  end
279
279
 
280
280
  @status ||= Status.new(error)
@@ -5,6 +5,6 @@
5
5
 
6
6
  module Async
7
7
  module Container
8
- VERSION = "0.27.7"
8
+ VERSION = "0.28.0"
9
9
  end
10
10
  end
data/license.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # MIT License
2
2
 
3
- Copyright, 2017-2025, by Samuel Williams.
3
+ Copyright, 2017-2026, by Samuel Williams.
4
4
  Copyright, 2019, by Yuji Yaginuma.
5
5
  Copyright, 2020, by Olle Jonsson.
6
6
  Copyright, 2020, by Juan Antonio Martín Lucas.
data/readme.md CHANGED
@@ -26,6 +26,11 @@ Please see the [project documentation](https://socketry.github.io/async-containe
26
26
 
27
27
  Please see the [project releases](https://socketry.github.io/async-container/releases/index) for all releases.
28
28
 
29
+ ### v0.28.0
30
+
31
+ - Add `startup_timeout` parameter to `spawn` and `run` methods for detecting processes that hang during startup and never become ready.
32
+ - Health check timeout now only applies after a process becomes ready, preventing premature timeouts for slow-starting applications.
33
+
29
34
  ### v0.27.5
30
35
 
31
36
  - Make the child handling more robust in the face of exceptions.
@@ -64,10 +69,6 @@ Please see the [project releases](https://socketry.github.io/async-container/rel
64
69
 
65
70
  - Add support for health check failure metrics.
66
71
 
67
- ### v0.23.0
68
-
69
- - [Add support for `NOTIFY_LOG` for Kubernetes readiness probes.](https://socketry.github.io/async-container/releases/index#add-support-for-notify_log-for-kubernetes-readiness-probes.)
70
-
71
72
  ## Contributing
72
73
 
73
74
  We welcome contributions to this project.
data/releases.md CHANGED
@@ -1,5 +1,10 @@
1
1
  # Releases
2
2
 
3
+ ## v0.28.0
4
+
5
+ - Add `startup_timeout` parameter to `spawn` and `run` methods for detecting processes that hang during startup and never become ready.
6
+ - Health check timeout now only applies after a process becomes ready, preventing premature timeouts for slow-starting applications.
7
+
3
8
  ## v0.27.5
4
9
 
5
10
  - Make the child handling more robust in the face of exceptions.
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.27.7
4
+ version: 0.28.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
@@ -106,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
106
106
  - !ruby/object:Gem::Version
107
107
  version: '0'
108
108
  requirements: []
109
- rubygems_version: 3.7.2
109
+ rubygems_version: 4.0.3
110
110
  specification_version: 4
111
111
  summary: Abstract container-based parallelism using threads and processes where appropriate.
112
112
  test_files: []
metadata.gz.sig CHANGED
Binary file