Loading…
Loading…
Documents the repository for relay authentication, heartbeat recording, dispatch selection, and self-update state management in multi-tenant deployments.
The RelayRepository is a data access component that manages the persistence and retrieval of information about relays. Relays are components that establish persistent connections to the platform for routing backend API calls. This repository is responsible for the database interactions that support the entire relay lifecycle, including:
This component interacts directly with the s2r_relay database table and is primarily used by the gateway's relay heartbeat controller. It is designed for multi-tenant (saas) deployments and is not active in single-tenant (byoc) environments.
The repository's design carefully handles tenant data isolation in a multi-tenant environment, using different database access strategies for initial authentication versus subsequent operations.
The process of authenticating a relay and recording its heartbeat involves a two-phase database interaction to ensure security and tenant isolation.
sequenceDiagram
participant C as API Consumer (Relay)
participant G as Gateway
participant R as RelayRepository
participant DB as Database
C->>G: Sends heartbeat with relay key
G->>G: Computes SHA-256 hash of key
G->>R: findByKeyHash(keyHash)
R->>DB: SELECT ... FROM s2r_lookup_relay_key(?)
Note right of R: RLS-bypassing function call
DB-->>R: Returns tenant_id, relay_id, status
R-->>G: Returns RelayLookup object
G->>G: Sets security context to tenant_id
G->>R: recordHeartbeat(keyHash, version)
R->>DB: UPDATE s2r_relay SET ...
Note right of R: RLS-scoped query
DB-->>R: 1 row updated
R-->>G: Returns 1
G-->>C: Heartbeat ACKfindByKeyHash with the SHA-256 hash of the relay's key.s2r_lookup_relay_key database function. This function is a SECURITY DEFINER, which allows it to bypass standard Row-Level Security (RLS) and search for the key hash across all tenants. It returns only the tenant_id, relay_id, and status, preventing any data leakage.tenant_id returned from the lookup to establish the security context for the remainder of the request.recordHeartbeat. This method issues a standard UPDATE statement to the s2r_relay table.UPDATE is subject to RLS and an additional RELAY_TENANT_SCOPE_SQL check. This ensures the operation can only modify the database row corresponding to the authenticated relay within its specific tenant.IMPORTANT
A relay cannot change its own credential status (e.g., from revoked to active) via a heartbeat. The recordHeartbeat operation only updates liveness information (last_heartbeat_at) and the self-reported software version.
When a backend call is configured with dispatch_mode=relay, the platform must select an active relay for the API consumer's tenant.
findActiveRelayId(). The tenant context for the API consumer is already established.s2r_relay table for relays with status = 'active'.last_heartbeat_at DESC NULLS LAST to select the relay that has sent the most recent heartbeat. Relays that have never sent a heartbeat are sorted last.relay_id of the selected relay. If no active relay is found for the tenant, the caller is responsible for failing the dispatch.Relays can query the platform to determine if a software update is available. This process also relies on the established tenant context for security.
findDesiredVersion with the relay's key hash.s2r_relay table, and the query is scoped to the relay's tenant.RelayDesiredVersion object containing the release channel, desired version, and details of the signed software artifact required for the update. If any artifact details (desiredArtifactUrl, desiredArtifactSha256, desiredArtifactSignature) are null, the relay can detect that an update is pending but cannot apply it.This example shows the sequence of repository calls made by the platform to process a single heartbeat from a relay.
A relay sends a heartbeat request containing its key. The gateway computes the SHA-256 hash of this key, for example, e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855.
The gateway calls findByKeyHash to authenticate the relay and identify its tenant.
// The keyHash is the SHA-256 hex digest of the relay's key
String keyHash = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";
Optional<RelayLookup> lookupResult = relayRepository.findByKeyHash(keyHash);
If a match is found, lookupResult will contain a RelayLookup object with the relay's tenantId, relayId, and status. The platform verifies the status is active.
The platform uses the tenantId from lookupResult to set the security context for the current operation.
The gateway calls recordHeartbeat to update the relay's liveness timestamp and reported version.
// The version is self-reported by the relay in its heartbeat
String reportedVersion = "v1.2.3";
int rowsUpdated = relayRepository.recordHeartbeat(keyHash, reportedVersion);
Expected Result: The recordHeartbeat method returns 1, indicating that one row in the s2r_relay table was successfully updated. The last_heartbeat_at column is set to the current time, and the version column is set to v1.2.3. If 0 is returned, it means no matching, non-revoked relay was found within the specified tenant.
The RelayRepository exposes methods for interacting with relay data. All methods that return a single result use Optional to handle cases where no data is found.
Looks up a relay by the SHA-256 hex digest of its key. This method uses an RLS-bypassing function and is intended for initial authentication before the tenant context is known.
keyHash (String, required): The lowercase SHA-256 hex digest of the relay key.Optional<RelayLookup> containing the relay's tenant, ID, and status. Returns an empty Optional if no relay matches the key hash.Records a successful heartbeat from an authenticated relay. This method updates the last_heartbeat_at timestamp and the relay's self-reported version. It runs under an established tenant context and will not update a relay whose status is revoked.
keyHash (String, required): The SHA-256 hex digest of the authenticated relay key.version (String): The software version self-reported by the relay. May be null.int, the number of rows updated (1 on success, 0 if no matching relay was found or the relay was revoked).Finds the most suitable active relay ID for a tenant to be used for dispatching a backend call. The "best" relay is the one with the most recent last_heartbeat_at timestamp. This method runs under an established tenant context.
Optional<String> containing the relay_id of the chosen relay. Returns an empty Optional if the tenant has no active relays.Retrieves the self-update state for a relay, including its release channel and target version information. This method runs under an established tenant context.
keyHash (String, required): The SHA-256 hex digest of the authenticated relay key.Optional<RelayDesiredVersion> containing the relay's update state. Returns an empty Optional if no relay matches the key hash within the current tenant.The repository uses the following data structures to return query results.
Contains the essential identity and status information for a relay, returned by findByKeyHash.
| Field | Type | Description |
|---|---|---|
tenantId | UUID | The unique identifier of the tenant that owns the relay. |
relayId | String | The unique identifier of the relay within its tenant. |
status | String | The credential lifecycle status (e.g., active). |
The RelayLookup record also provides a helper method isActive(), which returns true if the status field is equal to "active".
Contains the complete self-update state for a relay, returned by findDesiredVersion.
| Field | Type | Description |
|---|---|---|
relayId | String | The unique identifier of the relay. |
channel | String | The release ring the relay is assigned to. |
desiredVersion | String | The software version the control plane wants the relay to run. A null value means "stay current". |
currentVersion | String | The last software version the relay self-reported. May be null if it has never reported. |
desiredArtifactUrl | String | The HTTPS URL of the signed software artifact for the update. Null if no update is published. |
desiredArtifactSha256 | String | The lowercase hex SHA-256 digest of the artifact. Null if no update is published. |
desiredArtifactSignature | String | The Base64-encoded Ed25519 signature of the artifact. Null if no update is published. |
NOTE
A relay can only apply an update if desiredArtifactUrl, desiredArtifactSha256, and desiredArtifactSignature are all non-null. If any are null, the relay can detect a pending update but cannot execute it.
Methods findByKeyHash, findActiveRelayId, and findDesiredVersion are designed to handle cases where no matching relay is found. They do this by returning an empty Optional. Callers must check for this empty state and handle it appropriately. For example, if findActiveRelayId returns an empty Optional, the caller must fail the dispatch operation with an error message indicating no active relay is available for the tenant.
In multi-tenant deployments, operations that rely on an established tenant context (all methods except findByKeyHash) are protected by a guard. If the tenant context is not properly bound when one of these methods is called, the operation will fail with an S2R-TENANCY-UNBOUND error. This prevents data from being read from or written to an incorrect (e.g., default) tenant.
The recordHeartbeat method will not update relays with a status of revoked. This is a defense-in-depth measure. Even if a revoked relay's key were somehow used to pass initial authentication, the liveness update would still fail, returning 0 updated rows. The primary liveness signal is the last_heartbeat_at timestamp, which will not be updated for a revoked relay.