Surface Loose Foreign Keys cleanup backlog in /admin/database_diagnostics

Problem

LooseForeignKeys::CleanupWorker can silently fall behind: when it cannot drain loose_foreign_keys_deleted_records, the queue grows unbounded and nothing surfaces it to an operator. We only find out when a downstream migration breaks (e.g. gitlab-org/gitlab#605940). Existing instrumentation measures worker execution (apdex / error-rate, processed / rescheduled counters) but never queue depth or age.

Observed on a Dedicated tenant: public.projects ~49k pending (oldest 2024-12-23), public.users ~28k (oldest 2025-05-21), while low-fan-out tables drain same-day.

Proposal

Surface the backlog in /admin/database_diagnostics (Admin::DatabaseDiagnosticsController, feature_category :database) — the existing "run a check → cache results → render Vue panel" page used by the collation and schema checkers. (Not /admin/background_migrations, which is only for batched background migrations; LFK cleanup is a cron worker draining a queue.)

Add an LFK-backlog checker worker mirroring Database::CollationCheckerWorker that reports, per connection and parent table, the pending count and oldest-pending age (plus poison / deferred counts), cached for a new panel. This gives self-managed and Dedicated operators a first-class, discoverable signal for the fall-behind condition.

Also emit Prometheus gauges for the same values — loose_foreign_key_pending_records and loose_foreign_key_oldest_pending_age_seconds (labels: connection, parent table) — so growth can be alerted on automatically (e.g. oldest-pending age over a threshold) rather than only observed on demand. The admin page and the metrics share the same backlog query.

Related: #600628, gitlab-org/gitlab#605940.

Edited by Stan Hu