Skip to content

v2: db.php drop-in for early-query coverage and zero-overhead observation#32

Open
mrtwebdesign wants to merge 3 commits into
developmentfrom
feat/v2-db-dropin
Open

v2: db.php drop-in for early-query coverage and zero-overhead observation#32
mrtwebdesign wants to merge 3 commits into
developmentfrom
feat/v2-db-dropin

Conversation

@mrtwebdesign
Copy link
Copy Markdown
Contributor

Summary

  • Adds HCQG_DB class (db.php) extending wpdb with conditional backtracing and first-query SET SESSION MAX_EXECUTION_TIME, eliminating the ~10% CPU overhead of SAVEQUERIES at 100% observation and covering pre-init queries (autoloaded options, auth/usermeta, WC session bootstrap)
  • Mu-plugin coordination via dropin_active() — gates logging source, SAVEQUERIES usage, and SET SESSION method so v1 behavior is preserved when the drop-in is absent
  • Dependency guard on mu-plugin startup — returns early with a log warning if any companion class-hcqg-*.php file is missing, preventing fatal errors during partial uploads to live sites
  • README updated with v2 installation instructions (upload order, db.php deployment, Query Monitor conflict notes)
  • 11 new tests covering drop-in detection, v2 logging codepath, and v2 SET SESSION delegation

Status

Not production-ready — needs staging validation before merge:

  • Verify conditional backtracing captures slow queries correctly on a real WooCommerce request
  • Verify SET SESSION is applied before wp_load_alloptions() in enforce mode
  • Confirm no regressions in v1 behavior when db.php is absent
  • Measure before/after CPU overhead at 100% observation on a representative page

Related

🤖 Generated with Claude Code

mrtwebdesign and others added 2 commits May 14, 2026 16:30
Adds HCQG_DB (extends wpdb) for two capabilities the mu-plugin alone
cannot provide: SET SESSION MAX_EXECUTION_TIME at connection time
(covering pre-init queries like wp_load_alloptions), and conditional
backtracing that replaces SAVEQUERIES — dropping 100% observation
overhead from ~10% CPU to near zero.

Mu-plugin coordination: dropin_active() gates three codepaths so the
mu-plugin reads from hcqg_slow_queries when the drop-in is present
and falls back to SAVEQUERIES when it isn't.

Safety: dependency guard on the mu-plugin returns early with a log
warning if any companion class file is missing, preventing fatal
errors during partial uploads.

README updated with v2 installation instructions including upload
order, db.php deployment, and Query Monitor conflict notes.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Adds ?hcqg_test=1 URL param (admin-only) that fires a 6-second
SLEEP query to validate the slow-query logging pipeline end-to-end.

README: quick-test section at top, dependency guard docs, single-file
distribution note for future.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a v2 db.php drop-in path for Hypercart Query Guard, coordinating it with the existing MU-plugin so query observation can avoid SAVEQUERIES overhead and enforcement can begin before init.

Changes:

  • Adds HCQG_DB drop-in with conditional slow-query capture and first-query session timeout handling.
  • Updates MU-plugin coordination for drop-in detection, logging source selection, and session limit delegation.
  • Adds README installation/test guidance and PHPUnit coverage for MU-plugin/drop-in coordination.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 9 comments.

Show a summary per file
File Description
db.php Adds the v2 WordPress database drop-in implementation.
hypercart-query-guard.php Adds dependency guard, drop-in coordination, diagnostic query, and v2 logging/session paths.
README.md Documents quick test flow and v2 drop-in installation/operation.
tests/bootstrap.php Extends stubs for drop-in simulation and logger capture.
tests/DbDropinTest.php Adds tests for drop-in detection, slow-query logging routing, and session delegation.
Comments suppressed due to low confidence (3)

db.php:206

  • When the limit changes from a positive value to 0, this method updates the cached value but does not execute SET SESSION MAX_EXECUTION_TIME = 0. Any session that already received the pre-init/default cap will keep that cap, so callers cannot actually clear the limit for unlimited contexts.
		if ( $limit_ms > 0 ) {
			@mysqli_query( $this->dbh, sprintf( 'SET SESSION MAX_EXECUTION_TIME = %d', $limit_ms ) );
		}

README.md:59

  • This overstates standalone behavior: the drop-in only applies SET SESSION MAX_EXECUTION_TIME in enforce mode, while the documented default mode is observe. Without the mu-plugin and without an explicit enforce constant, standalone installs will not have SET SESSION protection active.
- **db.php present, mu-plugin present** — full v2 behavior. The mu-plugin detects the drop-in and uses it for logging and tiered limit updates.
- **db.php present, mu-plugin absent** — drop-in runs standalone. Conditional backtracing and SET SESSION protection are active, but there is no structured logging, no tiered limits, and no admin-search fallback notice.

db.php:39

  • The comment says compatibility is tested through WordPress 6.8, but the warning ceiling is set to 6.9 and the check only warns when the running version is greater than that. As written, an untested 6.9 install would not emit the compatibility warning.
	// Tested against WordPress 5.5 – 6.8. The override relies on query()
	// returning int|bool and _do_query() being private (not called through
	// the vtable). If core refactors _do_query into a protected method or
	// changes query()'s signature, the assertion below will fire.
	const WP_VERSION_FLOOR   = '5.5';
	const WP_VERSION_CEILING = '6.9';

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread hypercart-query-guard.php Outdated
Comment on lines +929 to +937
// v2 drop-in: update the cached limit and re-apply via raw mysqli.
// This also caches the per-context limit so reconnect/rotation
// re-applies the correct tier instead of the pre-init default.
if ( self::dropin_active() ) {
static $dropin_last_limit = null;
if ( $dropin_last_limit === $limit_ms ) {
return;
}
$wpdb->hcqg_update_limit( $limit_ms );
Comment thread hypercart-query-guard.php
public static function maybe_run_diagnostic_query() {
if ( ! isset( $_GET['hcqg_test'] ) || ! current_user_can( 'manage_options' ) ) {
return;
}
Comment thread db.php
Comment on lines +94 to +96
if ( defined( 'HYPERCART_QUERY_GUARD_WARN_THRESHOLD_MS' ) ) {
$this->hcqg_warn_threshold_s = max( 0, (int) HYPERCART_QUERY_GUARD_WARN_THRESHOLD_MS ) / 1000;
}
Comment thread README.md

## Quick test

Append `?hcqg_test=1` to any URL while logged in as admin. This fires a 6-second `SELECT SLEEP(6)` that triggers the slow-query logging pipeline. Check `debug.log` (or your Hypercart_Logger output) for a `slow_query` event to confirm end-to-end operation.
Comment thread tests/DbDropinTest.php

use PHPUnit\Framework\TestCase;

class DbDropinTest extends TestCase {
Comment thread db.php
Comment on lines +131 to +135
public function query( $query ) {
// Enforce: apply or re-apply SET SESSION on first query / reconnect / rotation.
if ( $this->hcqg_enforce &&
( ! $this->hcqg_session_applied || $this->hcqg_last_dbh !== $this->dbh ) ) {
$this->hcqg_apply_session();
Comment thread db.php
// Tested against WordPress 5.5 – 6.8. The override relies on query()
// returning int|bool and _do_query() being private (not called through
// the vtable). If core refactors _do_query into a protected method or
// changes query()'s signature, the assertion below will fire.
Comment thread hypercart-query-guard.php Outdated
Comment on lines +45 to +47
if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
error_log( '[hypercart_query_guard][error] Missing required file: ' . basename( $hcqg_file ) . ' — plugin disabled.' );
}
Comment thread db.php
exit;
}

class HCQG_DB extends wpdb {
@heymicoo
Copy link
Copy Markdown

With enforce + the new db.php drop-in, the first DB query gets a default 30s query limit before WordPress knows the request type. For Action Scheduler and other contexts that should be unlimited, the plugin never clears that limit, so those jobs can stay capped at 30s (a regression vs v1 without the drop-in). Low risk in observe or without db.php; worth fixing before enforce + v2 on production. Fix: when context is unlimited, explicitly reset the session limit via the drop-in (e.g. hcqg_update_limit(0)).

@mrtwebdesign @noelsaw1

Introduces an optional db.php drop-in that applies SET SESSION MAX_EXECUTION_TIME at connection time, improving coverage for pre-init queries. Updates the Hypercart_Query_Guard to conditionally backtrace slow queries and ensures that unlimited contexts clear the pre-init default. Modifies the architecture documentation to reflect these changes and adds a new test to validate the behavior when the drop-in is active.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@heymicoo
Copy link
Copy Markdown

@mrtwebdesign I added new commit to fix the issue I stated above. *8224b70

@mrtwebdesign
Copy link
Copy Markdown
Contributor Author

@noelsaw1 @heymicoo
That change looks good. Critical for enforce mode on Binoidcbd production. The code would have killed Action Scheduler jobs that should always be unlimited.

  1. Connection time (db.php): Drop-in sets 30s default
  2. init priority 1 (mu-plugin): Detects Action Scheduler context, resolves limit to 0 (unlimited)
  3. Bug: The 0 === $limit_ms → return check ran before the drop-in delegation code, so the function exited without ever telling the drop-in to clear the 30s ceiling

But.. there are some AS jobs that should be killed under some circumstances. That's why I added this feature request:
Feature: consequence-aware query thresholds #33
If the server is under load and we are having performance issues some AS jobs are less important than others. It may also help reduce concurrent AS jobs:
Feature: Priority-based concurrency throttling for Action Scheduler

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.

3 participants