laravel-workkit/CHANGELOG.md

4.9 KiB

Changelog

All notable changes to laravel-workkit are documented here. This project follows Keep a Changelog 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 sidecarworkkit: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).