standard_health 0.7.0 → 0.8.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
- data/CHANGELOG.md +57 -0
- data/README.md +27 -7
- data/lib/standard_health/aggregate_report.rb +5 -3
- data/lib/standard_health/aggregator.rb +41 -5
- data/lib/standard_health/check.rb +10 -0
- data/lib/standard_health/configuration.rb +28 -6
- data/lib/standard_health/env_spec.rb +19 -0
- data/lib/standard_health/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 3cf58624de0179c4903a4159e227baa82079b2a78e97679122a429b186783918
|
|
4
|
+
data.tar.gz: 33963ed5e02ec9794a3133e4fbf3444cb443bc821045ec8bde6ecfb4b575f0a0
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 846b8334841aeb56c429f8a767f76c1e3e22e849da7f5de261370895cb3d7e735e2ee1fe3a72508637474f0338b34c05848bdda32e359bee783857ca3dd85e79
|
|
7
|
+
data.tar.gz: b6fefd789b745ec5a20819c46b89d610b226283b09024db1426ba5aacebee6838941f9d9c423b152bc55df2ab09bd341906cc5b15de6e2a7c0c59a5891d291f6
|
data/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,63 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.8.0] - 2026-10-22
|
|
11
|
+
|
|
12
|
+
### Changed
|
|
13
|
+
|
|
14
|
+
- **Re-registering a check replaces it.** `register_check` and
|
|
15
|
+
`register_aggregate_check` replace an existing registration of the same name
|
|
16
|
+
in place (last writer wins) instead of appending a second one, matching
|
|
17
|
+
`register_diagnostics_assertion`. A `configure` block that runs twice, e.g.
|
|
18
|
+
from `to_prepare` on reload, no longer runs every check twice.
|
|
19
|
+
- **`env_spec` aliases are checked at boot.** Assigning `c.env_spec = …` calls
|
|
20
|
+
the new `EnvSpec#validate!`, which raises `EnvSpec::UnknownModeAlias` naming
|
|
21
|
+
every `in:` alias that has no `mode_alias`. Before, an undeclared alias raised
|
|
22
|
+
only on the first audit, which was a production `/diagnostics/env` request
|
|
23
|
+
(it 500'd one app's doctor tier once). All five estate apps declare every
|
|
24
|
+
alias they use, so none of them is affected.
|
|
25
|
+
|
|
26
|
+
## [0.7.1] - 2026-09-25
|
|
27
|
+
|
|
28
|
+
### Fixed
|
|
29
|
+
|
|
30
|
+
- **Skipped checks no longer degrade the aggregate.** A check that returns
|
|
31
|
+
`status: :skipped` itself means "not applicable here" (the feature it
|
|
32
|
+
covers is not configured or not enforced). It is now **neutral** in the
|
|
33
|
+
roll-up on every tier (`/ready` and the aggregate `/health`): it neither
|
|
34
|
+
degrades nor fails the status. Before, it counted like a failing
|
|
35
|
+
non-critical check, which held sidekick-web's `/health` at `degraded`
|
|
36
|
+
permanently while attestation was unconfigured. The row still renders in
|
|
37
|
+
`checks[]` with `"status": "skipped"`, and `check.completed` still fires,
|
|
38
|
+
so it stays visible. It is no longer listed in the `failed[]` / `failures`
|
|
39
|
+
of `ready.evaluated` / `aggregate.evaluated`, so the Logger and Sentry
|
|
40
|
+
notifiers don't name it as failing when something else degrades.
|
|
41
|
+
- **A critical check that reports `:skipped` is neutral too**, on purpose.
|
|
42
|
+
"Not applicable" says nothing about whether the instance can serve, so it
|
|
43
|
+
must not pull it out of rotation. Return `:fail` for a state that should
|
|
44
|
+
page.
|
|
45
|
+
- Real failures roll up exactly as before: a failing critical check is
|
|
46
|
+
`unavailable` (503), a failing non-critical one `degraded`, including
|
|
47
|
+
alongside a skipped check.
|
|
48
|
+
- **Budget skips are unchanged.** A check the `total_check_budget` never
|
|
49
|
+
reached was not performed, which is not the same as healthy. It still
|
|
50
|
+
floors the roll-up at `degraded` (never `unavailable`) and is still listed
|
|
51
|
+
in `failed[]`. Its row now carries `budget_exhausted: true`, which is how
|
|
52
|
+
the gem tells the two kinds of skip apart.
|
|
53
|
+
- `/diagnostics/env` is unaffected. Its roll-up is over env-audit rows and
|
|
54
|
+
assertions (`:ok` / `:warn` / `:error`), which have no skipped state.
|
|
55
|
+
|
|
56
|
+
### Changed
|
|
57
|
+
|
|
58
|
+
- **Requires Rails 8.1** (`rails >= 8.1`, was `>= 8.0`). Every consumer app
|
|
59
|
+
runs 8.1; 8.0 was never exercised in CI. Ruby 3.4 remains supported.
|
|
60
|
+
|
|
61
|
+
### Upgrade notes (0.7.0 → 0.7.1)
|
|
62
|
+
|
|
63
|
+
- **No required host change.** An app whose aggregate was `degraded` only
|
|
64
|
+
because of a self-reported skip now reports `ok`. Monitors or smoke tests
|
|
65
|
+
that expect `degraded` in that state need updating (sidekick-web).
|
|
66
|
+
|
|
10
67
|
## [0.7.0] - 2026-09-24
|
|
11
68
|
|
|
12
69
|
The Phase 4 release. 0.6 deprecated nothing, so nothing is removed. It adds
|
data/README.md
CHANGED
|
@@ -106,7 +106,7 @@ end
|
|
|
106
106
|
| Status | HTTP | When |
|
|
107
107
|
|---|---|---|
|
|
108
108
|
| `unavailable` | 503 | a critical check failed, or a `:critical` circuit is red |
|
|
109
|
-
| `degraded` | 200 | a non-critical check failed
|
|
109
|
+
| `degraded` | 200 | a non-critical check failed, a check was skipped by the total budget, or the circuit roll-up is `:degraded` |
|
|
110
110
|
| `ok` | 200 | otherwise |
|
|
111
111
|
|
|
112
112
|
**The aggregate tier re-runs your readiness checks by default.** With
|
|
@@ -362,7 +362,7 @@ end
|
|
|
362
362
|
|
|
363
363
|
- `nil` (omitted) — entry always applies
|
|
364
364
|
- `Array<String>` — literal mode list (existing behaviour)
|
|
365
|
-
- `Symbol` — resolved against `mode_alias
|
|
365
|
+
- `Symbol` — resolved against `mode_alias`. Assigning the spec (`c.env_spec = …`) checks every alias, so an undeclared Symbol raises `StandardHealth::EnvSpec::UnknownModeAlias` at boot, naming each unknown alias, rather than on the first `/diagnostics/env` request.
|
|
366
366
|
|
|
367
367
|
### `description:` and `consumed_by:`
|
|
368
368
|
|
|
@@ -522,6 +522,10 @@ end
|
|
|
522
522
|
|
|
523
523
|
`with_timing` captures `latency_ms` on success and converts any `StandardError` into `{ status: :fail, error: <message> }`.
|
|
524
524
|
|
|
525
|
+
Registering a name that is already registered replaces that check in place (the
|
|
526
|
+
same for `register_aggregate_check`), so a `configure` block that runs twice,
|
|
527
|
+
e.g. from `to_prepare` on reload, doesn't run any check twice.
|
|
528
|
+
|
|
525
529
|
**Per-registration options (0.6.0).** Keywords other than `critical:` and
|
|
526
530
|
`timeout:` are forwarded to the check's constructor, and validated against its
|
|
527
531
|
signature at registration — a typo fails at boot, not on every probe:
|
|
@@ -806,9 +810,25 @@ go in `extra:`.
|
|
|
806
810
|
|
|
807
811
|
The orchestrator should pull the instance out of rotation only on 503; degraded means "still serving, page someone."
|
|
808
812
|
|
|
809
|
-
`skipped` also exists,
|
|
810
|
-
|
|
811
|
-
`
|
|
813
|
+
`skipped` also exists, in two flavours that roll up differently:
|
|
814
|
+
|
|
815
|
+
- **A check that returns `status: :skipped` itself** — "not applicable here"
|
|
816
|
+
(the feature it covers isn't configured or enforced). This is **neutral**
|
|
817
|
+
(since 0.7.1): it neither degrades nor fails the roll-up, whether the check
|
|
818
|
+
is critical or not, and it is left out of the evaluation events' `failed[]`.
|
|
819
|
+
It still renders in `checks[]` with `"status": "skipped"` and still emits
|
|
820
|
+
`check.completed`, so it stays visible. A critical check is neutral too on
|
|
821
|
+
purpose: "not applicable" says nothing about whether the instance can serve,
|
|
822
|
+
so it must not pull it out of rotation — and it must not mark it healthy
|
|
823
|
+
*because of* that check either; it simply doesn't count. If the state should
|
|
824
|
+
page, return `:fail`.
|
|
825
|
+
- **A check the total budget never reached** (see Timeouts) — rendered with
|
|
826
|
+
`"budget_exhausted": true`. That check was not performed, which is not the
|
|
827
|
+
same as healthy, so it floors the roll-up at `degraded` and **never**
|
|
828
|
+
produces `unavailable`, even for a critical check.
|
|
829
|
+
|
|
830
|
+
A real failure still rolls up exactly as before alongside any skip: a failing
|
|
831
|
+
critical check is `unavailable`, a failing non-critical one `degraded`.
|
|
812
832
|
|
|
813
833
|
## Failure detail is redacted
|
|
814
834
|
|
|
@@ -934,8 +954,8 @@ slow-but-fine starts reporting `:fail`, and for a critical check that pulls
|
|
|
934
954
|
the instance out of rotation. Pick values from observed `latency_ms` rather
|
|
935
955
|
than intuition; that is what the `check.completed` events are for.
|
|
936
956
|
|
|
937
|
-
Checks the total budget never reaches report `:skipped
|
|
938
|
-
A skip alone floors the roll-up at `degraded` — otherwise a slow *non-critical*
|
|
957
|
+
Checks the total budget never reaches report `:skipped` (with
|
|
958
|
+
`budget_exhausted: true`), never silently `:ok`. A budget skip alone floors the roll-up at `degraded` — otherwise a slow *non-critical*
|
|
939
959
|
check could exhaust the budget, leave the database check unrun, and pull a
|
|
940
960
|
healthy instance out of rotation.
|
|
941
961
|
|
|
@@ -18,8 +18,10 @@ module StandardHealth
|
|
|
18
18
|
#
|
|
19
19
|
# Status roll-up, in the estate's readiness vocabulary:
|
|
20
20
|
# :unavailable (503) — a critical check failed, or a :critical circuit is RED
|
|
21
|
-
# :degraded (200) — a non-critical check failed
|
|
22
|
-
# circuit roll-up is
|
|
21
|
+
# :degraded (200) — a non-critical check failed, a check was skipped
|
|
22
|
+
# by the total budget, or the circuit roll-up is
|
|
23
|
+
# :degraded. A check that reports :skipped itself
|
|
24
|
+
# (not applicable) is neutral — see Aggregator.
|
|
23
25
|
# :ok (200) — otherwise
|
|
24
26
|
#
|
|
25
27
|
# StandardCircuit's own word for its worst state is `:critical`; it is
|
|
@@ -92,7 +94,7 @@ module StandardHealth
|
|
|
92
94
|
# notifier logs this one (so redacted messages still reach logs); Sentry
|
|
93
95
|
# and Metrics ignore it.
|
|
94
96
|
def emit_evaluation(report, rows, circuits, started)
|
|
95
|
-
failing = rows
|
|
97
|
+
failing = Aggregator.failing_rows(rows)
|
|
96
98
|
payload = {
|
|
97
99
|
status: report[:status],
|
|
98
100
|
duration_ms: ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - started) * 1000).round,
|
|
@@ -14,11 +14,23 @@ module StandardHealth
|
|
|
14
14
|
# Runs all registered checks and rolls them up into a single status.
|
|
15
15
|
#
|
|
16
16
|
# Status semantics:
|
|
17
|
-
# :ok — every check returned :ok
|
|
17
|
+
# :ok — every check returned :ok, or reported :skipped itself
|
|
18
18
|
# :degraded — at least one non-critical check failed, OR a check was
|
|
19
19
|
# skipped because the total budget ran out
|
|
20
20
|
# :unavailable — at least one critical check failed
|
|
21
21
|
#
|
|
22
|
+
# Two kinds of :skipped row exist, and they roll up differently (0.7.1):
|
|
23
|
+
#
|
|
24
|
+
# * A check that RETURNS `status: :skipped` is saying "not applicable
|
|
25
|
+
# here" (the feature it covers is not configured or not enforced). That
|
|
26
|
+
# is NEUTRAL — it neither degrades nor fails the tier, whatever its
|
|
27
|
+
# `critical:` flag, and it is not listed in an evaluation event's
|
|
28
|
+
# `failed[]`. The row still renders with status "skipped", and
|
|
29
|
+
# `check.completed` still fires, so it stays visible.
|
|
30
|
+
# * A check the total budget never REACHED (`budget_exhausted: true` on
|
|
31
|
+
# the row) was not performed at all, and an unperformed check is not a
|
|
32
|
+
# healthy one. It floors the tier at :degraded — never :unavailable.
|
|
33
|
+
#
|
|
22
34
|
# The aggregator never raises. Each check is invoked through `safe_run`
|
|
23
35
|
# which catches `StandardError` so a buggy custom check cannot take down
|
|
24
36
|
# /ready. Instrumentation is held to the same bar — every emit is wrapped
|
|
@@ -55,7 +67,7 @@ module StandardHealth
|
|
|
55
67
|
duration_ms = ((monotonic - started) * 1000).round
|
|
56
68
|
status = overall_status(check_rows)
|
|
57
69
|
|
|
58
|
-
failing = check_rows
|
|
70
|
+
failing = failing_rows(check_rows)
|
|
59
71
|
|
|
60
72
|
return { status: status, checks: check_rows, generated_at: now.iso8601 } unless tier == :ready
|
|
61
73
|
|
|
@@ -81,6 +93,21 @@ module StandardHealth
|
|
|
81
93
|
}
|
|
82
94
|
end
|
|
83
95
|
|
|
96
|
+
# The rows an evaluation event reports as failing: everything that is not
|
|
97
|
+
# :ok, except a check that reported :skipped itself (not applicable, so
|
|
98
|
+
# not a failure). A budget skip IS listed — it is the only place a skip
|
|
99
|
+
# shows up in the transition-gated event. @api private (also used by
|
|
100
|
+
# AggregateReport).
|
|
101
|
+
def self.failing_rows(rows)
|
|
102
|
+
rows.reject { |r| r[:status] == :ok || neutral_skip?(r) }
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# A row the check itself reported as :skipped — "not applicable here".
|
|
106
|
+
# Neutral in the roll-up. A budget skip is not neutral. @api private
|
|
107
|
+
def self.neutral_skip?(row)
|
|
108
|
+
row[:status] == :skipped && !row[:budget_exhausted]
|
|
109
|
+
end
|
|
110
|
+
|
|
84
111
|
# Per-failure detail for an evaluation event. Public (but @api private) so
|
|
85
112
|
# the aggregate tier's evaluation event carries the same shape.
|
|
86
113
|
# @api private
|
|
@@ -177,12 +204,15 @@ module StandardHealth
|
|
|
177
204
|
private_class_method :budget_exhausted?
|
|
178
205
|
|
|
179
206
|
# A check the total budget never reached. `:skipped`, never silently
|
|
180
|
-
# `:ok` — an unperformed check is not a healthy one.
|
|
207
|
+
# `:ok` — an unperformed check is not a healthy one. `budget_exhausted`
|
|
208
|
+
# is what separates it from a check that reported :skipped itself (which
|
|
209
|
+
# is neutral); see overall_status.
|
|
181
210
|
def self.skipped_row(reg, budget)
|
|
182
211
|
{
|
|
183
212
|
name: reg.name,
|
|
184
213
|
critical: reg.critical,
|
|
185
214
|
status: :skipped,
|
|
215
|
+
budget_exhausted: true,
|
|
186
216
|
error: "skipped — total check budget of #{budget}s exhausted"
|
|
187
217
|
}
|
|
188
218
|
end
|
|
@@ -191,10 +221,16 @@ module StandardHealth
|
|
|
191
221
|
def self.overall_status(rows)
|
|
192
222
|
return :ok if rows.empty?
|
|
193
223
|
|
|
194
|
-
|
|
224
|
+
# A check that reported :skipped itself is not applicable here, so it is
|
|
225
|
+
# NEUTRAL: it must not degrade the tier (sidekick-web's non-critical
|
|
226
|
+
# attestation check held /health at "degraded" forever while attestation
|
|
227
|
+
# was simply not configured), and a critical one must not fail it
|
|
228
|
+
# either — "not applicable" says nothing about whether the app can
|
|
229
|
+
# serve. It stays in checks[] as "skipped" for visibility.
|
|
230
|
+
failures = failing_rows(rows)
|
|
195
231
|
return :ok if failures.empty?
|
|
196
232
|
|
|
197
|
-
# A SKIP MUST NEVER PRODUCE :unavailable, even for a critical check.
|
|
233
|
+
# A BUDGET SKIP MUST NEVER PRODUCE :unavailable, even for a critical check.
|
|
198
234
|
# Otherwise a slow *non-critical* check could exhaust the budget, leave
|
|
199
235
|
# the database check unrun, and pull a perfectly healthy instance out of
|
|
200
236
|
# rotation — a self-inflicted outage caused by the safety mechanism.
|
|
@@ -11,6 +11,16 @@ module StandardHealth
|
|
|
11
11
|
#
|
|
12
12
|
# { status: :fail, error: "connection refused" }
|
|
13
13
|
#
|
|
14
|
+
# or, when the check does not apply to this deployment (the feature it
|
|
15
|
+
# covers is not configured or not enforced):
|
|
16
|
+
#
|
|
17
|
+
# { status: :skipped }
|
|
18
|
+
#
|
|
19
|
+
# A self-reported :skipped is NEUTRAL in the roll-up (0.7.1): it never
|
|
20
|
+
# degrades or fails the tier, even for a critical check, but it still
|
|
21
|
+
# renders in `checks[]` as "skipped". Return :fail, not :skipped, for
|
|
22
|
+
# anything that should page.
|
|
23
|
+
#
|
|
14
24
|
# The `with_timing` helper wraps a block, captures latency, and converts
|
|
15
25
|
# any unhandled `StandardError` into a `:fail` row so subclasses don't
|
|
16
26
|
# have to repeat the pattern.
|
|
@@ -86,7 +86,16 @@ module StandardHealth
|
|
|
86
86
|
# An optional `StandardHealth::EnvSpec` instance describing required and
|
|
87
87
|
# recommended environment variables for the host app. Audited via the
|
|
88
88
|
# /diagnostics/env endpoint.
|
|
89
|
-
|
|
89
|
+
attr_reader :env_spec
|
|
90
|
+
|
|
91
|
+
# Validates the spec as it is assigned (`EnvSpec#validate!`), so an
|
|
92
|
+
# `in:` alias with no `mode_alias` fails the initializer at boot rather
|
|
93
|
+
# than raising on the first audit, which is a /diagnostics/env request
|
|
94
|
+
# in production.
|
|
95
|
+
def env_spec=(spec)
|
|
96
|
+
spec.validate! if spec.respond_to?(:validate!)
|
|
97
|
+
@env_spec = spec
|
|
98
|
+
end
|
|
90
99
|
|
|
91
100
|
# --- Instrumentation -----------------------------------------------
|
|
92
101
|
#
|
|
@@ -192,7 +201,9 @@ module StandardHealth
|
|
|
192
201
|
attr_accessor :default_check_timeout
|
|
193
202
|
|
|
194
203
|
# Budget across all checks, evaluated BEFORE each check starts. Checks not
|
|
195
|
-
# reached are reported :skipped
|
|
204
|
+
# reached are reported :skipped with `budget_exhausted: true` (unlike a
|
|
205
|
+
# check that reports :skipped itself, which is neutral), and such a skip
|
|
206
|
+
# alone floors the roll-up at
|
|
196
207
|
# :degraded — never :unavailable. Otherwise a slow NON-critical check could
|
|
197
208
|
# exhaust the budget, leave a critical check unrun, and pull a healthy app
|
|
198
209
|
# out of rotation. nil = no budget.
|
|
@@ -268,13 +279,16 @@ module StandardHealth
|
|
|
268
279
|
# Validated against the constructor's signature HERE, so a typo fails
|
|
269
280
|
# at boot instead of turning into an ArgumentError on every probe (which
|
|
270
281
|
# the aggregator would dutifully report as a failing check forever).
|
|
282
|
+
#
|
|
283
|
+
# Re-registering a name replaces that registration in place (last writer
|
|
284
|
+
# wins), so `configure` can safely re-run, e.g. from `to_prepare` on
|
|
285
|
+
# reload, without running the check twice.
|
|
271
286
|
def register_check(name, klass, critical: false, timeout: nil, **options)
|
|
272
287
|
validate_check_options!(klass, options)
|
|
273
288
|
registration = Registration.new(
|
|
274
289
|
name: name.to_sym, klass: klass, critical: critical, timeout: timeout, options: options
|
|
275
290
|
)
|
|
276
|
-
@checks
|
|
277
|
-
registration
|
|
291
|
+
upsert_registration(@checks, registration)
|
|
278
292
|
end
|
|
279
293
|
|
|
280
294
|
# The check set every consumer app registers by hand. Each entry: default
|
|
@@ -360,13 +374,14 @@ module StandardHealth
|
|
|
360
374
|
#
|
|
361
375
|
# c.register_aggregate_check :solid_cable, StandardHealth::Checks::SolidCable
|
|
362
376
|
# c.register_aggregate_check :attestation_roots, "AttestationRootsCheck"
|
|
377
|
+
#
|
|
378
|
+
# Re-registering a name replaces it in place, as for #register_check.
|
|
363
379
|
def register_aggregate_check(name, klass, critical: false, timeout: nil, **options)
|
|
364
380
|
validate_check_options!(klass, options)
|
|
365
381
|
registration = Registration.new(
|
|
366
382
|
name: name.to_sym, klass: klass, critical: critical, timeout: timeout, options: options
|
|
367
383
|
)
|
|
368
|
-
@aggregate_checks
|
|
369
|
-
registration
|
|
384
|
+
upsert_registration(@aggregate_checks, registration)
|
|
370
385
|
end
|
|
371
386
|
|
|
372
387
|
DiagnosticsAssertion = Struct.new(:name, :callable)
|
|
@@ -438,6 +453,13 @@ module StandardHealth
|
|
|
438
453
|
|
|
439
454
|
private
|
|
440
455
|
|
|
456
|
+
# Replaces the registration with the same name in place, or appends.
|
|
457
|
+
def upsert_registration(registry, registration)
|
|
458
|
+
index = registry.index { |existing| existing.name == registration.name }
|
|
459
|
+
index ? registry[index] = registration : registry << registration
|
|
460
|
+
registration
|
|
461
|
+
end
|
|
462
|
+
|
|
441
463
|
# Rejects option keys the check's constructor cannot accept. Only
|
|
442
464
|
# inspects the signature — never instantiates — so a check with side
|
|
443
465
|
# effects in `initialize` is not run at boot. A constructor taking
|
|
@@ -115,6 +115,21 @@ module StandardHealth
|
|
|
115
115
|
@mode_aliases[name.to_sym] = Array(modes).map(&:to_s)
|
|
116
116
|
end
|
|
117
117
|
|
|
118
|
+
# Resolves every `in:` alias now. `Configuration#env_spec=` calls this,
|
|
119
|
+
# so an undeclared or misspelt alias fails at boot instead of raising on
|
|
120
|
+
# the first audit (a /diagnostics/env request, or an EnvSpecAudit row).
|
|
121
|
+
#
|
|
122
|
+
# @raise [UnknownModeAlias] naming every unknown alias
|
|
123
|
+
# @return [self]
|
|
124
|
+
def validate!
|
|
125
|
+
unknown = entries.filter_map { |entry| entry.modes if alias_unknown?(entry.modes) }.uniq
|
|
126
|
+
return self if unknown.empty?
|
|
127
|
+
|
|
128
|
+
raise UnknownModeAlias,
|
|
129
|
+
"Unknown mode alias#{"es" if unknown.size > 1}: #{unknown.map(&:inspect).join(", ")} " \
|
|
130
|
+
"(declare it with mode_alias)"
|
|
131
|
+
end
|
|
132
|
+
|
|
118
133
|
# Group subsequent declarations under a label. Pure metadata —
|
|
119
134
|
# propagated to audit rows as `group:` and otherwise inert. Nested
|
|
120
135
|
# `group` blocks are supported; the innermost label is the one that
|
|
@@ -253,6 +268,10 @@ module StandardHealth
|
|
|
253
268
|
modes.include?(mode_str)
|
|
254
269
|
end
|
|
255
270
|
|
|
271
|
+
def alias_unknown?(modes)
|
|
272
|
+
modes.is_a?(Symbol) && !@mode_aliases.key?(modes)
|
|
273
|
+
end
|
|
274
|
+
|
|
256
275
|
def resolve_modes(modes)
|
|
257
276
|
return nil if modes.nil?
|
|
258
277
|
if modes.is_a?(Symbol)
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: standard_health
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.8.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Jaryl Sim
|
|
@@ -15,14 +15,14 @@ dependencies:
|
|
|
15
15
|
requirements:
|
|
16
16
|
- - ">="
|
|
17
17
|
- !ruby/object:Gem::Version
|
|
18
|
-
version: '8.
|
|
18
|
+
version: '8.1'
|
|
19
19
|
type: :runtime
|
|
20
20
|
prerelease: false
|
|
21
21
|
version_requirements: !ruby/object:Gem::Requirement
|
|
22
22
|
requirements:
|
|
23
23
|
- - ">="
|
|
24
24
|
- !ruby/object:Gem::Version
|
|
25
|
-
version: '8.
|
|
25
|
+
version: '8.1'
|
|
26
26
|
description: StandardHealth is a mountable Rails engine providing /alive, /ready,
|
|
27
27
|
and /diagnostics/env endpoints, with a configuration block for registering custom
|
|
28
28
|
checks and a DSL for declaring required and recommended environment variables.
|
|
@@ -88,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
89
|
version: '0'
|
|
90
90
|
requirements: []
|
|
91
|
-
rubygems_version: 4.0.
|
|
91
|
+
rubygems_version: 4.0.10
|
|
92
92
|
specification_version: 4
|
|
93
93
|
summary: A drop-in health check and environment-spec engine for Rails 8 host apps.
|
|
94
94
|
test_files: []
|