laravel-workkit/CHANGELOG.md

86 lines
4.9 KiB
Markdown
Raw Permalink Normal View History

# Changelog
All notable changes to `laravel-workkit` are documented here. This project
follows [Keep a Changelog](https://keepachangelog.com/) and keeps every release
backward-compatible with the previous minor (see
`PRINCIPLES/laravel-composer-packages.md` § Backward compatibility).
## Unreleased
### Added
- **`workkit:stats`** (+ `StatsService`) — terminal "admin overview": per-Eloquent-model
row counts (fast `information_schema` estimate on MySQL, `--exact` for `COUNT(*)`),
largest tables by size, total database size, and a compact queue + backup summary.
Models are auto-discovered from `app/Models` or `config('workkit.stats.models')`.
`--json` for machine consumption; degrades gracefully on non-MySQL drivers.
- **`workkit:queue:health`** (+ `QueueHealthService`) — per-queue depth / due / delayed /
reserved counts and oldest-due-job age for the database queue driver, failed-jobs
totals (+ last *N* hours), and STALLED-queue detection (due work past
`max_age_minutes` with nothing reserved → worker likely down). Exits non-zero on any
breach for cron/monitoring; thresholds under `config('workkit.queue.*')` with per-queue
depth overrides. `QueueHealthService::evaluate()` is a pure, unit-testable function.
- New config blocks `workkit.stats.*` and `workkit.queue.*` (read with explicit
code-side defaults, so consumers who published an older config are unaffected).
### Added — backups
- **`workkit:db:restore --fresh`** — drops every table + view in the target
before importing, the only reliable fix for a restore failing with
`errno 150` / error `3780` against a dirty or partially-migrated schema. The
wipe is performed via the **same** `mysql` client and database the import
uses (built from the connection's `$cfg`, scoped to `DATABASE()`), so a
`url` DSN / `unix_socket` / read-write split can never make the wipe and the
import target different databases.
- **Pre-restore safety snapshot** — `--fresh` first takes *and verifies* a
snapshot of the current database (named `*.pre-restore.sql.xz.enc`) and
aborts before dropping anything if it can't be written; opt out with
`--no-safety-backup`. On a post-wipe import failure the command prints the
exact `workkit:db:restore --file=<snapshot>` recovery command.
- **`workkit:db:verify`** (+ `workkit:db:backup --verify`) — proves a backup
decrypts with this host's `APP_KEY` and is a complete, non-truncated xz
stream, without touching the database; flags a missing mysqldump completion
marker and compares the on-disk sha256 against the metadata sidecar.
`--all` checks every backup.
- **Metadata sidecar** — `workkit:db:backup` writes a best-effort
`<file>.meta.json` (size, sha256, created_at, cipher params) next to each
backup. Never fails a good backup if it can't be written.
- **`workkit:db:prune-backups --keep-min`** (config
`backup.retention_min_keep`, default 5) — always keeps the N newest backups
regardless of age, so an aggressive `--days` can never leave zero recovery
points. Prune now also removes a backup's sidecar alongside it and sweeps
orphaned sidecars.
- **Restore safeguards** — the source backup is verified before any
destructive step; a dirty (non-empty) target is reported with a `--fresh`
hint; an import that incompatibly fails prints actionable guidance; a
non-trivial backup that imports zero tables is flagged as a possible silent
failure. The confirm line now shows the backup size.
- New public `BackupService` helpers (all additive): `verify()`,
`dropAllTables()`, `countTables()`, `estimateDatabaseBytes()`,
`backupFiles()`, `restoreCandidates()`, `metaPathFor()`, `humanBytes()`,
`runResult()`.
### Changed
- **`BackupService::decryptDecompressImport()` now prepends
`SET FOREIGN_KEY_CHECKS=0;`** to the import stream so a hand-rolled dump
lacking mysqldump's own header still imports into an empty database
regardless of table order. Harmless for mysqldump output (which sets/restores
its own session vars), and the whole import is one short-lived session so the
relaxed check never leaks. This does **not** rescue a restore onto a dirty
schema with incompatible column types — use `--fresh` for that.
- File selection in `restore`/`prune` now ignores `*.meta.json` sidecars while
still finding custom `--out`-named backups (it denies the sidecar suffix
rather than allow-listing one extension). The `restore` auto-pick also skips
`*.pre-restore.*` snapshots so a recovery snapshot of a known-bad database is
never restored by accident.
### Notes
- Existing `BackupService` method signatures and all config keys are unchanged;
new behavior is additive or confined to the new `--fresh` path. New nested
config keys are read with explicit code-side defaults, so a consumer who
published an older `config/workkit.php` is unaffected.
- The README is now backup-documented and brought up to the standard Blax OSS
package skeleton (badges, feature list, Star History).