Loading…
Loading…
Manages persistence for software update checks and installation history. Tracks available updates, apply attempts, and notification status for each
The Update Channel Repository provides data persistence for the platform's software update mechanism. It is responsible for tracking the state of update checks, maintaining a historical log of all update attempts, and managing update notification visibility for system administrators.
This component interacts with two primary database tables:
s2r_update_check: Stores the latest result of a check for new versions on a specific update channel for a given installation.s2r_update_history: An append-only log that records every version change attempt, whether initiated by an operator or an automated process.The repository's functions are called by higher-level services that manage the update lifecycle, such as scheduled update pollers and API endpoints that trigger updates. It provides a structured way to query update status and history, ensuring that state is durable and consistent across system restarts and operator sessions.
The repository manages two distinct but related concepts: the current state of available updates and the historical record of applied updates.
The s2r_update_check table maintains a single record for each unique combination of an installation_id and an update channel. This record is managed using an "upsert" (update or insert) pattern.
When the system checks for updates, it calls upsertCheck or upsertCheckWithSigningMetadata. These methods create a new row if one doesn't exist for the (installation_id, channel) pair, or update the existing one.
A key behavior of this operation is how it handles failures. If an update check fails (e.g., due to a network error), the upsertCheck method is called with null values for the available update details. The underlying SQL query uses COALESCE to ensure that a failed check does not erase the details of a previously discovered available update. The information about the available update is only overwritten when a subsequent check successfully retrieves a new manifest.
The upsertCheckWithSigningMetadata variant extends this by also persisting manifest signature verification details, such as the signing_key_id and manifest_verified_at timestamp.
The s2r_update_history table provides an immutable, append-only log of all version changes. Each row represents a specific update attempt, capturing its origin, target versions, and final status.
An update attempt progresses through several states, managed by the repository's methods.
stateDiagram-v2
direction LR
[*] --> in_progress: insertHistory (operator)
[*] --> success: insertHistory (controller/baseline)
[*] --> failed: insertHistory (controller)
[*] --> rolled_back: insertHistory (controller)
in_progress --> success: completeInProgressHistory
in_progress --> failed: failInProgressHistory
in_progress --> rolled_back: closeInProgressHistory
in_progress --> in_progress: setApplyAttemptId
state terminal_states {
direction LR
success
failed
rolled_back
}Lifecycle Stages:
Initiation: A new record is created using insertHistory, insertHistoryWithReleaseMeta, or their variants.
initiated_by: This field is critical. It can be set to baseline for the initial version record on first boot, release-controller for automated updates detected at startup, or an operator identifier for manually triggered updates.status: For operator-initiated updates, the initial status is in_progress. For automated or baseline records, the status is typically a terminal one like success from the start.Correlation (In Progress): For an in_progress update triggered by an operator, the setApplyAttemptId method is called. This stamps the row with a unique apply_attempt_id returned by the underlying update controller. This ID is crucial for correlating the history record with the out-of-band process that performs the update.
Completion: Once the update attempt concludes, the in_progress row is moved to a terminal state.
completeInProgressHistory: Marks the update as success. This is typically used by a startup reconciler when it detects the system is now running the target version.failInProgressHistory: Marks the update as failed and records a reason.closeInProgressHistory: A more general method to set any terminal status (e.g., failed, rolled_back) and a failure reason, preserving the specific outcome from the update controller.All methods that modify an in_progress row are guarded to prevent updates to already-terminal rows, making them idempotent.
The repository supports two layers of update notifications based on release-controller initiated updates.
A global "unseen notification" exists if there is any successful, release-controller-initiated history record that has not been acknowledged.
countUnseenNotifications returns the number of such records.findLatestUnseenNotification retrieves the most recent one.acknowledgeUnseenNotifications marks all such records as acknowledged by setting their acknowledged_at timestamp. This is a single, system-wide acknowledgement.For a more granular experience, the system tracks which administrators have seen a notification for an automated update. This is managed by cross-referencing s2r_update_history with a separate s2r_update_notification_seen table.
An update is considered "unseen" for a specific admin if it was a successful, release-controller-initiated update, and there is no corresponding entry in s2r_update_notification_seen for that history record and admin.
countUnseenForAdmin returns the count of unseen updates for a given adminSubject.findLatestUnseenForAdmin retrieves the most recent unseen update for that admin.markSeenForAdmin marks all currently unseen auto-install notifications as seen for a specific admin by inserting records into the s2r_update_notification_seen table. This action is idempotent and does not affect the notification status for other admins.The repository exposes two primary data structures, CheckRow and HistoryRow, which map directly to the columns in the s2r_update_check and s2r_update_history tables, respectively.
CheckRow FieldsRepresents a record in the s2r_update_check table.
| Field | Type | Description |
|---|---|---|
id | UUID | The primary key of the row. |
installationId | UUID | The unique identifier for the installation. |
channel | String | The name of the update channel being checked. |
lastCheckAt | OffsetDateTime | The timestamp of the last update check attempt. |
lastCheckStatus | String | The status of the last check (e.g., 'success', 'failed'). |
lastCheckError | String | The error message if the last check failed. |
lastCheckErrorClass | String | The class of the error if the last check failed. |
latestAvailableVersion | String | The version string of the latest available update found. |
latestAvailableSeverity | String | The severity of the latest available update (e.g., 'critical', 'low'). |
latestAvailableSummary | String | A short summary of the latest available update. |
latestAvailableReleaseNotesUrl | String | A URL pointing to the release notes for the available update. |
rawManifest | String | The raw JSON content of the release manifest from the update channel. |
HistoryRow FieldsRepresents a record in the s2r_update_history table.
| Field | Type | Description |
|---|---|---|
id | UUID | The primary key of the row. |
installationId | UUID | The unique identifier for the installation. |
fromVersion | String | The version the system was on before this update attempt. |
toVersion | String | The target version for this update attempt. |
initiatedBy | String | Identifier for what triggered the update. Special values include baseline and release-controller. |
initiatedAt | OffsetDateTime | The timestamp when the update attempt was initiated. |
completedAt | OffsetDateTime | The timestamp when the update attempt reached a terminal state (success, failed, rolled_back). Null if in_progress. |
status | String | The current status of the update attempt (e.g., in_progress, success, failed). |
failureReason | String | The reason for failure, if the status is failed or rolled_back. |
acknowledgedAt | OffsetDateTime | Timestamp when a release-controller initiated update was globally acknowledged. Null if not applicable or not acknowledged. |
applyAttemptId | String | A unique ID from the update controller used to correlate this record with the underlying apply process. |
summary | String | A short summary of the update, used for notifications. |
releaseNotesUrl | String | A URL to the release notes, used for notifications. |
The repository exposes methods for querying and manipulating update check and history records.
upsertCheck(...)Inserts or updates a record in s2r_update_check. If the check resulted in an error, this method preserves the last known available update information.
| Name | Type | Required | Description |
|---|---|---|---|
installationId | UUID | Yes | The installation ID. |
channel | String | Yes | The update channel name. |
checkedAt | OffsetDateTime | Yes | The time of the check. |
status | String | Yes | The outcome of the check. |
error | String | No | Error message, if any. |
errorClass | String | No | Error class name, if any. |
version | String | No | Available version found. Pass null on error. |
severity | String | No | Severity of the available version. Pass null on error. |
summary | String | No | Summary of the available version. Pass null on error. |
releaseNotesUrl | String | No | Release notes URL. Pass null on error. |
rawManifestJson | String | No | Raw JSON manifest. Pass null on error. |
voidupsertCheckWithSigningMetadata(...)An extension of upsertCheck that also records manifest signature verification details. This method overwrites any previous available update information with the new data.
upsertCheck, plus:
| Name | Type | Required | Description |
|---|---|---|---|
signingKeyId | String | Yes | The ID of the key used to verify the manifest. |
manifestVerifiedAt | OffsetDateTime | Yes | The timestamp when the manifest signature was verified. |
voidfindCheck(installationId, channel)Retrieves the CheckRow for a given installation and channel.
Optional<CheckRow> containing the record if found.insertHistory(...)Inserts a new record into s2r_update_history. The completed_at timestamp is set automatically if the provided status is terminal (success, failed, rolled_back).
| Name | Type | Required | Description |
|---|---|---|---|
installationId | UUID | Yes | The installation ID. |
fromVersion | String | Yes | The version being updated from. |
toVersion | String | Yes | The version being updated to. |
initiatedBy | String | Yes | Who or what initiated the update. |
status | String | Yes | The status of the attempt. |
failureReason | String | No | Reason for failure, if applicable. |
applyAttemptId | String | No | The correlation ID for the update controller. |
UUID of the newly created history record.insertHistoryWithReleaseMeta(...)Inserts a history record with additional metadata for display in notifications. Used for automated updates detected at startup.
insertHistory, plus:
| Name | Type | Required | Description |
|---|---|---|---|
summary | String | No | A summary of the release. |
releaseNotesUrl | String | No | A link to the release notes. |
UUID of the newly created history record.setApplyAttemptId(id, applyAttemptId)Stamps the apply_attempt_id on an existing in_progress history row. This is used to link an operator-initiated action to the backend controller task.
int (number of rows affected, 0 or 1).completeInProgressHistory(id, status)Updates an in_progress history row to a terminal status and sets the completed_at timestamp.
int (number of rows affected, 0 or 1).failInProgressHistory(id, failureReason)Updates an in_progress history row to a failed status, recording a failure reason and setting the completed_at timestamp.
int (number of rows affected, 0 or 1).closeInProgressHistory(id, status, failureReason)Updates an in_progress history row to an arbitrary terminal status (e.g., rolled_back), recording a failure reason and setting completed_at.
int (number of rows affected, 0 or 1).findInProgressByApplyAttemptId(installationId, applyAttemptId)Finds the in_progress history row matching a specific applyAttemptId. This is used to prevent creating stranded in_progress rows.
Optional<HistoryRow> containing the record if found.listHistory(installationId, limit)Lists the most recent history records for an installation, up to a maximum of 200.
List<HistoryRow>.findLatestHistory(installationId)Retrieves the single most recent history record for an installation.
Optional<HistoryRow>.findLatestSuccessfulHistory(installationId)Retrieves the most recent successfully completed history record. This is useful for determining the current running version if the latest attempt failed.
Optional<HistoryRow>.hasInProgressApplyTo(installationId, toVersion)Checks if there is already an in_progress update to a specific target version. This helps prevent race conditions.
boolean.countUnseenNotifications(installationId)Counts globally unacknowledged, release-controller-initiated updates.
int.findLatestUnseenNotification(installationId)Finds the most recent globally unacknowledged, release-controller-initiated update.
Optional<HistoryRow>.acknowledgeUnseenNotifications(installationId)Marks all unseen release-controller updates as acknowledged globally.
int (number of rows acknowledged).countUnseenForAdmin(installationId, adminSubject)Counts release-controller-initiated updates that a specific admin has not seen.
int.findLatestUnseenForAdmin(installationId, adminSubject)Finds the most recent release-controller-initiated update that a specific admin has not seen.
Optional<HistoryRow>.markSeenForAdmin(installationId, adminSubject)Marks all unseen release-controller updates as seen for a specific admin.
int (number of notification states inserted).An update attempt could theoretically get stuck in an in_progress state if the system responsible for completing the update fails to do so.
in_progress, but the update controller never reports a terminal outcome, or the reconciliation logic fails.status = 'in_progress' and initiated_at is unexpectedly old.findInProgressByApplyAttemptId to correlate outcomes from the update controller back to the specific history row that initiated the attempt, even if it's not the most recent one. This prevents the original in_progress row from being stranded. If a row is still stranded, it indicates a potential bug in the reconciliation logic.An administrator may notice that a previously visible "update available" notification is gone after a new check.
upsertCheck method is designed to preserve the last known available version during failed checks. However, if a subsequent check succeeds and finds no available update (e.g., the update was pulled from the channel), the "update available" fields will be cleared.last_check_status and last_check_at fields in the s2r_update_check table for the relevant installation and channel to understand the outcome of the most recent check.