Expand description
§ferro-deployments
Immutable deployment rows and atomic pointer promotion for the Ferro framework.
§Overview
Each deployment is recorded as an append-only row in the deployments table.
A per-owner deployment_pointers row tracks which deployment is currently active
and which was the previous one, enabling atomic promotion and rollback.
Artifact storage is abstracted through ferro_storage so the same crate works
with local filesystem, S3, or any other configured driver. The artifact shape is
opaque — static site bundles, JSON-UI spec bundles, SSR manifests, and any other
byte sequence all fit without crate-level assumptions.
§Quick Start
Register both migration helpers in your Migrator, then use
DeploymentConfig::from_env to read operator configuration.
use ferro_deployments::{CreateDeploymentsTable, CreateDeploymentPointersTable};
impl MigratorTrait for Migrator {
fn migrations() -> Vec<Box<dyn MigrationTrait>> {
vec![
Box::new(CreateDeploymentsTable),
Box::new(CreateDeploymentPointersTable),
]
}
}§Full lifecycle example (criterion 5 — JSON spec artifact)
This example stores a JSON spec bundle through the full lifecycle API:
create → store → mark_ready → promote → retrieve. The artifact
is opaque bytes — the crate makes no assumption about content type.
// Connect to an in-memory SQLite database and run migrations.
let conn = Database::connect("sqlite::memory:").await.unwrap();
DocMigrator::up(&conn, None).await.unwrap();
// Create a deployment handle and register a new build.
let deps = Deployments::new(conn);
let d = deps.create("project:demo", Some("sha-abcdef")).await.unwrap();
assert_eq!(d.status, DeploymentStatus::Building);
// Build a memory-backed storage adapter and store a JSON spec bundle.
let storage_config = StorageConfig::new("mem").disk("mem", DiskConfig::memory());
let disk = Storage::with_storage_config(storage_config).disk("mem").unwrap();
let storage = StorageDeploymentStorage::new(disk);
let spec_json = Bytes::from_static(br#"{"intent":"browse","fields":[]}"#);
storage.store(d.id, "spec.json", spec_json.clone()).await.unwrap();
// Transition the deployment to ready, recording artifact location and size.
let artifact_location = format!("deployments/{}/", d.id);
deps.mark_ready(d.id, &artifact_location, spec_json.len() as i64)
.await
.unwrap();
// Atomically promote the deployment.
let previous = deps.promote("project:demo", d.id).await.unwrap();
assert!(previous.is_none(), "first promotion has no previous deployment");
// Retrieve the stored artifact and verify round-trip fidelity.
let retrieved = storage.retrieve(d.id, "spec.json").await.unwrap();
assert_eq!(retrieved, spec_json);Structs§
- Create
Deployment Pointers Table - Migration that creates the
deployment_pointerstable. - Create
Deployments Table - Migration that creates the
deploymentstable. - Deployment
- An immutable deployment row.
- Deployment
Config - Deployment system configuration.
- Deployments
- Handle to the deployments system, wrapping a
DatabaseConnection. - Storage
Deployment Storage - Default
DeploymentStoragebacked by aferro_storage::Disk.
Enums§
- Deployment
Status - Lifecycle state of a deployment.
- Error
- Errors that can occur in the deployments system.
Traits§
- Deployment
Storage - Artifact storage abstraction for a deployment prefix.
Functions§
- preview_
url - Build the wildcard-subdomain preview URL for a deployment.