Skip to content

feat: add MySQL/MariaDB engine support with full session and lock tra… - #4

Merged
Fayupable merged 1 commit into
mainfrom
pr-4
Sep 4, 2026
Merged

feat: add MySQL/MariaDB engine support with full session and lock tra…#4
Fayupable merged 1 commit into
mainfrom
pr-4

Conversation

@Fayupable

Copy link
Copy Markdown
Owner

feat: add MySQL/MariaDB engine support with full session and lock tracking

Adds a complete second infrastructure adapter (internal/infrastructure/mysql) implementing every application-layer port the Postgres adapter does, so pgscope can now monitor either engine via PGSCOPE_DB_ENGINE.

Backend:

  • 20 MySQL collectors covering database size, connection saturation, duplicate/unused indexes, idle-in-transaction, top queries, long-running queries, sequence (AUTO_INCREMENT) overflow, pagination warnings, index candidates, prepared transactions, and unlogged (MEMORY) tables
  • Full live session/lock graph support (ISessionCollectorPort): active session listing, blocking-pid relationships, and per-lock detail with a MySQL-specific RECORD vs TABLE lock severity mapping
  • New MySQL-only insight: lock wait detection via sys.innodb_lock_waits, with query text always sourced from normalized DIGEST_TEXT rather than raw PROCESSLIST_INFO to avoid leaking literal query values
  • New GET /api/v1/connection endpoint reporting which engine is active, shaped to extend cleanly to a future multi-connection list
  • main.go now wires MySQL through the same Poller/SSE/history/insights flow Postgres uses, no more feature gap between the two engines

Frontend:

  • Insights responses are normalized so MySQL's unpopulated fields (which serialize as null) never reach a component expecting an array, fixing a real crash on the Health tab
  • New EngineProvider/useEngine context so the UI knows which engine it's talking to
  • Postgres-only cards, tabs, and notices (vacuum health, checkpoints, replication lag/slots, physical I/O, function/trigger cost tracking, pg_stat_statements.track hints) are now hidden when connected to MySQL instead of showing incorrect or misleading instructions
  • New LockWaitCard for the MySQL-only lock wait insight
  • Long health-card warning lists now scroll within a max height instead of distorting the grid
  • Every health-card now shows a short, always-visible plain-language subtitle explaining what it checks, not just when it has a warning

Every collector and adapter was verified against a live MySQL 8 container, not just reviewed for correctness.

What does this PR do

Adds MySQL/MariaDB as a second, fully-supported database engine alongside Postgres. Every insight category, the live session/lock graph, SSE streaming, and history recording now work identically on both engines, selected at startup via PGSCOPE_DB_ENGINE. The frontend also now knows which engine it is talking to and hides Postgres-only advisories instead of showing incorrect instructions against a MySQL database.

Why

Postgres was pgscope's only supported engine so far, and the architecture was already built with hexagonal boundaries specifically to make a second engine possible without touching domain or application. This PR is that proof: MySQL support was written entirely inside a new infrastructure/mysql package, with zero changes to the domain layer's types or logic. It also closes a real gap for anyone running MySQL/MariaDB in production who wanted the same live blocking-graph and advisory insights Postgres users already have.

How was this tested

  • go build ./... && go vet ./... && go test ./... passes
  • npx tsc -b passes (if frontend changed)
  • Manually tested in the browser: logged in against a MySQL-backed server, exercised every Insights tab (Top Queries, Index Candidates, Duplicate/Unused Indexes, Pagination Warnings, Health), triggered real lock contention and long-running-query scenarios via a live mysql:8.0 container to confirm lockWaitWarnings, blockedBy, and per-session lock detail render correctly on the live SSE session/lock graph, and confirmed Postgres-only cards and notices (vacuum health, checkpoints, replication lag/slots, physical I/O, function/trigger cost tracking) are hidden rather than shown incorrectly. golangci-lint run also passes with 0 issues.

Checklist

  • New backend code follows the hexagonal architecture rules in CONTRIBUTING.md (no SQL outside infrastructure/postgres; the new infrastructure/mysql package is the only place with MySQL-specific SQL, and domain/application have zero engine-specific vocabulary in actual types or logic, only in explanatory comments, matching the existing Postgres adapter's own comment style)
  • Any new Insights category's SQL filter/order matches the domain layer's actual judgment criteria (verified against a live MySQL 8 container for every new collector, not just reviewed)
  • This does not add any capability beyond read-only SELECT against statistics views (the MySQL monitoring role needs SELECT and EXECUTE on performance_schema/sys plus global PROCESS, documented in the updated root README; no write capability anywhere)

…cking

Adds a complete second infrastructure adapter (internal/infrastructure/mysql)
implementing every application-layer port the Postgres adapter does, so
pgscope can now monitor either engine via PGSCOPE_DB_ENGINE.

Backend:
- 20 MySQL collectors covering database size, connection saturation,
  duplicate/unused indexes, idle-in-transaction, top queries, long-running
  queries, sequence (AUTO_INCREMENT) overflow, pagination warnings, index
  candidates, prepared transactions, and unlogged (MEMORY) tables
- Full live session/lock graph support (ISessionCollectorPort): active
  session listing, blocking-pid relationships, and per-lock detail with a
  MySQL-specific RECORD vs TABLE lock severity mapping
- New MySQL-only insight: lock wait detection via sys.innodb_lock_waits,
  with query text always sourced from normalized DIGEST_TEXT rather than
  raw PROCESSLIST_INFO to avoid leaking literal query values
- New GET /api/v1/connection endpoint reporting which engine is active,
  shaped to extend cleanly to a future multi-connection list
- main.go now wires MySQL through the same Poller/SSE/history/insights
  flow Postgres uses, no more feature gap between the two engines

Frontend:
- Insights responses are normalized so MySQL's unpopulated fields (which
  serialize as null) never reach a component expecting an array, fixing a
  real crash on the Health tab
- New EngineProvider/useEngine context so the UI knows which engine it's
  talking to
- Postgres-only cards, tabs, and notices (vacuum health, checkpoints,
  replication lag/slots, physical I/O, function/trigger cost tracking,
  pg_stat_statements.track hints) are now hidden when connected to MySQL
  instead of showing incorrect or misleading instructions
- New LockWaitCard for the MySQL-only lock wait insight
- Long health-card warning lists now scroll within a max height instead
  of distorting the grid
- Every health-card now shows a short, always-visible plain-language
  subtitle explaining what it checks, not just when it has a warning

Every collector and adapter was verified against a live MySQL 8 container,
not just reviewed for correctness.
@Fayupable
Fayupable merged commit acdb2a1 into main Sep 4, 2026
2 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant