Loading…
Loading…
Describes the license heartbeat client, which sends periodic telemetry to the Specaria platform. Details the payload, configuration, and operational
The Specaria Heartbeat Client is an internal component responsible for sending periodic liveness and telemetry data to the Specaria platform. This process, known as a "heartbeat," serves to validate the license status and provide anonymized, high-level usage metrics and health information.
The client runs as part of the admin-api service. It is triggered automatically on a daily schedule and once upon application startup. On each trigger, it gathers data from the platform's database and runtime environment, constructs a JSON payload, and sends it via an HTTP POST request to the Specaria API endpoint associated with the active license.
The system is designed to be fail-open, meaning that any failure during the heartbeat process (e.g., network errors, database issues) will not crash the product or interrupt its operation.
The heartbeat process is initiated by one of two triggers: a daily scheduled task or a one-time event on application startup. The client then follows a sequence of steps to build and send the payload, with several gates and decision points.
sequenceDiagram
participant Scheduler as Scheduler/Startup
participant HeartbeatClient as SpecariaHeartbeatClient
participant DB as Database (s2r_system_setting)
participant LicenseValidator as License Validator
participant SpecariaAPI as Specaria API
Scheduler->>HeartbeatClient: Trigger (daily cron / on boot)
HeartbeatClient->>LicenseValidator: Get current license state
LicenseValidator-->>HeartbeatClient: LicenseState (or null)
alt License absent/disabled
HeartbeatClient-->>Scheduler: Stop
end
HeartbeatClient->>DB: Read 'specaria.heartbeat_sender'
DB-->>HeartbeatClient: Sender owner
alt Another component is sender
HeartbeatClient->>DB: Write component versions
DB-->>HeartbeatClient: OK
HeartbeatClient-->>Scheduler: Stop (stand down)
end
HeartbeatClient->>DB: Write component versions
DB-->>HeartbeatClient: OK
HeartbeatClient->>HeartbeatClient: buildPayload()
Note right of HeartbeatClient: Gathers metrics from DB, <br/>health probes, env vars.
HeartbeatClient->>HeartbeatClient: redact(payload)
alt Redaction fails
HeartbeatClient->>DB: Record status 'redactor-rejected'
HeartbeatClient-->>Scheduler: Stop
end
HeartbeatClient->>LicenseValidator: Get raw JWT
LicenseValidator-->>HeartbeatClient: JWT
HeartbeatClient->>SpecariaAPI: POST /v1/licenses/{jti}/heartbeat
SpecariaAPI-->>HeartbeatClient: HTTP Response (e.g., 2xx, 4xx, 5xx)
alt Transient Failure (e.g., 5xx)
HeartbeatClient->>HeartbeatClient: Wait 60s
HeartbeatClient->>SpecariaAPI: POST /v1/licenses/{jti}/heartbeat (Retry)
SpecariaAPI-->>HeartbeatClient: HTTP Response
end
HeartbeatClient->>DB: Record final status and timestamp
DB-->>HeartbeatClient: OKs2r.specaria.heartbeat-cron (default 0 5 0 * * * UTC). To prevent multiple installations from contacting the API simultaneously, a random jitter of up to ±2 hours is applied before the job executes.To ensure an installation sends exactly one heartbeat, a leader election mechanism is used.
specaria.heartbeat_sender in the s2r_system_setting table.s2r-release-controller), this client will stand down and not send a heartbeat. It will still publish its known component versions to the database for the active sender to use.admin-api, this client proceeds with sending the heartbeat.SpecariaRedactor. This is a privacy backstop that ensures no disallowed data patterns (e.g., hostnames, URLs) are ever sent. If the redactor rejects the payload, the heartbeat is dropped and an error is logged.s2r.specaria.heartbeat-url-template. The request is authenticated using the raw license JWT as a Bearer token in the Authorization header.410 Gone, 429 Too Many Requests) are treated as permanent failures for the current cycle, and no retry is attempted.accepted-202, dropped-404, redactor-rejected) is recorded in the s2r_system_setting table with the key specaria.last_heartbeat_status. If successful, a timestamp is also recorded under the key specaria.last_heartbeat_at.The heartbeat payload is structured into tiers, allowing operators to control the level of detail shared.
inventory and diagnostics, are considered optional. They are included only if the installation-wide setting specaria.telemetry_optional_enabled is true (the default). Operators can disable this tier via an administrative API endpoint.IMPORTANT
Even when optional telemetry is enabled for the installation, specific sub-fields within the inventory block are further controlled by consent flags in the license JWT (meta.telemetry_consent). A field is only included if both the installation-wide setting is enabled AND the license consents to that specific category.
The client sends an HTTP POST request with a JSON body.
POSTs2r.specaria.heartbeat-url-template configuration property, with {jti} replaced by the license's JWT ID.
https://api.specaria.io/v1/licenses/{jti}/heartbeatAuthorization: Bearer <raw-license-jwt>Content-Type: application/jsonUser-Agent: s2r-licensing/1Accept: application/jsonThe JSON payload has the following structure. All fields are subject to redaction to remove sensitive data patterns before being sent.
{
"product_version": "<string>",
"agent_version": "<string>",
"success": "<boolean>",
"metrics": {
"max_discovered_services": "<integer>",
"max_converted_services": "<integer>"
},
"environment": "production",
"host_fingerprint": "sha256-<string>",
"telemetry": {
"schema_version": 1,
"product_id": "<string>",
"release_version": "<string>",
"service_versions": {
"admin-api": "<string>",
"admin-ui": "<string>",
"worker": "<string>",
"f5-ingest": "<string>",
"runtime": "<string>",
"s2r-release-controller": "<string>"
},
"uptime_seconds": "<long>",
"deployment_type": "<string>",
"cloud_provider": "<string>",
"orchestrator": "<string>",
"instance_id": "<uuid>",
"error_count_5m": "<long>",
"request_count_5m": "<long>",
"controller_status": "<string>",
"last_update_outcome": {
"release_version": "<string>",
"status": "<string>",
"at": "<iso-8601-timestamp>"
},
"inventory": {
"service_inventory": [
{
"name": "<string>",
"image_tag": "<string>",
"replicas": "<integer>"
}
],
"capabilities": ["<string>"],
"config_keys_set": ["<string>"],
"integrations": ["<string>"],
"schema_versions": {
"admin-api": "<string>"
},
"resource_profile": {
"cpu_class": "<string>",
"mem_class": "<string>",
"storage_class": "<string>"
}
},
"diagnostics": {
"...": "..."
}
}
}
| Field | Type | Description |
|---|---|---|
product_version | String | The authoritative semantic version of the product, sourced from the S2R_DEPLOY_VERSION environment variable. |
agent_version | String | Same as product_version. |
success | Boolean | A flag indicating the combined health of the database connection and runtime components. true if healthy. |
metrics | Object | A container for usage metrics. Keys must match those in the license's limits. |
environment | String | Hardcoded to "production". |
host_fingerprint | String | A sha256- prefixed hash of the sender's hostname, used for instance identification. |
telemetry | Object | A nested object containing detailed telemetry data conforming to telemetry-schema-v1. |
telemetry Object| Field | Type | Description |
|---|---|---|
schema_version | Integer | The version of the telemetry schema being sent. Hardcoded to 1. |
product_id | String | The product slug (e.g., s2r). Must match the product claim in the license JWT. |
release_version | String | The version of the release manifest last applied by the release controller. |
service_versions | Object | A map of component names to their versions. |
uptime_seconds | Long | The number of seconds the sending process has been running. |
deployment_type | String | The deployment model (e.g., CUSTOMER_VPC, SAAS_HOSTED). Sourced from the license or defaults to CUSTOMER_VPC. |
cloud_provider | String | The cloud provider where the product is running (e.g., gcp, aws, azure, on_prem). |
orchestrator | String | The container orchestrator (e.g., cloud-run, kubernetes, compose). |
instance_id | String | A stable v4 UUID that identifies the installation, consistent across restarts. |
error_count_5m | Long | A point-in-time sample of the number of failed requests in the last 5 minutes. |
request_count_5m | Long | A point-in-time sample of the total number of requests in the last 5 minutes. |
controller_status | String | The status of the release controller (ok, degraded, error), or the product's own health if the controller is not present. |
last_update_outcome | Object | The outcome of the last release applied by the controller. |
inventory | Object | (Optional) A description of the deployed components and configuration. See details below. |
diagnostics | Object | (Optional) A block containing always-safe, Tier-0 diagnostic data. |
inventory Object (Optional)The inventory block is only included if optional telemetry is enabled. Each sub-field is additionally gated by a specific consent key in the license. If consent is not granted for a category, its corresponding field is omitted.
| Field | Consent Key | Description |
|---|---|---|
service_inventory | service_inventory | List of running services with their name and image tag. |
capabilities | capabilities | List of enabled feature slugs from the license features claim. |
config_keys_set | config_keys | Names of relevant environment variables that are set (values are never included). |
integrations | integrations | List of distinct connector vendor slugs (e.g., f5, datapower). |
schema_versions | schema_versions | The current database migration version for each component. |
resource_profile | resource_profile | Coarse-grained classification of allocated resources (e.g., small, medium, large). |
The heartbeat client's behavior can be configured via application properties and environment variables.
| Name | Type | Default | Description |
|---|---|---|---|
s2r.specaria.heartbeat-cron | String | 0 5 0 * * * | Cron expression in UTC for the daily scheduled heartbeat. |
s2r.specaria.heartbeat-url-template | String | https://api.specaria.io/v1/licenses/{jti}/heartbeat | URL template for the heartbeat API endpoint. The {jti} placeholder is replaced with the license JWT ID. |
S2R_SPECARIA_HTTP_TIMEOUT_SECONDS | Long | 60 | Timeout in seconds for the outbound HTTP request. |
S2R_DEPLOY_VERSION | String | — | The authoritative product version, stamped at deployment. This is the primary source for the reported version. |
s2r.cloud.provider | String | gcp | Cloud provider identifier (e.g., gcp, aws, azure, on_prem). |
s2r.specaria.orchestrator | String | cloud-run | Runtime orchestrator identifier (e.g., cloud-run, kubernetes, compose). |
S2R_INSTANCE_ID | String | — | A stable, unique identifier (UUID v4) for the installation. If not set, a deterministic ID is derived from the license or host fingerprint. |
s2r.specaria.optional-telemetry-default | Boolean | true | The default value for enabling optional telemetry if no setting is stored in the database. |
NOTE
The HTTP client respects the standard HTTPS_PROXY, NO_PROXY, and SSL_CERT_FILE environment variables for routing requests through a corporate egress proxy.
An operator can control the inclusion of optional telemetry blocks (inventory and diagnostics).
The setOptionalTelemetryEnabled(boolean enabled) method updates the specaria.telemetry_optional_enabled setting in the s2r_system_setting table. This method is exposed via an administrative API endpoint (POST /admin/v1/specaria/telemetry/optional).
true enables the optional telemetry tier.false disables it, and only the liveness signal and basic telemetry will be sent.The outcome of each heartbeat cycle is recorded in the s2r_system_setting table under the key specaria.last_heartbeat_status. This provides visibility into the client's operation.
| Status Value | Trigger | Meaning |
|---|---|---|
accepted-<status_code> | The Specaria API responded with a 2xx status code. | The heartbeat was successfully received and accepted by the platform. |
dropped-transport | A network error (e.g., timeout, DNS failure) occurred on both the initial attempt and the retry. | The client could not reach the Specaria API. Check network connectivity, proxy settings, and firewall rules. |
dropped-<status_code> | The Specaria API responded with an unhandled error code (e.g., 500, 503) on both attempts. | The platform reported a server-side error. The client will try again on the next scheduled cycle. |
no-such-license-404 | The API returned HTTP 404. | The jti from the license is not recognized by the platform. This is a configuration error, not a revocation. Ensure the installed license is correct. |
dropped-401 | The API returned HTTP 401. | The license JWT used for authentication was rejected (e.g., expired, invalid signature). The client will not retry this cycle. |
dropped-410 | The API returned HTTP 410. | The license has been permanently revoked by the platform. The product will enter a degraded mode on its next restart. |
dropped-429 | The API returned HTTP 429. | The platform is rate-limiting requests from this installation. The client will not retry this cycle. |
redactor-rejected | The internal SpecariaRedactor rejected the payload before it was sent. | A value with a disallowed shape (e.g., containing a URL or hostname) was found in the payload. This is a privacy-guard failure; the heartbeat was dropped to prevent data leakage. |
serialize-failed | The client failed to serialize the payload to JSON. | An internal error occurred during payload construction. The heartbeat was dropped. |
no-jwt | The client could not retrieve a raw JWT from the license validator. | The heartbeat was dropped because it could not be authenticated. |
stood-down | Another component has claimed ownership of the heartbeat sender role. | This is normal behavior in a multi-component deployment. The heartbeat is being sent by another service. |
interrupted | The sending thread was interrupted while waiting for the retry delay. | The heartbeat cycle was aborted. |