feat: instance meter query#6380
Conversation
This stack of pull requests is managed by jj-ryu. |
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — adds GetInstanceMeterUsage to the ClickHouse client, a billing query that computes deploy meter usage (CPU, memory, egress, disk) from Heimdall checkpoint data using window-function pair integration over adjustable time windows.
- Add
GetInstanceMeterUsagequery withleadInFramepair integration — counter deltas for CPU/egress, gauge × interval for memory/disk, gap-drop at 2 minutes, conservativeleast()for resize safety. - Add
GetInstanceMeterUsageRequest/InstanceMeterUsagetypes withch:struct tags for ClickHouse-go deserialization and Float64 accumulators to prevent int64 overflow on large billing windows. - Add integration tests with real ClickHouse covering counter deltas, outage-gap dropping, restart-boundary isolation, cross-workspace aggregation, and empty-window returning zero rows.
- Add no-op implementation and
Querierinterface entry matching existing patterns.
DeepSeek Pro | 𝕏
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — the delta since the prior pullfrog review (72885e6) is entirely a dashboard settings UI refactor; the GetInstanceMeterUsage ClickHouse query is unchanged. This run reviewed the new @unkey/ui page-layout primitives, the settings-page migration onto them, and the supporting design-app docs.
- Add
@unkey/uipage-layout primitives — newPageContainer(compound,width="default"|"full"propagated via agroup/pagedata attribute),PageBody, thePageHeader*family, and a cva-basedSecondaryNav*family underweb/internal/ui/src/components/page-header/, re-exported from the package index. - Migrate settings pages to the primitives —
general,team,root-keys, andbilling(newbilling-container.tsx) dropWorkspaceNavbar/SettingsShellfor the new layout; a newsettings/layout.tsxrenders theSecondaryNavrail. - Remove the settings sub-nav from the global sidebar —
buildSettingsLinksis deleted fromleaves.tsandcase "settings"insidebar-body.tsxnow returnsbuildWorkspaceSections; deletedsettings/workspace-navbar.tsxandsettings/root-keys/navigation.tsx. - Design app additions —
Previewgains ableedprop,copy-button.tsgains aninlineoption, and a newpatterns/layoutMDX page with example sources documents the primitives.
I verified the load-bearing parts of the refactor: general/page.tsx drops the old workspace && guard but useWorkspaceNavigation() redirects on a null workspace so the access is safe; buildSettingsLinks, WorkspaceNavbar, the settings Navigation, and SettingsShell have no remaining importers in settings; and the billing page never double-wraps BillingContainer since its branches and Client are mutually exclusive.
Claude Opus | 𝕏
b28441c to
1a6504e
Compare
1a6504e to
41aa7df
Compare
3612763 to
9dbb06c
Compare
43936db to
ffa0928
Compare
9dbb06c to
f3f4377
Compare
chronark
left a comment
There was a problem hiding this comment.
just nits really, looks good
ffa0928 to
cf6a201
Compare
f3f4377 to
5c98214
Compare
5c98214 to
a7d8f65
Compare
There was a problem hiding this comment.
✅ No new issues found.
Reviewed changes — the delta since the prior pullfrog review (f3f4377) addresses the two nits from chronark's approval. Both land in pkg/clickhouse and leave the query's billing semantics unchanged.
- Switch the gap constant to a
time.Duration—maxSampleGapMillis int64 = 2*60*1000becomesmaxSampleGap = 2 * time.Minute, converted with.Milliseconds()at the query-param boundary; doc comments updated to drop theMillissuffix. The wire value is still120000ms, so query behavior is identical. - Derive the test anchor from
time.Now()— the integration test'sbasemoves from a hardcoded2026-06-01totime.Now().UTC().Truncate(24h).Add(-24h), keeping inserted rows inside the table's 95-day TTL so ClickHouse can't silently drop the parts before the query runs. This fixes a latent flakiness that would have surfaced once the fixed date aged past the TTL.
Claude Opus | 𝕏
…27.dahlia) Sits at the bottom of the deploy-billing stack so every change above it is written and tested against one SDK/API version. Full breaking-change audit in ENG-2895; this change migrates the code that exists on main: - API version pins -> 2026-05-27.dahlia (lib/stripe.ts, webhook route). - New lib/stripe/invoiceCompat.ts: dual-shape readers for invoice subscription / payment intent / line price / line proration and the per-item subscription period (basil reshaped all of these). Webhook payload shapes follow the ENDPOINT's pinned API version, not the SDK's, so the helpers accept both shapes; after deploy, bump the webhook endpoint to 2026-05-27.dahlia in Stripe, then the legacy halves can be removed. - paymentUtils reads all go through the compat helpers. - isAutomatedBillingRenewal compares only fields present in previous_attributes: basil+ endpoints report renewals as per-item current_period_* diffs, which the old comparison misread as plan changes. - createSubscription pins billing_mode classic (clover defaults new subscriptions to flexible, which itemizes prorations differently). - handleStripeError: v22 exports error classes as values, not types. Stack changes above this one carry their own dahlia-isms: subscribeDeploy billing_mode pin and price.product reads (deploy-subscribe-flows), invoices.createPreview (deploy-project-gate), credit grants (ENG-2870). ENG-2895
cf6a201 to
e045d0b
Compare
a7d8f65 to
bbff1c6
Compare

ClickHouse meter aggregation query
The foundation of the Deploy metering pipeline:
clickhouse.GetInstanceMeterUsagecomputes billable usage from Heimdall checkpoint data (instance_checkpoints) over a time window, returning one row per(workspace, project, environment, resource)for the four meters.last − firstwhen there are no gaps.value × dt, a left-Riemann integral over time.Correctness properties that matter for billing real money:
container_uid(pod UID + restart count). A container restart resets the cgroup/network counters, so we never diff across that boundary.instance_checkpointsview (FINAL applied) so un-merged duplicate inserts can't double-count the integrals.Float64— byte-milliseconds over a month overflowInt64.Exposed on
*clickhouse.Client, theQuerierinterface, and the noop. Units (CPU-seconds, GiB-hours, bytes) are converted to the Stripe meter units by the consumer in the stacked worker PR (#6381).Closes ENG-2863.
How to test
The integration test runs against a real ClickHouse container and covers:
container_uid; totals sum per container life and never diff across the boundary,WorkspaceIDfilter), andThe billing formulas are also documented inline in
pkg/clickhouse/schema/025_instance_checkpoints_v1.sqlfor reference.