Loading…
Loading…
Technical documentation for the platform's update service, which manages update channels, automatic installations, and operator-approved updates via a
The Update Channel Service manages the platform's update lifecycle. It provides the backend functionality for the administration UI's "Settings → Updates" panel, allowing operators to view the current version, check for updates, configure update behavior, and view installation history.
A key architectural aspect of this service is that it does not directly poll an external update platform for new releases. Instead, it acts as a client to an in-VPC release controller. The release controller is the sole component responsible for pulling, verifying, and applying new software versions. This service reflects the state reported by the release controller, providing a durable and consistent view of the update process.
The service is responsible for:
release, beta, etc.) and update mode (auto or operator_approved).The service's functionality is centered around reflecting the state of the release controller and managing a durable history of update events in the s2r_update_history table.
IMPORTANT
This service no longer performs its own network poll for updates or verifies release manifest signatures. This responsibility has been delegated entirely to the in-VPC release controller. As a result, status conditions related to manifest signature verification failures are no longer possible from this service.
The effective update status, as seen in the admin UI, is generated by the effective() method. This method uses a 30-second in-memory cache to reduce load. When the cache is invalid, it resolves the status by:
update_channel and update_mode from the system settings repository./status endpoint. This call is fail-open with a short timeout, ensuring the admin UI remains responsive even if the controller is absent or unhealthy.lastCheckStatus (success, degraded, unreachable) from the controller's reported health.operator_approved mode and has observed a new version, this service surfaces it as latestAvailableVersion. In auto mode, the controller applies updates automatically, so no "available-but-not-installed" state exists.in_progress update history rows if the controller's status now reports a terminal outcome (e.g., success, failed, rolled_back) for the corresponding update attempt. This correlation is done using a unique apply_attempt_id.The following diagram illustrates the data flow for status reporting:
flowchart TD
subgraph "API Platform"
subgraph "Admin API"
UCS["Update Service"]
end
subgraph "Release Controller"
RC["Release Controller"]
end
end
Operator["API Publisher (Operator)"] -- "1. Views update status" --> UCS
UCS -- "2. GET /status" --> RC
RC -- "3. Reports status" --> UCS
UCS -- "4. Displays status to Operator" --> Operator
RC -- "Pulls & verifies releases" --> UpdatePlatform["External Update Platform"]When the platform is in operator_approved update mode, an operator must explicitly trigger an available update. This is handled by the applyUpdate method, which is invoked via the POST /admin/v1/updates/apply endpoint.
The process is as follows:
s2r_update_history table with a status of in_progress. This ensures a durable record of the update attempt exists before any action is taken. A client-generated apply_attempt_id is included in this record for correlation.triggerApply endpoint, passing the target version and the apply_attempt_id.TRIGGERED outcome.applyUpdate method receives the outcome:
TRIGGERED, the history row remains in_progress. The final result will be determined later via status polling or startup reconciliation.CONFLICT, NOT_OBSERVED), the service immediately updates the in_progress history row to a failed status, ensuring no dangling records exist for rollouts that never started.The release controller can apply updates automatically without involving this service. To ensure the update history is accurate, a reconciliation process runs every time the application starts.
currentVersion) against the to_version of the most recent record in the s2r_update_history table.in_progress history rows that match a terminal apply_attempt_id reported by the controller. This ensures operator-initiated updates are correctly marked as success, failed, or rolled_back.initiated_by set to release-controller. This new record appears as an unacknowledged notification for administrators in the UI.baseline history record is created.The update service is configured through a combination of system settings and environment variables.
These settings are managed via the system settings API and control the update behavior.
| Name | Type | Default | Required | Description |
|---|---|---|---|---|
update_channel | String | release | No | The update channel to follow. Valid values are internal, beta, early-access, and release. |
update_mode | String | operator_approved | No | The update mode. Valid values are auto (updates are applied automatically) and operator_approved (an operator must approve updates). |
update_check_interval_hours | String | 24 | No | The source does not specify the usage of this setting. |
update_window_utc_start_hour | String | 02 | No | The source does not specify the usage of this setting. |
update_window_utc_duration_hours | String | 2 | No | The source does not specify the usage of this setting. |
installation_id | String | — | Yes | A unique UUID for the installation, used to scope update history. If not set, it falls back to the ID from the platform license. |
These properties configure service-level parameters.
| Property / Environment Variable | Default Value | Description |
|---|---|---|
s2r.deploy.version / S2R_DEPLOY_VERSION | dev | The currently running version of the platform. Also falls back to S2R_DEPLOY_COMMIT_SHORT. |
s2r.updates.release-notes-base-url / S2R_UPDATES_RELEASE_NOTES_BASE_URL | Canonical public API base URL | The base URL used to construct links to release notes for the installed version. |
s2r.updates.check-cron | 0 0 3 * * * | The cron schedule for refreshing the cached update status. This does not trigger a network poll to the external update platform, only a refresh from the release controller. |
The service exposes functionality that backs several administrative API endpoints.
Retrieves the current update status, including channel, mode, current version, and any available updates. The response is cached for 30 seconds.
EffectiveStatus):| Field | Type | Description |
|---|---|---|
channel | String | The active update channel (e.g., release). |
mode | String | The active update mode (auto or operator_approved). |
currentVersion | String | The currently installed platform version. |
currentReleaseNotesUrl | String | A full URL to the release notes for the currentVersion. Null if the version is not a standard semantic version. |
lastCheckAt | OffsetDateTime | The timestamp of the last status refresh. |
lastCheckStatus | String | The status of the last check: success, degraded, or unreachable. Derived from the release controller's health. |
lastCheckError | String | A descriptive error message if lastCheckStatus is not success. |
lastCheckErrorClass | String | An internal error class for the last check status. |
latestAvailableVersion | String | The version string of a pending update, if one is observed by the release controller in operator_approved mode. Null otherwise. |
latestAvailableSeverity | String | The severity of the available update (e.g., medium, high), sourced from the verified release manifest. |
latestAvailableSummary | String | A short summary of the available update, sourced from the verified release manifest. |
latestAvailableReleaseNotesUrl | String | A full URL to the release notes for the latestAvailableVersion. |
checkIntervalHours | Integer | The configured check interval. The source does not specify its usage. |
windowStartHour | Integer | The configured update window start hour. The source does not specify its usage. |
windowDurationHours | Integer | The configured update window duration. The source does not specify its usage. |
stubMode | Boolean | Always false. The network poll is retired, not a stub. |
placeholderKey | Boolean | Always false. Manifest verification is no longer performed by this service. |
entitledChannels | List<String> | The complete list of valid channel names that can be configured: internal, beta, early-access, release. |
updateProcessActive | Boolean | true if the release controller is present and reporting status. |
Triggers the release controller to apply an update. This is intended for use in operator_approved mode.
POST /admin/v1/updates/applylatestAvailableVersion.Example Response (Trigger Accepted)
If the release controller accepts the request, it returns a 202 status and begins the update in the background. The history row is left in_progress.
{
"fromVersion": "1.2.3",
"toVersion": "1.2.4",
"outcome": "TRIGGERED",
"historyId": "a1b2c3d4-e5f6-7890-1234-567890abcdef",
"status": "in_progress",
"note": "Apply requested — the release controller is applying 1.2.4 in the background. Watch history for the result."
}
Example Response (Trigger Rejected)
If the controller rejects the request, the response indicates the reason, and the pre-created history row is marked as not_applied.
{
"fromVersion": "1.2.3",
"toVersion": "1.2.4",
"outcome": "CONFLICT",
"historyId": "b2c3d4e5-f6a7-8901-2345-67890abcdef1",
"status": "not_applied",
"note": "The release controller could not apply 1.2.4 — it is not the currently observed available version, or automatic apply is not enabled on this install."
}
The service also provides methods to support the following operations, typically exposed via the admin API:
history(int limit) - Fetches a list of recent update history records for the current installation.notifications(String adminSubject) - Fetches unseen auto-install notifications for a given administrator.acknowledgeNotifications(String adminSubject) - Marks all unseen notifications as seen for a given administrator.checkOnce(String trigger) - Immediately refreshes the cached status from the release controller. Backs the POST /admin/v1/updates/check endpoint.| Issue | Cause & Meaning
| "Last check status" is unreachable | The service could not connect to the in-VPC release controller. This is expected if the release controller is not deployed with your installation. The lastCheckError will be "The in-VPC release controller is not reachable."
| "Last check status" is degraded | The release controller is running but reports a non-healthy state. This can mean the controller process itself is degraded, or that its own attempt to check for updates from the external platform failed. The lastCheckError will provide more detail, such as "The last update check could not verify a release from the update platform."
| Update apply fails with CONFLICT | The release controller rejected the request because the target version is not the one it currently sees as available, or because automatic updates are not enabled for the installation.
| Update apply fails with UNAUTHORIZED or UNAVAILABLE | The release controller rejected the request because an internal signing secret used for communication between this service and the controller is not configured correctly, or the controller is not reachable.
| An update remains in_progress indefinitely | This can happen if an update was triggered but the platform was restarted before the release controller reported a terminal status. The status should resolve automatically during the next status check or application restart when the service reconciles its history with the controller's list of terminal attempts. If it persists, it may indicate an issue with the release controller itself.
| installation_id is not configured error | An operation like applying an update or fetching history failed because the installation_id could not be resolved from system settings or the platform license. Ensure the installation_id setting is configured or a valid license is present.