Repository navigation
Health check api #5952
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
hazel-bohon
wants to merge
8
commits into
master
Choose a base branch
from
health-check-api
base: master
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+1,521
−51
Draft
Health check api #5952
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
91735c5
first pass
hazel-bohon 8ecd9bb
Separate internal checks from the custom checks
hazel-bohon e1ceaa9
Pin Azure CLI on Windows CI
Copilot 7e21069
Remvoe license checking information from the API.
hazel-bohon 2fc4229
Update docs/README.md
hazel-bohon c80678f
Refactor PlatformHealthView to enforce required properties and update…
hazel-bohon dacd308
Move `.record` call into `try` block.
hazel-bohon 5ca6de3
Wait for current index during range unarchive
Copilot File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,71 @@ | ||
| # Platform Health API | ||
|
|
||
| ServiceControl exposes `GET /api/platform-health` for the ServiceControl-owned data on ServicePulse's Platform Health page. The API root advertises its URL in `platform_health`. The response uses the existing snake_case JSON convention and omits unknown nullable fields. | ||
|
|
||
| The public motivation is [ServiceControl #5860](https://github.com/Particular/ServiceControl/issues/5860). The consumer data requirements were checked against [ServicePulse's Platform Health store](https://github.com/Particular/ServicePulse/blob/e2688743d23fe5a4b835d4cff128ad12da87d34c/src/Frontend/src/stores/PlatformHealthStore.ts) and [platform model](https://github.com/Particular/ServicePulse/blob/e2688743d23fe5a4b835d4cff128ad12da87d34c/src/Frontend/src/resources/PlatformModel.ts). | ||
|
|
||
| ## Response | ||
|
|
||
| The existing `status`, `severity`, and `alerts` fields remain, with an additive `instances` section. | ||
|
|
||
| ### Instances | ||
|
|
||
| `instances` contains the primary followed by every distinct configured remote, even when no check has reported or a remote cannot be reached. Remotes are ordered by stable ID, not by the order that their requests complete. | ||
|
|
||
| | Field | Meaning and source | | ||
| | --- | --- | | ||
| | `id` | Existing URL-derived ServiceControl instance ID; independent of display name and row position | | ||
| | `name` | Configured instance name; a never-observed remote falls back to its URI hostname | | ||
| | `kind`, `role` | `error` / `primary-error`, `error` / `remote-error`, `audit` / `remote-audit`, or `unknown` / `remote-unknown` | | ||
| | `api_url` | Request-facing primary URL, honoring forwarded scheme, host and prefix; configured remote URL with its virtual directory preserved | | ||
| | `version` | Installed local version or remote `X-Particular-Version`; absent when unknown, never replaced with the primary's version | | ||
| | `host_id` | Actual reporting host identity from the local NServiceBus host or remote configuration; absent on older remotes | | ||
| | `health` | `healthy` for reachable instances without an associated failure, `degraded` for reachable instances with failures, `unavailable` for failed probes | | ||
| | `observed_at` | UTC timestamp for the current refresh, from the injected clock | | ||
| | `metadata_observed_at` | Timestamp of the last successful metadata observation; differs from `observed_at` during an outage | | ||
| | `health_signals_status` | `reported`, `unreported`, `disabled`, or `ambiguous`; not a guarantee that every possible check has run | | ||
| | `last_reported_at` | Latest associated check timestamp, including successful reports; distinct from HTTP observation time | | ||
| | `issues` | Associated failed internal checks, with the same fields as root alerts | | ||
| | `transport_type`, `error_queue`, `error_log_queue`, `forward_error_messages` | Available transport configuration; a known `false` forwarding setting is preserved | | ||
| | `audit_queue`, `audit_log_queue`, `forward_audit_messages` | Available audit transport configuration | | ||
| | `error_retention_period`, `audit_retention_period` | Available retention durations in the existing TimeSpan JSON format, for example `14.00:00:00` | | ||
|
|
||
| Primary and audit `/api/configuration` (also `/api/instance-info`) include `instance_type` and `host.host_id`. Primary configuration additionally reports `health_checks_enabled`. Older remotes without `instance_type` are identified only when their retention configuration establishes the type. A never-observed, unreachable remote is explicitly unknown, not assumed to be an audit instance. | ||
|
|
||
| Remote probes use the registered named HTTP clients and their query timeout. Non-success status codes, empty or malformed configuration, and connection failures do not produce healthy rows. An outage retains the last successful metadata in memory, clearly dated by `metadata_observed_at`. Other rows still return. Caller cancellation propagates instead of returning partial success. No recursive platform-health requests are made to other primaries. | ||
|
|
||
| ### Issues and summary | ||
|
|
||
| Each failed check has `id`, `check_id`, `category`, `message`, `reported_at`, `instance_name`, `host`, and `host_id`. An associated issue also has `instance_id`. | ||
|
|
||
| Association uses case-insensitive instance name plus reporting host ID. A legacy remote without a host ID can use a name match only when there is one matching inventory row and one reporting host with that name. Ambiguous or unmatched reports remain in root `alerts` without `instance_id`; they are never assigned to several rows. Consumers should retain a place to display those unassigned alerts. | ||
|
|
||
| The legacy summary describes captured checks, not the whole browser-visible platform: `status` is `unknown` before any internal report, `healthy` when none are failing, and `unhealthy` when at least one is failing. Its corresponding `severity` values are `unknown`, `none`, and `error`. ServicePulse should use per-instance health for page severity and combine it with its independently observed monitoring state. The legacy summary does not account for monitoring, browser connectivity, or available upgrades. | ||
|
|
||
| Check state is process-local. Reports older than a check's latest `reported_at` are ignored; a newer successful report clears that failure. Reports do not expire: different checks have different schedules, including one-shot checks. After restart, check observations and last-known remote metadata are initially empty. `healthy` therefore means reachable without a known associated failure, not proof of complete or fresh check coverage. An unreachable process cannot report its own browser-facing unavailability in a successful response. | ||
|
|
||
| ## ServicePulse integration | ||
|
|
||
| The endpoint supplies primary/remote inventory, installed versions, configuration, and issues. Updating this endpoint does not update the ServicePulse consumer automatically; the consumer must map `instances` into its stores and support unknown instance types and unassigned alerts. | ||
|
|
||
| ServicePulse continues to own: | ||
|
|
||
| - Its running frontend version and ServicePulse row. | ||
| - The browser-selected monitoring URL, monitoring requests, and monitoring row. | ||
| - Browser-to-primary connectivity failures, including when this endpoint cannot be reached. | ||
| - Release-feed requests, latest-version comparison, release links, upgrade badges, and outdated-only navigation state. An installed version is not a guarantee that an upgrade path is supported. | ||
| - The customer-check fetch for the support export. Export combines this response, browser-owned rows, and the existing custom-check results. Customer checks never affect platform health. | ||
|
|
||
| Keep the legacy consumer fallback for supported ServiceControl versions without the advertised capability. Do not interpret `401`, `403`, a timeout, or a failed response as an absent capability. The existing custom-check API, classification, notifications, and integration events remain unchanged. Audit health still arrives through the current custom-check reporting transport; this increment does not remove that dependency or introduce replacement events. | ||
|
|
||
| ## Access | ||
|
|
||
| The endpoint retains `error:customchecks:view`, granted by the existing reader, writer and admin roles. No permission or authentication behavior is changed. With authentication disabled it is anonymous. With authentication and RBAC enabled, anonymous callers receive `401` and authenticated callers without a read role receive `403`. | ||
|
|
||
| Known shared-policy limitation: authentication enabled with RBAC disabled currently resolves named permissions to allow-all, so the expanded response can be accessed anonymously. Fixing that policy is separate work. Container liveness and readiness remain separate at `/health` and `/health/ready`. | ||
|
|
||
| ## Verification | ||
|
|
||
| For manual requests, use [PlatformHealth.http](../src/ServiceControl/PlatformHealth.http). Its authenticated request reads an existing bearer token from `SERVICECONTROL_ACCESS_TOKEN`; do not store credentials in the request file. | ||
|
|
||
| `PlatformHealthStateTests` and `PlatformHealthApiTests` cover snapshot ordering, delayed reports, serialization, source projection, identity ambiguity, offline metadata, partial failures and cancellation. Remote-client tests cover HTTP status, malformed responses and prefixed URLs. Shared acceptance scenarios exercise the real root/configuration/health responses and preserve custom-check behavior. The multi-instance `When_inspecting_platform_health` scenario exercises real audit check delivery, issue ownership, recovery and unavailable inventory. OIDC acceptance scenarios cover the existing read-role policy. | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these multiple fields listed in the same row? They read like the possible values for a field and not the field name themselves.