Restore Channel Postgres

Record a restore of the channel's database and answer 202.

The checks run in one transaction with the record, in this order, and each refusal records nothing:

  1. The channel: 404 for a caller who is not a member.
  2. A move that carries the app: 409 maintenance. The check runs under the owner lock in its weaker mode (pg_placement.py::lock_owner_no_key), which conflicts with the FOR UPDATE every plan_apply producer takes before it checks for a restore, so a restore and a plan change of one user never both pass.
  3. The prod channel: 403 protected_action unless a person drives the caller or the owner turned agent access on.
  4. The typed name: 400 invalid_confirmation.
  5. A maintenance_channel_id with a mode other than maintenance: 400 maintenance_channel_needs_maintenance.
  6. Degraded mode: 503 postgres_unavailable.

A request_id the ledger already holds then goes straight to the core's verb, which replays the recorded restore, or answers 409 request_id_conflict for an id recorded for another call. A new request takes the channel's row lock (channels/service.py::lock_channel), which the tenant deploy and rewind, the admin rebuild, the operator redeploy, the push worker, and the transfer accept take before they read the restore holds, and meets:

  1. The owner, read again under the channel lock: 409 when an ownership transfer changed it since the read of check 1.
  2. The snapshot: 404 snapshot_not_found or snapshot_host_gone, and 409 snapshot_out_of_window.
  3. The page channel, when the body names one (proxy/maintenance.py::maintenance_target_refusal): 400 maintenance_channel_not_found for a channel that does not exist or has another owner, maintenance_channel_not_static, or maintenance_channel_not_deployed.
  4. The core's verb (postgres/api.py::restore_channel_database): 409 when the database is not ready, and 409 restore_in_flight while another restore of the channel is active.

Once the core records the restore, the same transaction cancels the channel's queued deploys and rewinds (deploy/dispatch.py::cancel_queued_for_restore). A running deploy and a queued rehome are left alone: the restore waits for them (design/PG-FLEET.md, "Guards while a restore is active").

The body's during_restore, read_only by default, maintenance, or live, and its maintenance_channel_id are parameters of the recorded command, so a replay that names another mode or another page channel answers request_id_conflict. The answer is the restore's status and the ids of the deploys its start cancelled, with Location naming its status route. A replay reads the cancelled deploys back and cancels nothing. The route then nudges the restore dispatcher.

post/apps/{app_id}/channels/{channel_id}/postgres/restore

Request

  • Base URL: https://api.xhostd.com (the document declares no server; this is the origin it was published from)
  • URL: https://api.xhostd.com/apps/{app_id}/channels/{channel_id}/postgres/restore
  • Auth: none declared

Path parameters

app_idstring uuid required
channel_idstring uuid required

Headers

authorizationstring nullable

Request body

confirm_db_namestring required
snapshot_idstring uuid required
request_idstring uuid nullable
during_restore'read_only' | 'maintenance' | 'live'

What the channel's app can do with its database while the restore runs, from the claim to the swap.

read_only: the hold step makes every new transaction of r_<ch32> in ch_<ch32> read-only, so a write fails with SQLSTATE 25006 rather than vanish at the swap. maintenance: the same hold, and the edge serves a page in place of the app (proxy/maintenance.py), the restore's maintenance_channel_id parameter naming a static channel for the page or None for the platform's own. live: the app keeps writing, and the swap discards those writes.

maintenance_channel_idstring uuid nullable

Response

Successful Response

restore_idstring uuid required
app_idstring uuid required
channel_idstring uuid required
snapshot_idstring uuid required
during_restore'read_only' | 'maintenance' | 'live' required

What the channel's app can do with its database while the restore runs, from the claim to the swap.

read_only: the hold step makes every new transaction of r_<ch32> in ch_<ch32> read-only, so a write fails with SQLSTATE 25006 rather than vanish at the swap. maintenance: the same hold, and the edge serves a page in place of the app (proxy/maintenance.py), the restore's maintenance_channel_id parameter naming a static channel for the page or None for the platform's own. live: the app keeps writing, and the swap discards those writes.

maintenance_channel_idstring uuid nullable required
status'queued' | 'extracting' | 'loading' | 'swapping' | 'succeeded' | 'failed' required
waitingstring nullable required
queue_aheadinteger nullable required
activitystring nullable required
error_codestring nullable required
messagestring nullable required
noticestring required
submitted_atstring date-time required
started_atstring date-time nullable required
updated_atstring date-time required
finished_atstring date-time nullable required
cancelled_deploysstring[] required

Changes

No recorded changes to this operation across all 1 revision of this API.