yamine 0.6.0 → 0.6.1
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 +18 -1
- data/README.md +3 -1
- data/lib/yamine/cli/boot.rb +1 -1
- data/lib/yamine/readiness.rb +15 -12
- data/lib/yamine/version.rb +1 -1
- 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: 8066e974d3f0f4849a0b6173c3a8d6acf5f576149afffc9bec3981623ce7faee
|
|
4
|
+
data.tar.gz: ded221f8f3f2c6430383c4666d69bc2d397ee924e9f1409d04b0096c750674d7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 28e06d646cb8f5d7e5a9a16a40f1e4a091ed544f39a5dcd6753d7bd740d11cfa331c213c23c417543670d3c2ab09485edd50717abd5eef3533034d0f1e58d883
|
|
7
|
+
data.tar.gz: 6b1180bffb37227e10bff3d0072faae0d790d684b2e74f462e64b3db3ded819c3a96736b27e8b30098c0ad2abcf50ed95f292babc02409e242d7887eac8d6e03
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [0.6.
|
|
3
|
+
## [0.6.1] — 2026-09-10
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Healthchecks no longer speak TLS to the backend.** `--wait` probed
|
|
8
|
+
`127.0.0.1:$PORT` — the app's own listener — with the *proxy's* `tls`
|
|
9
|
+
flag, so any app declaring `healthcheck: { path: }` could never boot
|
|
10
|
+
under the default TLS-on proxy: the probe began an SSL handshake
|
|
11
|
+
against a plaintext Puma, which logged `Invalid HTTP format, parsing
|
|
12
|
+
fails. Are you trying to open an SSL connection to a non-SSL Puma?`
|
|
13
|
+
once per attempt until the process phase timed out and the whole boot
|
|
14
|
+
was torn down. TLS is the proxy's job; the proxy dials backends with a
|
|
15
|
+
bare `TCPSocket`, so `Readiness.probe`/`probe_http`/`wait_healthy`/
|
|
16
|
+
`wait_all` drop the `tls:` keyword entirely (an `https://` banner URL
|
|
17
|
+
never implied the backend speaks TLS). Reported from anyworkers, whose
|
|
18
|
+
web process healthchecks `/up`.
|
|
19
|
+
|
|
20
|
+
## [0.6.0] — 2026-09-09
|
|
4
21
|
|
|
5
22
|
`yamine start --wait` + boot readiness protocol. The remaining gap from
|
|
6
23
|
“one-storey building” onwards: boot had no definitive answer — agents
|
data/README.md
CHANGED
|
@@ -95,7 +95,9 @@ Optional top-level `db: false` opts out of per-worktree databases
|
|
|
95
95
|
(exotic setups — manual `establish_connection`, shared staging DB, …);
|
|
96
96
|
`db.schema_load` overrides the schema-load command. Per-process
|
|
97
97
|
`healthcheck: { path: /up, timeout: 30 }` declares what `--wait` polls
|
|
98
|
-
(TCP accept when absent).
|
|
98
|
+
(TCP accept when absent). The poll is plain HTTP against the app's own
|
|
99
|
+
`127.0.0.1:$PORT` listener — TLS is terminated by the proxy, so the path
|
|
100
|
+
is reached over http regardless of the `https://` URL in the banner.)
|
|
99
101
|
|
|
100
102
|
`yamine init` creates the file (migrating an existing Procfile);
|
|
101
103
|
Rails apps need no extra gem — yamine injects `RAILS_DEVELOPMENT_HOSTS`
|
data/lib/yamine/cli/boot.rb
CHANGED
|
@@ -183,7 +183,7 @@ module Yamine
|
|
|
183
183
|
database_url: db_url, force: opts[:force])
|
|
184
184
|
}
|
|
185
185
|
end
|
|
186
|
-
wait_result = Readiness.wait_all(apps,
|
|
186
|
+
wait_result = Readiness.wait_all(apps, out: nil)
|
|
187
187
|
failed = wait_result.select { |r| r[:status] != "ok" }
|
|
188
188
|
|
|
189
189
|
if failed.empty?
|
data/lib/yamine/readiness.rb
CHANGED
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
require "json"
|
|
4
4
|
require "net/http"
|
|
5
5
|
require "open3"
|
|
6
|
-
require "openssl"
|
|
7
6
|
require "socket"
|
|
8
7
|
require "timeout"
|
|
9
8
|
require "uri"
|
|
@@ -89,11 +88,17 @@ module Yamine
|
|
|
89
88
|
# Poll an HTTP route until healthy or timeout. Healthy = healthcheck
|
|
90
89
|
# path returns 2xx-3xx, or (no healthcheck) TCP accept on the port.
|
|
91
90
|
# Returns [healthy, detail].
|
|
92
|
-
|
|
91
|
+
#
|
|
92
|
+
# Probes are plaintext by construction: the target is the app's OWN
|
|
93
|
+
# listener (127.0.0.1:$PORT). TLS is terminated by the proxy, which
|
|
94
|
+
# dials backends with a bare TCPSocket (Proxy#connect_backend), so a
|
|
95
|
+
# `tls:` flag taken from the proxy must never reach here — an
|
|
96
|
+
# https:// URL in the banner does not mean the backend speaks TLS.
|
|
97
|
+
def wait_healthy(hostname, port:, path: nil, timeout: 30)
|
|
93
98
|
deadline = Process.clock_gettime(Process::CLOCK_MONOTONIC) + timeout
|
|
94
99
|
last_error = "not yet attempted"
|
|
95
100
|
until Process.clock_gettime(Process::CLOCK_MONOTONIC) > deadline
|
|
96
|
-
ok, detail = probe(hostname, port,
|
|
101
|
+
ok, detail = probe(hostname, port, path: path)
|
|
97
102
|
return [true, nil] if ok
|
|
98
103
|
|
|
99
104
|
last_error = detail
|
|
@@ -102,9 +107,9 @@ module Yamine
|
|
|
102
107
|
[false, last_error]
|
|
103
108
|
end
|
|
104
109
|
|
|
105
|
-
def probe(hostname, port,
|
|
110
|
+
def probe(hostname, port, path: nil)
|
|
106
111
|
if path
|
|
107
|
-
probe_http(hostname, port,
|
|
112
|
+
probe_http(hostname, port, path: path)
|
|
108
113
|
else
|
|
109
114
|
probe_tcp(port)
|
|
110
115
|
end
|
|
@@ -117,10 +122,8 @@ module Yamine
|
|
|
117
122
|
[false, e.message.lines.first&.strip]
|
|
118
123
|
end
|
|
119
124
|
|
|
120
|
-
def probe_http(hostname, port,
|
|
125
|
+
def probe_http(hostname, port, path:)
|
|
121
126
|
http = Net::HTTP.new("127.0.0.1", port)
|
|
122
|
-
http.use_ssl = tls
|
|
123
|
-
http.verify_mode = OpenSSL::SSL::VERIFY_NONE if tls
|
|
124
127
|
http.open_timeout = 3
|
|
125
128
|
http.read_timeout = 5
|
|
126
129
|
res = http.get(path, { "Host" => hostname })
|
|
@@ -140,17 +143,17 @@ module Yamine
|
|
|
140
143
|
# or "timeout" (never answered within its healthcheck timeout).
|
|
141
144
|
# Dead-pid short-circuit: a reaped backend fails immediately
|
|
142
145
|
# instead of burning its full timeout on connection-refused.
|
|
143
|
-
def wait_all(apps,
|
|
146
|
+
def wait_all(apps, out: nil)
|
|
144
147
|
threads = apps.map do |name, slot|
|
|
145
148
|
Thread.new do
|
|
146
|
-
Thread.current[:result] = wait_one(name, slot,
|
|
149
|
+
Thread.current[:result] = wait_one(name, slot, out: out)
|
|
147
150
|
end
|
|
148
151
|
end
|
|
149
152
|
threads.each(&:join)
|
|
150
153
|
threads.map { |t| t[:result] }
|
|
151
154
|
end
|
|
152
155
|
|
|
153
|
-
def wait_one(name, slot,
|
|
156
|
+
def wait_one(name, slot, out:)
|
|
154
157
|
item = slot[:item]
|
|
155
158
|
app = slot[:app]
|
|
156
159
|
hc = item[:entry]["healthcheck"] || {}
|
|
@@ -165,7 +168,7 @@ module Yamine
|
|
|
165
168
|
return fail_result(name, started, ms,
|
|
166
169
|
"process exited before becoming healthy — see log/yamine-#{name}.log", out)
|
|
167
170
|
end
|
|
168
|
-
ok, detail = probe(item[:hostname], item[:port],
|
|
171
|
+
ok, detail = probe(item[:hostname], item[:port], path: path)
|
|
169
172
|
if ok
|
|
170
173
|
ms = elapsed_ms(started)
|
|
171
174
|
return ok_result(name, started, ms, path, out)
|
data/lib/yamine/version.rb
CHANGED