Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 21 additions & 4 deletions learn/developers/deploying-from-ci.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ harper deploy project=my-app by_ref=true \

Keep the workflow's wait step when using `restart=rolling`. For a single-node instance, use `restart=true` instead. Changing isolation makes canary certification unavailable on v5.4.0 and later; see [Canary certification](/reference/v5/operations-api/operations#certifying-a-release-in-a-canary-worker).

Creating an isolated application, or turning isolation on or off, also restarts the shared workers. Later redeploys that keep the application isolated restart only its worker, except an activation retry whose release is already live. A package redeploy that omits `isolated` preserves it; pass `isolated=false` to return the application to the shared pool.
Turning isolation off also restarts the shared workers, as does turning it on for an application they had loaded, or, before v5.4.0, creating an isolated application. From v5.4.0, a new isolated application's first `restart=true` deploy starts only its own worker. Later redeploys that keep the application isolated restart only its worker, except an activation retry whose release is already live. A package redeploy that omits `isolated` preserves it; pass `isolated=false` to return the application to the shared pool.

## Per-PR previews with shared databases

Expand Down Expand Up @@ -465,14 +465,31 @@ jobs:

The workflow reads the PR's current state, base branch, and head SHA from GitHub, rather than deploying the default-branch commit in `GITHUB_SHA`. Its concurrency group serializes updates and cleanup for that PR without canceling a deploy midway. A delayed run sees a closed or retargeted PR and cleans up instead of recreating the preview. The job filter ignores title/body edits and unrelated updates on other base branches, while admitting closures and base-branch edits. The fresh API read remains authoritative.

Cleanup checks component files and running workers separately on **each listed node**, so it also handles a worker left running after files were removed. An absent node is skipped: dropping an absent preview with `restart=true` can restart its shared workers. Each necessary drop uses `replicated=false`, and requests a restart only when that node has the preview worker. Files without a worker are dropped with `restart=false`; the node's shared workers stay running. It then verifies the component and worker are both absent; a successful drop response alone is insufficient. The loop attempts the remaining nodes after an error and fails the job with each failed target in the summary. After a failed, timed-out, or interrupted run, rerun cleanup and check those nodes directly with an administrator account; do not reuse the project name until cleanup has completed on every node. An omitted node cannot be checked or cleaned by this workflow.
Cleanup checks component files and running workers separately on **each listed node**, so it also handles a worker left running after files were removed. An absent node is skipped: before v5.4.0, dropping an absent preview with `restart=true` can restart its shared workers. Each necessary drop uses `replicated=false`, and requests a restart only when that node has the preview worker. Files without a worker are dropped with `restart=false`; the node's shared workers stay running. It then verifies the component and worker are both absent; a successful drop response alone is insufficient. The loop attempts the remaining nodes after an error and fails the job with each failed target in the summary. After a failed, timed-out, or interrupted run, rerun cleanup and check those nodes directly with an administrator account; do not reuse the project name until cleanup has completed on every node. An omitted node cannot be checked or cleaned by this workflow.

The deploy still propagates to peers by default on Fabric and Pro, and a failed peer install fails the CLI unless `ignore_replication_errors` is set. Do not enable that option here. Cleanup uses direct node calls specifically to recover from asymmetric deploy or drop state.

`restart=true` waits for the restart on the answering node, but a successful response does not establish that every peer loaded the application: a peer restart can be slow or fail, and a node can refuse isolation. This workflow prints the URL but does not probe preview health. Check [application status](/reference/v5/operations-api/operations#set_status--get_status--clear_status) on each node with an administrator account and verify the routed preview endpoint. This recipe uses inline restarts instead of the production workflows' rolling job. **The first deploy of each preview can restart shared workers on all nodes concurrently**, disrupting existing connections. Use a dedicated preview cluster if that interruption is unacceptable; adapting the [rolling workflow](#path-a-deploy-a-tagged-release-from-your-repository) also requires granting `get_deployment` and `get_job` to the preview role and retaining its wait step.
`restart=true` waits for the restart on the answering node, but a successful response does not establish that every peer loaded the application: a peer restart can be slow or fail, and a node can refuse isolation. This workflow prints the URL but does not probe preview health. Check [application status](/reference/v5/operations-api/operations#set_status--get_status--clear_status) on each node with an administrator account and verify the routed preview endpoint. This recipe uses inline restarts instead of the production workflows' rolling job. **Before v5.4.0, the first deploy of each preview restarts the shared workers on all nodes concurrently**, disrupting existing connections; from v5.4.0, it starts only the preview's own worker. On earlier versions, use a dedicated preview cluster if that interruption is unacceptable; adapting the [rolling workflow](#path-a-deploy-a-tagged-release-from-your-repository) also requires granting `get_deployment` and `get_job` to the preview role and retaining its wait step.

Fork PRs are skipped; keep that same-repository condition. The policy pins `workflow_ref` so a PR cannot change the trusted workflow to mint a token with different commands; `event_name` explicitly authorizes `pull_request_target`, which Harper otherwise refuses unless constrained. Provision the hostname before opening the preview URL; successful deployment alone does not make an unconfigured hostname reachable. Close unused previews to release worker slots. Dropping a running isolated preview stops its worker and normally reclaims retained installs; inspect node logs if storage cleanup fails. Removing an application does not undo its shared-database writes or remove DNS and Fabric custom-domain registrations; clean up that routing separately.

#### Cleanup in one call on v5.4.0

<VersionBadge version="v5.4.0" />

When every node runs v5.4.0 or later, cleanup is one replicated drop through `HARPER_CLI_TARGET`. The per-node targets, their trust policies, and the role's `get_components` and `system_information` grants are then unnecessary. In the workflow, delete the `PREVIEW_NODE_TARGETS` entry under `env:` and the `jq` line that validates it, and replace the cleanup branch, from `if [ "$(jq -r .state <<< "$PR")" = closed ]` through its `fi`, with:

```bash
if [ "$(jq -r .state <<< "$PR")" = closed ] ||
[ "$(jq -r .base.ref <<< "$PR")" != main ]; then
harper drop_component project="$PROJECT" json=true > drop.json
jq -e '[., .replicated[]?] | all(.error == null and (.componentRemoved | type == "boolean"))' drop.json > /dev/null
exit 0
fi
```

The check fails the job when a node reports an error, or reports no outcome, as a node on an earlier version does. The drop stops the preview's worker on every node without restarting the shared workers, with no `restart` needed, and each node answers only once that worker has stopped. A node that no longer has the preview's files only stops a worker left running there, and restarts nothing, so rerunning a failed cleanup is safe. The response's `replicated` results give each node's outcome; see [`drop_component`](/reference/v5/components/applications#drop_component). A node on an earlier version keeps the worker running until its next restart, so keep the per-node cleanup while any node runs one.

### Private sources and built artifacts

For a private repository, each preview project needs its own grant to a durable source credential. Once you know the PR number, run setup from your machine for that project's name, using a dedicated read-only preview token:
Expand All @@ -487,7 +504,7 @@ For applications that need a build, build and publish an immutable package versi

### Adding private database forks later

The recipe deliberately omits `branchedDatabases`. On v5.3.0 and v5.3.1, a package deployment ignores that key when loading the application ([harper#3071](https://github.com/HarperFast/harper/issues/3071)). Follow [Branched databases](/reference/v5/components/applications#branched-databases) for current behavior and limitations; database forks can be added to the recipe once that deployment path is fixed. Revisit cleanup then as well: a drop with `restart=false` leaves fork storage in place.
The recipe deliberately omits `branchedDatabases`. On v5.3.0 and v5.3.1, a package deployment ignores that key when loading the application ([harper#3071](https://github.com/HarperFast/harper/issues/3071)). Follow [Branched databases](/reference/v5/components/applications#branched-databases) for current behavior and limitations; database forks can be added to the recipe once that deployment path is fixed. Revisit cleanup then as well: before v5.4.0, a drop with `restart=false` leaves fork storage in place. From v5.4.0, dropping an isolated preview removes its forks with or without `restart`.

## Other CI systems

Expand Down
2 changes: 1 addition & 1 deletion learn/developers/multiple-applications.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -150,7 +150,7 @@ listings-api-staging:
branchedDatabases: [listings]
```

The first time the application loads, Harper takes a snapshot of each named database as the application's fork. The `databases` the application imports from `harper` then resolves those names to its fork, so its code is unchanged, and every other application keeps using the base. The `tables` import follows only a fork of the default `data` database, so reach any other branched database, like `listings` here, through `databases`. The fork is durable and is never refreshed from the base. It is not replicated: each node of a cluster keeps its own. `drop_component` with `restart=true` removes it.
The first time the application loads, Harper takes a snapshot of each named database as the application's fork. The `databases` the application imports from `harper` then resolves those names to its fork, so its code is unchanged, and every other application keeps using the base. The `tables` import follows only a fork of the default `data` database, so reach any other branched database, like `listings` here, through `databases`. The fork is durable and is never refreshed from the base. It is not replicated: each node of a cluster keeps its own. `drop_component` with `restart=true` removes it. Without `restart`, the shared workers still have it loaded, so it stays until you drop the application again after they restart. Dropping an isolated application removes its fork with or without `restart` (v5.4.0), and `keepBranches` keeps it. See [Removing a fork](/reference/v5/components/applications#removing-a-fork).

A fork is still not an enforced boundary. The bare `databases` and `tables` globals reach the base. The application can also still open any database that it did not branch. On v5.3.0 and v5.3.1, an application deployed by `package` or `by_ref` gets no fork at all ([harper#3071](https://github.com/HarperFast/harper/issues/3071)). See [Branched databases](/reference/v5/components/applications#branched-databases) for the requirements and the manual steps that work in the meantime.

Expand Down
Loading
Loading