The target Pi only has MariaDB, and SQL Server has no ARM64 build at all - not a config problem, a real gap discovered during deployment setup. Swapped the EF Core provider, regenerated every migration, updated connection strings and the backup script everywhere they appear. Took two tries to land on a provider that actually works: Pomelo builds fine against this project's EF Core 10 packages but fails at runtime (it's compiled against 9's internal API surface, which moved in 10 wherever Identity/DataProtection force the newer packages). Oracle's official provider builds and migrates fine but has a real MariaDB bug in its own migration-lock code, reproduced against a live database. Kept Oracle's provider and worked around just that one broken method - everything else it does is correct - rather than give up more of the stack to chase a workaround. Verified against a real local MariaDB end to end: all three migrations applied, both hosts start clean, full suite still green.
3.2 KiB
Rollback Plan
Mechanism (D-26, infrastructure-design.md § 3–4): two releases are always retained —
current plus exactly one previous. Pruning only ever runs after a passing health check, so a
failed deploy never leaves fewer than two releases on disk.
When to Roll Back
- The deploy workflow's health check failed (job already shows red;
currentwas left pointing at the new, unhealthy release — no automatic rollback, perinfrastructure-design.md§ 4) - The deploy succeeded and passed its health check, but a defect surfaces afterward that only shows up under real traffic
Fast Rollback (Previous Release Still on Disk) — the Common Case
No rebuild needed. Over SSH, on the Pi:
cd ~/apps/slpsoftware/<env>/releases
ls -1t # confirm which directory is the previous, working release
ln -sfn ~/apps/slpsoftware/<env>/releases/<previous-timestamp> ~/apps/slpsoftware/<env>/current
systemctl --user restart slpsoftware-<env>.service
curl -f https://<env-domain>/health # confirm the rollback itself is healthy
This is the same atomic-switch primitive the deploy workflow itself uses — pointing it backward
instead of forward. wwwroot/web/ is untouched either way, since it was never part of the switched
directory to begin with (FR-08).
Rebuild-and-Redeploy Rollback (Older Than One Release Back)
If the defect predates the retained previous release, redeploy an earlier commit through the normal pipeline:
git revertor check out the last-known-good commit on a branch- Push to
master(test) or runworkflow_dispatchwithdeploy_production: true(production) — the same gates and deploy sequence run as any other deploy - This only works because migrations are required to be forward-compatible and non-destructive (D-26) — redeploying an older commit's code against a database that has since had newer migrations applied must not break. If a migration since the target commit was destructive, this path is not safe and the database backup (§ below) is the actual recovery route instead
Database Rollback
A backup is taken before every production deploy (operations/deployment/deployment-instructions.md
§ 4, invoked by deploy-scp.yaml when run_db_backup: true). To restore:
gunzip -c <path-to-backup>.sql.gz | mariadb -h <server> -u <user> -p SlpSoftwareProduction
Restoring a database backup and rolling back the application release are independent actions — decide based on the actual failure whether one, the other, or both are needed. Rolling back the app without restoring the database is usually sufficient (migrations are non-destructive by design); restoring the database without rolling back the app should be rare and deliberate.
What Is Never Part of a Rollback
wwwroot/web/(the customer's website) — structurally outside every release directory; no rollback action should ever touch it- The Data Protection key ring — lives in the database, not the release directory; rolling back the app release does not affect it
- Gitea Actions variables/secrets — these describe the target, not a specific release; nothing about them changes during a rollback