feat(query-engine): cache sweep + listLogs skip-index capabilities - #350
Merged
Conversation
… already had The pipe path (list_logs, which the maple CLI uses) has always passed attributeIndexMode and logBodySearchMode. The dashboard's HTTP path compiled the same builder without them, so CLI log search got bloom/tokenbf index acceleration while the dashboard silently full-scanned the same table. Same builder, same data, different plans -- exactly the drift the registry exists to remove, found by diffing the two surfaces against each other. QueryDef gains `capabilityAware`, off by default because resolving capabilities is not free: on BYO ClickHouse it costs a live system.* probe (measured p50 262ms). Managed backends answer from the generated static snapshot, so for them it is free. compile() now receives capabilities as a third argument; without the flag that argument is the BASELINE (all indices assumed absent), so every other def emits byte-identical SQL. listLogs' `settings` callback needed an explicit payload annotation: with a three-parameter compile, TS resolves that callback before it can pin Payload from compile. THIS CHANGES EMITTED SQL for listLogs. The __sql_baseline__ catalog has to be regenerated, and the ClickHouse DESCRIBE sweep re-run, before merge: bun run ch:up && bun run ch:test The catalog already covers all three capability variants (baseline / bloom / text), so the shapes themselves are pre-validated -- what moves is which variant the listLogs entry records. Verified: both packages typecheck. Tests deliberately NOT run locally.
…cket cache Prod measurement of EdgeCacheService.getOrCompute on the org-clickhouse-config bucket, over 1039 reads: hit 597 p50 8ms miss 64 p50 27ms <- includes the actual Postgres read timeout 378 p50 2650ms A cold Postgres read costs 27ms. The ~2.9s that has been attributed to it all along is the cache read being ABANDONED at its 40ms deadline, which happens on 36% of reads. That rate matches the failure mode already documented in edge-cache.ts almost exactly (35.9% measured at 4 reads/request): a cache.match() issued while a sibling branch's warehouse fetch holds a connection slot gets queued and never returns in time. So the fix is ordering, not caching. #343 added warmRoute but only called it from the bucket-cache fill path, and only when the fill split into more than one range. Every other fan-out -- the service bundles, the Cloudflare and PlanetScale panels, listPods, serviceDbQuerySummary -- still issued its config read concurrently with sibling warehouse fetches. Calling warmRoute immediately before each of the 14 Effect.all sites means the cache read happens with an empty connection pool, so it lands in ~8ms; every branch behind it then hits the in-isolate memo for free. On a warm memo the call is a no-op, so it costs nothing when there is nothing to warm. Verified: apps/api typecheck. Tests not run locally by request.
🍁 Maple PR previewNote Preview resources were removed when this pull request closed. Final commit |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two changes, both enabled by the registry. The second one needs your test run before merge — see below.
1. Turn on caching for the 59 uncached queries
This is the payoff of making
cacherequired-but-nullable.Before the registry, caching was opt-in per handler and silence read as "off": 11 of 61 handlers called
cachedDirect; the other 50 were uncached by omission rather than by decision. Migrating them recorded that state ascache: undefined. This turns those markers into actual decisions.serviceOverview,serviceHealthSnapshot,serviceApdex,listLogs. Short enough that a panel never looks frozen, long enough to absorb repeat loads from navigating between tabs of the same service.podFacets,nodeFacets,workloadFacets,cloudflareInfraZoneFacets,listMetrics,metricsSummary. These move on the scale of deploys, not requests, and are UNION fan-outs over wide Map columns.cache: undefinednow means exactly one thing: the query runs inside an outercachedDirectin its handler, so caching it here would double-cache. The seven arespanHierarchy+ its two probes, and the fourserviceOperationsrollup/raw variants.For the probes that's not merely redundant but wrong — they exist to fire only on an outer miss, and caching them would run a probe on every request, which is the cost the probe was added to avoid.
No SQL changes here, so the byte-identical baseline still holds. This only affects whether a compiled query is served from the edge cache.
2.
listLogsgets the skip-index capabilities the CLI already hadThe pipe path (
list_logs, used by themapleCLI) has always passedattributeIndexModeandlogBodySearchMode. The dashboard's HTTP path compiled the same builder without them — so CLI log search got bloom/tokenbf index acceleration while the dashboard silently full-scanned the same table.Same builder, same data, different plans. Exactly the drift the registry exists to remove, and it was found by diffing the two surfaces against each other.
QueryDefgainscapabilityAware, off by default because resolving capabilities isn't free: on BYO ClickHouse it costs a livesystem.*probe (measured p50 262ms). Managed backends answer from the generated static snapshot, so for them it's free.compile()now takes capabilities as a third argument. Without the flag that argument is the baseline (all indices assumed absent), so every other def emits byte-identical SQL.bun run ch:up && bun run ch:testThe
__sql_baseline__catalog has to be regenerated and the DESCRIBE sweep re-run. The catalog already covers all three capability variants (baseline / bloom / text), so the shapes themselves are pre-validated — what moves is which variant thelistLogsentry records.Testing
🤖 Generated with Claude Code
Need help on this PR? Tag
@codesmith-botwith what you need. Autofix is disabled.