async-service 0.16.0 → 0.17.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/best-practices.md +23 -0
- data/context/service-architecture.md +31 -2
- data/lib/async/service/generic_service.rb +1 -1
- data/lib/async/service/managed_environment.rb +9 -1
- data/lib/async/service/managed_service.rb +22 -8
- data/lib/async/service/version.rb +1 -1
- data/license.md +1 -1
- data/readme.md +5 -4
- data/releases.md +5 -0
- data.tar.gz.sig +0 -0
- metadata +4 -4
- 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: 6e9258424ee834d70b309984ba6f2d0c89f87ed9b2a16ec38fb298dfafb33fcd
|
|
4
|
+
data.tar.gz: e91b2129702c7c8ad7f3203063d3dd526b8e6e91d322bb84388afe873cf638f0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: edc78ce3ff189ef951f19b206d02bbef4f2c121b10e24f074b6a7eab702c6ffeceb5e47c7c29d330363c7389c721b371c4584f33b9145cde42b798ec08e47237
|
|
7
|
+
data.tar.gz: be8a666be488d9d428339edea966834c0a7d5e935bcf330b8669f914b58661ed11deff0782b4202327951b108063992e5ac6f4fb9427beca5d6c1daaf09f440a
|
checksums.yaml.gz.sig
CHANGED
|
Binary file
|
data/context/best-practices.md
CHANGED
|
@@ -208,6 +208,7 @@ class WebService < Async::Service::ManagedService
|
|
|
208
208
|
# Managed::Service automatically handles:
|
|
209
209
|
# - Container setup with proper options.
|
|
210
210
|
# - Health checking with process title updates.
|
|
211
|
+
# - Status messages during startup to prevent premature timeouts.
|
|
211
212
|
# - Preloading of scripts before startup.
|
|
212
213
|
|
|
213
214
|
private def format_title(evaluator, server)
|
|
@@ -222,6 +223,28 @@ class WebService < Async::Service::ManagedService
|
|
|
222
223
|
end
|
|
223
224
|
```
|
|
224
225
|
|
|
226
|
+
### Configure Timeouts for Slow-Starting Services
|
|
227
|
+
|
|
228
|
+
If your service takes a long time to start up (e.g., loading large datasets, connecting to external services), configure appropriate timeouts:
|
|
229
|
+
|
|
230
|
+
```ruby
|
|
231
|
+
module WebEnvironment
|
|
232
|
+
include Async::Service::ManagedEnvironment
|
|
233
|
+
|
|
234
|
+
# Allow 2 minutes for startup.
|
|
235
|
+
def startup_timeout
|
|
236
|
+
120
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
# Require health checks every 30 seconds.
|
|
240
|
+
def health_check_timeout
|
|
241
|
+
30
|
|
242
|
+
end
|
|
243
|
+
end
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
The `startup_timeout` ensures processes that hang during startup are detected, while `health_check_timeout` monitors processes after they've become ready. `ManagedService` automatically sends `status!` messages during startup to keep the health check clock resetting until the service is ready.
|
|
247
|
+
|
|
225
248
|
### Implement Meaningful Process Titles
|
|
226
249
|
|
|
227
250
|
Use the `format_title` method to provide dynamic process information:
|
|
@@ -262,7 +262,9 @@ end
|
|
|
262
262
|
|
|
263
263
|
### Health Checking
|
|
264
264
|
|
|
265
|
-
For services using `Async::Service::ManagedService`, health checking is handled automatically.
|
|
265
|
+
For services using `Async::Service::ManagedService`, health checking is handled automatically. The service sends `status!` messages during startup to prevent premature health check timeouts, then transitions to sending `ready!` messages once the service is actually ready.
|
|
266
|
+
|
|
267
|
+
For services extending `GenericService`, you can set up health checking manually:
|
|
266
268
|
|
|
267
269
|
```ruby
|
|
268
270
|
def setup(container)
|
|
@@ -270,12 +272,15 @@ def setup(container)
|
|
|
270
272
|
health_check_timeout = container_options[:health_check_timeout]
|
|
271
273
|
|
|
272
274
|
container.run(**container_options) do |instance|
|
|
275
|
+
# Send status updates during startup:
|
|
276
|
+
instance.status!("Preparing...")
|
|
273
277
|
# Prepare your service.
|
|
274
278
|
|
|
275
279
|
Async do
|
|
276
280
|
# Start your service.
|
|
281
|
+
instance.status!("Starting...")
|
|
277
282
|
|
|
278
|
-
#
|
|
283
|
+
# Once ready, set up health checking:
|
|
279
284
|
health_checker(instance, health_check_timeout) do
|
|
280
285
|
instance.name = "#{self.name}: #{current_status}"
|
|
281
286
|
end
|
|
@@ -284,6 +289,30 @@ def setup(container)
|
|
|
284
289
|
end
|
|
285
290
|
```
|
|
286
291
|
|
|
292
|
+
#### Startup Timeout vs Health Check Timeout
|
|
293
|
+
|
|
294
|
+
The container supports two separate timeout mechanisms:
|
|
295
|
+
|
|
296
|
+
- **`startup_timeout`**: Maximum time a process can take to become ready (call `ready!`) before being terminated. This detects processes that hang during startup and never become ready.
|
|
297
|
+
- **`health_check_timeout`**: Maximum time between health check messages after the process has become ready. This detects processes that stop responding after they've started.
|
|
298
|
+
|
|
299
|
+
Both timeouts use a single clock that starts when the process starts. The clock resets when the process becomes ready, transitioning from startup timeout monitoring to health check timeout monitoring.
|
|
300
|
+
|
|
301
|
+
You can configure these timeouts via `container_options`:
|
|
302
|
+
|
|
303
|
+
```ruby
|
|
304
|
+
module WebEnvironment
|
|
305
|
+
include Async::Service::ManagedEnvironment
|
|
306
|
+
|
|
307
|
+
def container_options
|
|
308
|
+
super.merge(
|
|
309
|
+
startup_timeout: 60, # Allow up to 60 seconds for startup.
|
|
310
|
+
health_check_timeout: 30 # Require health checks every 30 seconds after ready.
|
|
311
|
+
)
|
|
312
|
+
end
|
|
313
|
+
end
|
|
314
|
+
```
|
|
315
|
+
|
|
287
316
|
Note: `Async::Service::ManagedService` automatically handles health checking, container options, and process title formatting, so you typically don't need to set this up manually.
|
|
288
317
|
|
|
289
318
|
## How They Work Together
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2025, by Samuel Williams.
|
|
4
|
+
# Copyright, 2025-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
module Async
|
|
7
7
|
module Service
|
|
@@ -16,6 +16,13 @@ module Async
|
|
|
16
16
|
nil
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
+
# The timeout duration for the startup. Set to `nil` to disable the startup timeout.
|
|
20
|
+
#
|
|
21
|
+
# @returns [Numeric | nil] The startup timeout in seconds.
|
|
22
|
+
def startup_timeout
|
|
23
|
+
nil
|
|
24
|
+
end
|
|
25
|
+
|
|
19
26
|
# The timeout duration for the health check. Set to `nil` to disable the health check.
|
|
20
27
|
#
|
|
21
28
|
# @returns [Numeric | nil] The health check timeout in seconds.
|
|
@@ -30,6 +37,7 @@ module Async
|
|
|
30
37
|
{
|
|
31
38
|
restart: true,
|
|
32
39
|
count: self.count,
|
|
40
|
+
startup_timeout: self.startup_timeout,
|
|
33
41
|
health_check_timeout: self.health_check_timeout,
|
|
34
42
|
}.compact
|
|
35
43
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
# Released under the MIT License.
|
|
4
|
-
# Copyright, 2025, by Samuel Williams.
|
|
4
|
+
# Copyright, 2025-2026, by Samuel Williams.
|
|
5
5
|
|
|
6
6
|
require_relative "generic_service"
|
|
7
7
|
require_relative "health_checker"
|
|
@@ -46,18 +46,32 @@ module Async
|
|
|
46
46
|
rescue StandardError, LoadError => error
|
|
47
47
|
Console.warn(self, "Service preload failed!", error)
|
|
48
48
|
end
|
|
49
|
-
|
|
49
|
+
|
|
50
50
|
# Start the service, including preloading resources.
|
|
51
51
|
def start
|
|
52
52
|
preload!
|
|
53
53
|
|
|
54
54
|
super
|
|
55
55
|
end
|
|
56
|
-
|
|
56
|
+
|
|
57
|
+
# Called after the service has been prepared but before it starts running.
|
|
58
|
+
#
|
|
59
|
+
# Override this method to emit metrics, logs, or perform other actions when the service preparation is complete.
|
|
60
|
+
#
|
|
61
|
+
# @parameter instance [Async::Container::Instance] The container instance.
|
|
62
|
+
# @parameter start_time [Async::Clock] The monotonic start time from {Async::Clock.start}.
|
|
57
63
|
def emit_prepared(instance, start_time)
|
|
64
|
+
# Override in subclasses as needed.
|
|
58
65
|
end
|
|
59
|
-
|
|
66
|
+
|
|
67
|
+
# Called after the service has started running.
|
|
68
|
+
#
|
|
69
|
+
# Override this method to emit metrics, logs, or perform other actions when the service begins running.
|
|
70
|
+
#
|
|
71
|
+
# @parameter instance [Async::Container::Instance] The container instance.
|
|
72
|
+
# @parameter start_time [Async::Clock] The monotonic start time from {Async::Clock.start}.
|
|
60
73
|
def emit_running(instance, start_time)
|
|
74
|
+
# Override in subclasses as needed.
|
|
61
75
|
end
|
|
62
76
|
|
|
63
77
|
# Set up the container with health checking and process title formatting.
|
|
@@ -70,16 +84,16 @@ module Async
|
|
|
70
84
|
|
|
71
85
|
container.run(**container_options) do |instance|
|
|
72
86
|
start_time = Async::Clock.start
|
|
73
|
-
|
|
87
|
+
|
|
74
88
|
Async do
|
|
75
89
|
evaluator = self.environment.evaluator
|
|
76
90
|
|
|
91
|
+
instance.status!("Preparing...")
|
|
77
92
|
evaluator.prepare!(instance)
|
|
78
|
-
|
|
79
93
|
emit_prepared(instance, start_time)
|
|
80
|
-
|
|
81
|
-
server = run(instance, evaluator)
|
|
82
94
|
|
|
95
|
+
instance.status!("Running...")
|
|
96
|
+
server = run(instance, evaluator)
|
|
83
97
|
emit_running(instance, start_time)
|
|
84
98
|
|
|
85
99
|
health_checker(instance) do
|
data/license.md
CHANGED
data/readme.md
CHANGED
|
@@ -29,6 +29,11 @@ Please see the [project documentation](https://socketry.github.io/async-service/
|
|
|
29
29
|
|
|
30
30
|
Please see the [project releases](https://socketry.github.io/async-service/releases/index) for all releases.
|
|
31
31
|
|
|
32
|
+
### v0.17.0
|
|
33
|
+
|
|
34
|
+
- `ManagedService` now sends `status!` messages during startup to prevent premature health check timeouts for slow-starting services.
|
|
35
|
+
- Support for `startup_timeout` option via `container_options` to detect processes that hang during startup and never become ready.
|
|
36
|
+
|
|
32
37
|
### v0.16.0
|
|
33
38
|
|
|
34
39
|
- Renamed `Async::Service::Generic` -\> `Async::Service::GenericService`, added compatibilty alias.
|
|
@@ -72,10 +77,6 @@ Please see the [project releases](https://socketry.github.io/async-service/relea
|
|
|
72
77
|
- Add `Environment::Evaluator#as_json` for JSON serialization support.
|
|
73
78
|
- Allow constructing a configuration with existing environments.
|
|
74
79
|
|
|
75
|
-
### v0.9.0
|
|
76
|
-
|
|
77
|
-
- Allow providing a list of modules to include in environments.
|
|
78
|
-
|
|
79
80
|
## Contributing
|
|
80
81
|
|
|
81
82
|
We welcome contributions to this project.
|
data/releases.md
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
# Releases
|
|
2
2
|
|
|
3
|
+
## v0.17.0
|
|
4
|
+
|
|
5
|
+
- `ManagedService` now sends `status!` messages during startup to prevent premature health check timeouts for slow-starting services.
|
|
6
|
+
- Support for `startup_timeout` option via `container_options` to detect processes that hang during startup and never become ready.
|
|
7
|
+
|
|
3
8
|
## v0.16.0
|
|
4
9
|
|
|
5
10
|
- Renamed `Async::Service::Generic` -\> `Async::Service::GenericService`, added compatibilty alias.
|
data.tar.gz.sig
CHANGED
|
Binary file
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: async-service
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.17.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Samuel Williams
|
|
@@ -58,14 +58,14 @@ dependencies:
|
|
|
58
58
|
requirements:
|
|
59
59
|
- - "~>"
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version: '0.
|
|
61
|
+
version: '0.28'
|
|
62
62
|
type: :runtime
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
66
|
- - "~>"
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version: '0.
|
|
68
|
+
version: '0.28'
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: string-format
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -126,7 +126,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
126
126
|
- !ruby/object:Gem::Version
|
|
127
127
|
version: '0'
|
|
128
128
|
requirements: []
|
|
129
|
-
rubygems_version:
|
|
129
|
+
rubygems_version: 4.0.3
|
|
130
130
|
specification_version: 4
|
|
131
131
|
summary: A service layer for Async.
|
|
132
132
|
test_files: []
|
metadata.gz.sig
CHANGED
|
Binary file
|