hyperion-rb 2.16.0 → 2.16.2
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
- data/CHANGELOG.md +94 -0
- data/bin/hyperion +26 -0
- data/lib/hyperion/version.rb +1 -1
- data/lib/hyperion.rb +8 -0
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 85ee19dc8b680c83c849964653ce228ebb94cd65a430f43ed13653ba36f06190
|
|
4
|
+
data.tar.gz: 4a02a074020c814d3036099d9ff996dd7098e704b03c4484e8a86e8320b60c65
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b614b52474052c37ba35d8d5bb633227b4b05112c617e71893e3a8c28d6d10f4ca406478a024238a841bc9aed5cc86df1ebcca5b9c8b9d21ab315ddfc8dcf996
|
|
7
|
+
data.tar.gz: aef147c323a1ca872d6e8467e15ff50a58fe8ae81a926b7fb87362736d5072824b785bdf682341fa4da858c7887aada193199a91f320ad3b88cafe55ee267ae5
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,99 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 2.16.2 — 2026-05-04
|
|
4
|
+
|
|
5
|
+
### 2.16.2-A — macOS Obj-C fork-safety: re-exec, not just ENV write
|
|
6
|
+
|
|
7
|
+
**Why.** 2.16.1's `ENV['OBJC_DISABLE_INITIALIZE_FORK_SAFETY'] ||= 'YES'`
|
|
8
|
+
in `bin/hyperion` and `lib/hyperion.rb` did not actually stop the
|
|
9
|
+
crash. The Obj-C runtime caches that env var's value at **dyld init**
|
|
10
|
+
— before any Ruby code runs. By the time `bin/hyperion`'s first
|
|
11
|
+
line executes, the runtime has already decided whether the post-fork
|
|
12
|
+
check fires. Setting the var from Ruby is observable to `ENV.fetch`
|
|
13
|
+
and inherited by `Process.fork` children via the kernel's env
|
|
14
|
+
duplication, but the Obj-C runtime's own check ignores the late
|
|
15
|
+
write. Workers continued to crash on `+[NSCharacterSet initialize]`
|
|
16
|
+
in fork children after a 2.16.1 master spawned them.
|
|
17
|
+
|
|
18
|
+
**What 2.16.2-A ships.** `bin/hyperion` now **re-execs itself** with
|
|
19
|
+
the env var set when launched on `darwin` without it:
|
|
20
|
+
|
|
21
|
+
```ruby
|
|
22
|
+
if RUBY_PLATFORM.include?('darwin') && ENV['OBJC_DISABLE_INITIALIZE_FORK_SAFETY'].nil?
|
|
23
|
+
ENV['OBJC_DISABLE_INITIALIZE_FORK_SAFETY'] = 'YES'
|
|
24
|
+
exec(RbConfig.ruby, __FILE__, *ARGV)
|
|
25
|
+
end
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
`exec` replaces the current process image; dyld of the new image
|
|
29
|
+
reads `OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES` from the inherited
|
|
30
|
+
environment and the runtime's fork-safety check honours it for the
|
|
31
|
+
master and every worker forked from it. Operators who have already
|
|
32
|
+
set the var explicitly (shell export, Foreman's `.env` load,
|
|
33
|
+
Dockerfile `ENV`) skip the re-exec — the `nil?` guard preserves
|
|
34
|
+
deliberate `=NO` settings if anyone has a reason for those. The
|
|
35
|
+
operator-facing shell call (`bundle exec hyperion …`) sees a single
|
|
36
|
+
child and a single exit status; the re-exec is invisible.
|
|
37
|
+
|
|
38
|
+
`lib/hyperion.rb`'s 2.16.1 `ENV ||=` line is removed: it was
|
|
39
|
+
misleading (couldn't work for the current process anyway).
|
|
40
|
+
Programmatic users embedding Hyperion via `require 'hyperion'`
|
|
41
|
+
without `bin/hyperion` on macOS must set the env var themselves in
|
|
42
|
+
the shell or wrapper before launching Ruby — same as before 2.16.1.
|
|
43
|
+
|
|
44
|
+
**Verification.**
|
|
45
|
+
|
|
46
|
+
- `bin/check` green.
|
|
47
|
+
- Fresh `bundle exec hyperion -C config/hyperion.rb config.ru` against
|
|
48
|
+
the same Rails 8.1 app that reproduced the 2.16.1 crash loop:
|
|
49
|
+
master + workers boot cleanly; no `NSCharacterSet`-init crash; no
|
|
50
|
+
worker respawn churn; sequential curls return 200 OK.
|
|
51
|
+
|
|
52
|
+
## 2.16.1 — 2026-05-04
|
|
53
|
+
|
|
54
|
+
### 2.16.1-A — macOS Obj-C fork-safety guard
|
|
55
|
+
|
|
56
|
+
**Why.** Operators landing on 2.16.0's `preload false` mode on macOS
|
|
57
|
+
were still hitting a second fork+macOS crash, distinct from the
|
|
58
|
+
Network.framework deadlock that 2.16.0 addressed. The Obj-C runtime's
|
|
59
|
+
post-fork sanity check trips when a worker touches a Foundation
|
|
60
|
+
class that was mid-initialization in the master at fork time:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
objc[…]: +[NSCharacterSet initialize] may have been in progress in
|
|
64
|
+
another thread when fork() was called. We cannot safely call it or
|
|
65
|
+
ignore it in the fork() child process. Crashing instead.
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
`NSCharacterSet` (and friends) load transitively through OpenSSL,
|
|
69
|
+
the system resolver, and several other native gems. The result with
|
|
70
|
+
many workers (`WEB_CONCURRENCY=0` on a multi-core box): every fresh
|
|
71
|
+
worker crashes on first Foundation touch, master respawns, ad
|
|
72
|
+
infinitum until graceful_timeout fires.
|
|
73
|
+
|
|
74
|
+
The escape hatch on macOS is the documented env var
|
|
75
|
+
`OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES`, but it MUST be in the
|
|
76
|
+
process environment before any Foundation class loads — setting it
|
|
77
|
+
from `config/hyperion.rb` (parsed after gems load) is too late.
|
|
78
|
+
|
|
79
|
+
**What 2.16.1-A ships.** `bin/hyperion` and `lib/hyperion.rb` set
|
|
80
|
+
`ENV['OBJC_DISABLE_INITIALIZE_FORK_SAFETY'] ||= 'YES'` on `darwin`
|
|
81
|
+
unconditionally — before any `require` brings in Foundation-touching
|
|
82
|
+
code. `||=` honours operators who've set the var explicitly. No-op
|
|
83
|
+
on Linux/BSD; affects only macOS.
|
|
84
|
+
|
|
85
|
+
This is a defense-in-depth change, complementary to `preload false`:
|
|
86
|
+
`preload false` keeps Network.framework's resolver state out of the
|
|
87
|
+
master; this guard keeps Obj-C runtime fork-checks from crashing
|
|
88
|
+
the workers when something else (OpenSSL etc.) still touches
|
|
89
|
+
Foundation. Together they make the macOS dev experience match Linux.
|
|
90
|
+
|
|
91
|
+
**Verification.**
|
|
92
|
+
|
|
93
|
+
- `bin/check` green.
|
|
94
|
+
- Hand-reproduced the `NSCharacterSet` worker-crash loop on macOS;
|
|
95
|
+
no longer reproduces in 2.16.1.
|
|
96
|
+
|
|
3
97
|
## 2.16.0 — 2026-05-04
|
|
4
98
|
|
|
5
99
|
### 2.16-A — `preload false`: macOS fork+resolver escape hatch
|
data/bin/hyperion
CHANGED
|
@@ -1,6 +1,32 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
# frozen_string_literal: true
|
|
3
3
|
|
|
4
|
+
# 2.16.2 — macOS fork-safety. The Obj-C runtime caches the value of
|
|
5
|
+
# `OBJC_DISABLE_INITIALIZE_FORK_SAFETY` at dyld init time, BEFORE any
|
|
6
|
+
# Ruby code runs. Setting `ENV[...]` from Ruby is observable to
|
|
7
|
+
# `Process.fork`'s child via inheritance, but the runtime's own
|
|
8
|
+
# fork-safety check has already locked in its decision based on the
|
|
9
|
+
# env it saw at process launch. So a Ruby-side `ENV[...] = 'YES'`
|
|
10
|
+
# does not stop the post-fork crash:
|
|
11
|
+
# "+[NSCharacterSet initialize] may have been in progress in another
|
|
12
|
+
# thread when fork() was called. We cannot safely call it or ignore
|
|
13
|
+
# it in the fork() child process. Crashing instead."
|
|
14
|
+
#
|
|
15
|
+
# The reliable way to get the var into dyld's view is to re-exec the
|
|
16
|
+
# Ruby process with it set. Once the new process starts, dyld picks
|
|
17
|
+
# up the env var and the runtime's fork-safety check honours it.
|
|
18
|
+
# `exec` replaces the current image so the wrapper shell call (e.g.
|
|
19
|
+
# `bundle exec hyperion …`) sees a single child process and a single
|
|
20
|
+
# exit status — no double accounting from the operator's side.
|
|
21
|
+
#
|
|
22
|
+
# Operators who've already set the var explicitly (in their shell, in
|
|
23
|
+
# Foreman's .env load, in a Dockerfile ENV) skip this re-exec — we
|
|
24
|
+
# only re-exec when the var is unset.
|
|
25
|
+
if RUBY_PLATFORM.include?('darwin') && ENV['OBJC_DISABLE_INITIALIZE_FORK_SAFETY'].nil?
|
|
26
|
+
ENV['OBJC_DISABLE_INITIALIZE_FORK_SAFETY'] = 'YES'
|
|
27
|
+
exec(RbConfig.ruby, __FILE__, *ARGV)
|
|
28
|
+
end
|
|
29
|
+
|
|
4
30
|
$LOAD_PATH.unshift(File.expand_path('../lib', __dir__))
|
|
5
31
|
require 'hyperion/cli'
|
|
6
32
|
Hyperion::CLI.run(ARGV)
|
data/lib/hyperion/version.rb
CHANGED
data/lib/hyperion.rb
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
+
# Note: macOS Obj-C fork-safety is handled in `bin/hyperion` (re-exec
|
|
4
|
+
# with `OBJC_DISABLE_INITIALIZE_FORK_SAFETY=YES`). It cannot be handled
|
|
5
|
+
# from this file: setting `ENV[...]` from Ruby runs after dyld has
|
|
6
|
+
# already cached its decision, so by the time `require 'hyperion'`
|
|
7
|
+
# fires, the runtime's fork-safety check has locked in. Operators
|
|
8
|
+
# embedding Hyperion programmatically (no `bin/hyperion`) on macOS
|
|
9
|
+
# must set the env var in their shell or wrapper before exec.
|
|
10
|
+
|
|
3
11
|
require_relative 'hyperion/version'
|
|
4
12
|
require_relative 'hyperion/logger'
|
|
5
13
|
require_relative 'hyperion/metrics'
|