Release safety
Three lifecycle steps (v0.11.0) that harden the deploy around the parts Orbit already automates. All are configured per-environment; none require anything on the host beyond the agent.
Service preflight
On by default. Before anything disruptive happens — before composer, before any maintenance window — the agent reads the new release's app/etc/env.php and TCP-probes every backing service it names:
- the database connection
- Redis session and cache backends
- RabbitMQ (when
queue/amqpis configured)
Each probe is a plain TCP connect with a 3-second timeout — reachability, not authentication. An unreachable service fails the deploy immediately, while the live release is still serving untouched:
Service preflight: probing 4 endpoint(s) from env.php
preflight: database db.internal:3306 reachable (2ms)
preflight: redis-session 10.0.0.5:6379 reachable (1ms)
preflight: redis-cache-default 10.0.0.5:6380 UNREACHABLE — connection refused
preflight: rabbitmq mq.internal:5672 reachable (3ms)
This closes the ugliest failure class in deployment automation: the deploy "succeeds" and the site dies on the first real request because a backing service moved, got firewalled, or changed ports.
Notes:
- Unix-socket endpoints (
/var/run/redis.sock) are skipped, never reported as down. - OpenSearch/Elasticsearch config lives in
core_config_data, notenv.php, so it isn't probed (yet). - If your env.php intentionally names endpoints unreachable from the deploy host, disable the toggle (Environment → Maintenance tab).
Pre-migration database backup
Off by default — opt in. When a deploy will actually run setup:upgrade, the agent takes a dump before the maintenance window opens, so the backup never extends customer-visible downtime:
mysqldump --single-transaction --quick --routines --triggers
→ shared/orbit/backups/db/<version>.sql.gz
- Credentials come from the release's own
env.php; the password travels viaMYSQL_PWD, never the process list. --single-transactionmeans no table locks on InnoDB — the live site keeps serving during the dump.- The newest 3 dumps are kept; older ones are pruned automatically.
- Strict by design: if you enabled the backup and it fails, the deploy fails. A safety net that silently skips is worse than none.
Mind the cost on large databases: the dump is written uncompressed first, then gzipped — budget disk for roughly the DB size, and expect the deploy to take as long as the dump does. Code-only deploys (no migrations) never trigger it.
Restoring is standard MySQL:
gunzip < shared/orbit/backups/db/20260728_141500.sql.gz | mysql -u <user> -p <dbname>
Cache warming
Off unless URLs are configured. After the post-deploy health check passes — never inside a maintenance window, never before rollback detection — the agent GETs each configured URL to prime the full-page cache, OPcache, and block caches before real customers arrive:
Cache warming: 3 URL(s)
warmed https://www.example.com/ — 200 OK in 840ms
warmed https://www.example.com/bestsellers — 200 OK in 620ms
warmed https://www.example.com/checkout/cart — 200 OK in 410ms
Configure in Environment → Operations tab: one absolute URL per line (up to 50), # comments allowed. Warming is strictly best-effort — a failed warm is logged and never fails the deploy.
Good candidates: the homepage, your top category pages, top sellers, CMS landing pages. The first visitor after a deploy then hits a warm FPC instead of paying the cold-cache penalty.
How the three fit the deploy timeline
prep → env.php linked
├─ service preflight ← fails fast, site untouched
build (composer, di:compile, static content)
├─ migration analysis ← predicted hold (Migration Intelligence)
├─ DB backup (opt-in) ← before the window, no downtime added
maintenance window / traffic hold
└─ setup:upgrade → swap → cache:flush
health check
└─ cache warming ← only after the release is verified good