-
Notifications
You must be signed in to change notification settings - Fork 14
Rollback Procedure
Use this runbook when a release causes a critical issue in UAT or Production and you need to return to the previous known good state.
Rule #1: Do not improvise under pressure. Follow this document in order.
Answer these questions before touching anything:
| Question | Answer guides you to |
|---|---|
| Is it frontend-only? (UI broken, API responses are fine) | Frontend-only rollback |
| Is the API returning errors but the database looks intact? | Full application rollback |
| Is data corrupted or missing? |
Database restore from backup — do NOT use migrate:rollback
|
| Did a migration fail mid-run? | Partial migration failure |
| Is the Reverb / WebSocket service down only? | Reverb service restart |
If data is corrupted or a destructive migration ran — go straight to Database restore from backup.
migrate:rollbackcannot recover dropped columns or deleted rows.
git tag --sort=-version:refname | grep -E '^v[0-9]+\.[0-9]+\.[0-9]+$' | head -5The tag immediately before the broken release is your rollback target.
| Broken release | Rollback target |
|---|---|
| v2.71.0 | v2.70.0 |
| v2.70.0 | v2.69.3 |
Use when: UI is broken, GraphQL API responds correctly, database is intact.
- Go to Azure DevOps → Pipelines → GCTalent
- Click Run pipeline
- Set the ref to the previous release tag (e.g.
refs/tags/v2.70.0) - Run — this produces a frontend artifact from the previous tag
- Create a release in Azure DevOps from that artifact and deploy to the affected environment
- Verify the UI is restored
- No database changes needed
Use when: API errors, database is intact, no data corruption.
# From your local repo — compare migration files between tags
git diff v2.70.0..v2.71.0 --name-only -- 'api/database/migrations/*.php'Cross-reference with the Migration rollback safety table on the affected release's wiki page (e.g. v2.71.0) before proceeding.
# Connect to the affected environment's database and check current state first
php artisan migrate:status
# Roll back one step at a time — never use --step=N blindly
php artisan migrate:rollback --step=1
# verify, then continue
php artisan migrate:rollback --step=1
# repeat until back to the target release's migration stateCheck
migrate:statusafter each step. Stop if the release wiki page marks a migration as ❌ or⚠️ — use a database restore instead.
- Go to Azure DevOps → Pipelines → GCTalent
- Run pipeline against the previous release tag
- Deploy the artifact to the affected environment
- API health check responds
- Auth flow works (log in as a test user)
- Core user journey works (job search, application)
- Check application logs for errors
Use when: data is corrupted, a destructive migration ran and data was lost, or migrate:rollback is not safe.
This is the nuclear option. It restores the entire database to a point in time before the failed deployment. All data written after the backup timestamp will be lost.
Prevent new writes while restoring.
- Azure DevOps → take the environment offline or point traffic to a maintenance page
Find the most recent backup taken before the deployment started.
- Backups are managed in Azure — confirm the backup timestamp predates the
php artisan migraterun - Coordinate with your infrastructure team / IAC repo to locate the correct snapshot
Follow Azure Database for PostgreSQL point-in-time restore procedure.
Document the exact restore timestamp and who authorized it here when you run this.
After restore completes:
- Run the Azure DevOps pipeline against the previous release tag
- Deploy — do not run
php artisan migrate(the database is already at the correct schema state) - Run
php artisan migrate:statusto confirm migration state matches the restored tag
-
migrate:statusshows correct state for the rollback tag - Auth flow works
- Spot-check data integrity (recent records present, no corruption)
- Notify stakeholders of the data loss window (time of backup → time of incident)
Use when: php artisan migrate failed partway through, leaving the database in an intermediate state.
php artisan migrate:statusMigrations marked Ran have been applied. Find the last successfully applied migration and the one that failed.
Fix the underlying issue (e.g. null data failing a non-nullable constraint) and re-run:
php artisan migrateSome migrations create a table then fail on a subsequent step. Check for orphaned tables or columns:
-- Check if a table was partially created
SELECT table_name FROM information_schema.tables
WHERE table_schema = 'public'
ORDER BY table_name;Manually clean up the partial state, then re-run or roll back as appropriate.
Use when: WebSocket subscriptions are not working but the rest of the application is fine.
# Restart the Reverb service on the affected environment
php artisan reverb:restart
# Or if managed as a system service
sudo systemctl restart reverbCheck the Reverb logs for the root cause before restarting in production.
- Write an incident note: what broke, what was rolled back, when, who approved
- Add the rollback event to this wiki under the affected release page
- Open a follow-up issue in GitHub for the root cause
- If a database restore was used — document the data loss window and notify affected users if required
- Update the deployment plan for the re-release to address the root cause