fix(clickhouse): improve latest keys used queries for high volume (150M +) #4959
fix(clickhouse): improve latest keys used queries for high volume (150M +) #4959
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
1 Skipped Deployment
|
|
Note Reviews pausedIt looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughAdds a ClickHouse AggregatingMergeTree table and materialized view for per-key latest verification, a client flag to choose MV vs time-frame lookup, refactors queries to use PREWHERE/WHERE separation, and updates TRPC and client hooks to pass and respect the new flag. Changes
Sequence Diagram(s)sequenceDiagram
participant Client as Dashboard Client
participant TRPC as TRPC Router
participant CH as ClickHouse
participant MV as Materialized View
participant Raw as Raw Verifications
Client->>TRPC: queryKeysOverviewLogs(useTimeFrameFilter, filters)
TRPC->>CH: Execute SQL (PREWHERE workspace_id,time + WHERE other filters)
Note over CH: top_keys CTE chooses source
Note over CH: - MV path reads `key_last_used_v1` (populated by MV)
Note over CH: - Time-frame path computes from hourly + raw tables
Raw->>MV: INSERTs into `key_verifications_raw_v2`
MV->>CH: Aggregate inserts into `key_last_used_v1`
CH->>CH: Compute counts, outcome distributions, join with top_keys
CH->>TRPC: Return paginated top keys with last_time, request_id, tags, counts
TRPC->>Client: Respond with transformed results (outcome_counts object)
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing touches🧪 Generate unit tests (beta)
Comment |
web/apps/dashboard/lib/trpc/routers/api/keys/query-overview-logs/index.ts
Show resolved
Hide resolved
perkinsjr
left a comment
There was a problem hiding this comment.
This seems to work with a large amount of data.
Will let someone like Andreas comment on the SQL implementation.
👍
There was a problem hiding this comment.
Actionable comments posted: 4
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
web/internal/clickhouse/src/logs.ts (1)
84-143:⚠️ Potential issue | 🟠 MajorNormalize nullable array parameters to empty arrays before executing the ClickHouse query.
The Zod schema allows
nullforrequestIds,hosts,excludeHosts,methods, andstatusCodes(all defined as.nullable()). However, ClickHouse does not supportNullable(Array(T))types—it will reject the parameter binding at runtime ifnullis passed. The current code directly spreadsargsintoparameterswithout normalization, so anynullvalue will cause a type mismatch error.Normalize these parameters to empty arrays before query execution. The SQL pattern
length({param: Array(...)}) > 0is correct for detecting active filters; it just requires thatnullis replaced with[].Suggested normalization
- const parameters: Record<string, any> = { ...args }; + const parameters: Record<string, any> = { + ...args, + requestIds: args.requestIds ?? [], + hosts: args.hosts ?? [], + excludeHosts: args.excludeHosts ?? [], + methods: args.methods ?? [], + statusCodes: args.statusCodes ?? [], + };
🤖 Fix all issues with AI agents
In `@pkg/clickhouse/migrations/20260129000000.sql`:
- Around line 11-13: The ORDER BY for the AggregatingMergeTree is incorrect:
change the ORDER BY clause that currently lists (`workspace_id`, `key_space_id`,
`key_id`, `time`) so it exactly matches the materialized view's GROUP BY
(`workspace_id`, `key_space_id`, `key_id`, `identity_id`); remove `time` (a
SimpleAggregateFunction) from ORDER BY and include `identity_id` instead so the
AggregatingMergeTree can merge/aggregate rows correctly.
In `@pkg/clickhouse/schema/024_keys_last_used_v1.sql`:
- Around line 9-20: The AggregatingMergeTree table `keys_last_used_v1` currently
orders by (`workspace_id`, `key_space_id`, `key_id`) which allows rows with
different `identity_id` to be merged, corrupting the SimpleAggregateFunction
results; update the table definition so the ORDER BY includes `identity_id`
(i.e., ORDER BY (`workspace_id`, `key_space_id`, `key_id`, `identity_id`)) to
ensure rows are only merged when the identity matches and preserve correct "last
used" aggregation for the `time`, `request_id`, `outcome`, and `tags` columns.
In `@web/internal/clickhouse/src/keys/keys.ts`:
- Around line 262-279: The top_keys CTE is incorrectly filtering using the
global last_time from the materialized view keys_last_used_v1 (via max(time) as
last_time), which excludes keys that were active inside the requested historical
window but had later activity; change the aggregation to compute a time-bound
per-hour/per-record max using a conditional aggregate (e.g., replace max(time)
as last_time with a maxIf(time, time BETWEEN {startTime: UInt64} AND {endTime:
UInt64}) or equivalent) and use that conditional value in the HAVING/ORDER
clauses so top_keys correctly reflects activity within the requested
startTime/endTime range; update any references to last_time, last_request_id,
and last_tags in the top_keys CTE to use corresponding time-bound aggregates
(e.g., anyLast* variants scoped to the same time condition) so the CTE no longer
relies on the global materialized-view timestamp.
- Around line 281-349: The query currently returns keys from top_keys even when
outcome/tag filters yield zero events; fix this by excluding zero-count keys
when filters are active: when either (${outcomeCondition}) or (${tagConditions})
is non-empty, change the final FROM to join only keys that have counts (replace
"FROM top_keys t" with "FROM top_keys t INNER JOIN aggregated_counts a ON
t.key_id = a.key_id" and use a.valid_count/a.error_count directly instead of
COALESCE), otherwise keep the original LEFT behavior; alternatively implement
the exclusion in aggregated_counts using HAVING sum(count) > 0 when filters are
applied so keys with zero matching events are omitted.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Fix all issues with AI agents
In `@web/internal/clickhouse/src/keys/keys.ts`:
- Around line 249-257: The linter flags unnecessary template literals in the
pagination cursor build: update the cursorCondition assignment in the block that
checks args.cursorTime (the code manipulating cursorCondition based on
timeDirection) to use regular string literals instead of backtick template
strings—replace `AND t.last_time > {cursorTime: Nullable(UInt64)}` and `AND
t.last_time < {cursorTime: Nullable(UInt64)}` with normal quoted strings so
cursorCondition is set with plain string values.
- Around line 316-335: The original topKeysCTE path (used when
useTimeFrameFilter is false) is missing the cursor pagination filter: update the
topKeysCTE that queries default.keys_last_used_v1 (the block that defines
top_keys AS ...) to alias the table (e.g. AS t) and inject the existing
cursorCondition into its WHERE clause when args.cursorTime is present so
pagination uses t.last_time (or the same column name used by cursorCondition)
and respects timeDirection; ensure you preserve keyIdConditions, timeDirection
and LIMIT {limit: Int} and do not add a GROUP BY.
- Around line 398-419: When useTimeFrameFilter=false the original path leaves
keys from top_keys that have no matching aggregated_counts (producing zero
counts via LEFT JOIN+COALESCE) when outcome/tag filters are active; change the
original logic to mirror the new path by either (A) making the join between
top_keys and aggregated_counts (and/or outcome_counts) an INNER JOIN in the
original branch (e.g., in the keys_for_pagination/top_keys selection) so only
keys with matching events remain, or (B) add a HAVING clause on the aggregated
counts (e.g., HAVING COALESCE(a.valid_count,0)+COALESCE(a.error_count,0) > 0)
before ordering/pagination; update references to keys_with_usage, top_keys,
aggregated_counts, hourly_counts and recent_counts accordingly.
c4f4114 to
a41abd9
Compare
There was a problem hiding this comment.
Actionable comments posted: 1
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
web/internal/clickhouse/src/logs.ts (1)
460-460:⚠️ Potential issue | 🔴 CriticalMissing
INTERVALS.threeDaysdefinition causes runtime error.
getThreeDayLogsTimeseriesreferencesINTERVALS.threeDays, but this key doesn't exist in theINTERVALSobject (lines 227-293). This will cause a runtime error when invoked.🐛 Proposed fix: Add the missing interval definition
day: { table: "default.api_requests_per_day_v2", step: "DAY", stepSize: 1, }, + threeDays: { + table: "default.api_requests_per_day_v2", + step: "DAYS", + stepSize: 3, + }, week: { table: "default.api_requests_per_day_v2", step: "DAYS", stepSize: 7, },
🤖 Fix all issues with AI agents
In `@web/internal/clickhouse/src/keys/keys.ts`:
- Around line 396-417: The query returns keys with both valid_count and
error_count equal to 0; update the main SELECT that builds results from
top_keys/aggregated_counts/outcome_counts to filter these out at the SQL level
by adding a HAVING clause (e.g., HAVING valid_count > 0 OR error_count > 0)
after the GROUP BY but before ORDER BY (${orderByClause}), so top_keys rows with
zero total requests are excluded for the rolling-window path; ensure the change
targets the query that defines top_keys / aggregated_counts and preserves the
existing COALESCE semantics for valid_count and error_count.
🧹 Nitpick comments (4)
web/internal/clickhouse/src/logs.ts (1)
47-48: Coding guideline violation:anytype usage.The
Record<string, any>type violates the coding guidelines which state "Never compromise type safety: Noany". Consider using a more specific type.♻️ Suggested refactor
- // biome-ignore lint/suspicious/noExplicitAny: Safe to use any here - const parameters: Record<string, any> = { ...args }; + const parameters: Record<string, string | number | null | Array<string | number>> = { ...args };As per coding guidelines: "Never compromise type safety: No
any, no!(non-null assertion), noas Type"web/apps/dashboard/lib/trpc/routers/api/keys/query-overview-logs/index.ts (1)
46-57: Inconsistent nullish handling between ClickHouse and database queries.Lines 56-57 correctly use
??(nullish coalescing) fornamesandidentitiespassed to ClickHouse, but lines 84-85 still use||(logical OR) for the same fields passed toqueryApiKeys. This inconsistency could cause different behavior for empty arrays.♻️ Suggested fix for consistency
const { keys } = await queryApiKeys({ apiId: input.apiId, workspaceId: ctx.workspace.id, keyIds: keyIdsFromLogs.map((id) => ({ operator: "is", value: id })), - names: input.names || null, - identities: input.identities || null, + names: input.names ?? null, + identities: input.identities ?? null, });web/internal/clickhouse/src/keys/keys.ts (2)
281-282: Redundant time filter condition.Line 281 (
AND time >= {startTime: UInt64}) is redundant since line 282 already usesAND time BETWEEN {startTime: UInt64} AND {endTime: UInt64}, which includes the>= startTimecheck.♻️ Remove redundant condition
WHERE workspace_id = {workspaceId: String} AND key_space_id = {keyspaceId: String} AND (${keyIdConditions}) - AND time >= {startTime: UInt64} AND time BETWEEN {startTime: UInt64} AND {endTime: UInt64}
258-263: Verify the rolling window detection threshold.The 5-minute threshold (
now - 5 * 60 * 1000) determines whether to use the fast MV path vs. the accurate time-frame path. This assumes queries withendTimewithin 5 minutes of now are "rolling" queries that can use the MV's global latest data.Consider documenting this threshold or making it configurable, as it directly affects query accuracy vs. performance trade-offs.
…ble and mv for latest keys used
446a512 to
3bafd09
Compare
…0M +) (#4959) * fix(clickhouse): improve clickhouse query for key logs and add new table and mv for latest keys used * fix valid/error count = 0 scenario * remove identity_id from order by * wrap identity_id with aggregating function since its removed from the order key --------- Co-authored-by: Flo <53355483+Flo4604@users.noreply.github.com>
* test keys table * re org and exports * error fix * Apos * chore: remove deployment breadcrumbs (#5019) * fix: cleanup project side nav * feat: simplify deployment overview page only show build logs until it's built, then show domains and network * chore: clean up nav * fix(clickhouse): improve latest keys used queries for high volume (150M +) (#4959) * fix(clickhouse): improve clickhouse query for key logs and add new table and mv for latest keys used * fix valid/error count = 0 scenario * remove identity_id from order by * wrap identity_id with aggregating function since its removed from the order key --------- Co-authored-by: Flo <53355483+Flo4604@users.noreply.github.com> * fix: domain refetch and promotion disable rule (#5013) * fix: domain refetch and promotion disable rule * fix: regression --------- Co-authored-by: Andreas Thomas <dev@chronark.com> * refactor: move custom domains to tanstack db (#5017) * refactor: move custom domains to tanstack db * fix: comment * fix: delete mutation * remove: unnecessary query * remove agent (#5021) * remove agent * remove agent * chore: vault in dashboard (#5023) * remove agent * remove agent * use vault in dashboard * remove * project domain (#5022) * fix: cleanup project side nav * feat: simplify deployment overview page only show build logs until it's built, then show domains and network * chore: clean up nav * feat: add per-project sticky domain and only display that * chore: use vault in api (#5024) * chore: use vault in api * chore: use vault in api * fix harness * use memory test * vault container go start * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: Make GH callback dynamic (#5029) * dunno * nextjs should allow a setting that says dynamic * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * allow longer timeouts (#5032) * docs: add ratelimit.unkey.com benchmark links to ratelimiting docs Add references to real-time performance benchmarks in: - introduction.mdx: new 'Performance at scale' accordion - modes.mdx: link after latency claim Presents benchmarks as capability demonstration rather than comparison. * docs: add description to cache store interface page (#5037) Add missing SEO description to frontmatter Generated-By: mintlify-agent Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com> Co-authored-by: Andreas Thomas <dev@chronark.com> * docs: remove orphaned SDK documentation (#5033) Remove Spring Boot Java, Rust, and Elixir SDK docs that are not linked in navigation and appear to be outdated/unmaintained. Generated-By: mintlify-agent Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com> Co-authored-by: Andreas Thomas <dev@chronark.com> * No data * add bg * rework release (#5044) * rework release * rework release * feat: generate rpc wrappers (#5028) * feat: generate rpc wrappers * bazel happyier * more changes * more changes * move path * delete old files (#5043) * fix: rabbit comments --------- Co-authored-by: Oz <21091016+ogzhanolguncu@users.noreply.github.com> * feat/gossip (#5015) * add a gossip implementation * add gossip to sentinel/frontline * add message muxing * sentinel fun * cleansings * cleansings * cleansings * cleansings * use oneof * fix bazel happiness * do some changies * exportoneof * more cool fancy thingx * change gateway choosing * add label * adjjust some more * adjjust some more * fixa test * goodbye kafka * fix: bazel * rename gateway -> ambassador * add docs * fix: rabbit comments * [autofix.ci] apply automated fixes * idfk * more changes * more changes * fix ordering * fix missing files * fix test --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: retry hubble ui (#5056) * fix: wait for cillium policy until CRDs are ready (#5059) * fix: retry cillium policy until CRDs are ready * fix: blocks until all system pods are ready * deployment build screen v1 (#5042) * fix: cleanup project side nav * feat: simplify deployment overview page only show build logs until it's built, then show domains and network * feat: new build screen for ongoing deployments * fix: table column typo * fix: update copy to remove mention of analytics deletion (#5067) * fix typo (#5039) * rfc: sentinel middlewares (#5041) * fix: cleanup project side nav * feat: simplify deployment overview page only show build logs until it's built, then show domains and network * feat: middleware rfc * Update svc/sentinel/proto/buf.gen.ts.yaml Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Flo <53355483+Flo4604@users.noreply.github.com> * feat: config files (#5045) * fix: cleanup project side nav * feat: simplify deployment overview page only show build logs until it's built, then show domains and network * feat: add pkg/config for struct-tag-driven TOML/YAML/JSON configuration Introduces a new configuration package that replaces environment variable based configuration with file-based config. Features: - Load and validate config from TOML, YAML, or JSON files - Struct tag driven: required, default, min/max, oneof, nonempty - Environment variable expansion (${VAR} and ${VAR:-default}) - JSON Schema generation for editor autocompletion - Collects all validation errors instead of failing on first - Custom Validator interface for cross-field checks Also adds cmd/generate-config-docs for generating MDX documentation from Go struct tags, and a Makefile target 'config-docs'. Amp-Thread-ID: https://ampcode.com/threads/T-019c672a-0e8e-7138-b0ab-27cdbeaca7ba Co-authored-by: Amp <amp@ampcode.com> * remove gen * clean up * feat(api): migrate API service to file-based TOML config (#5046) * feat(api): migrate API service to file-based config Migrate the API service from environment variables to TOML file-based configuration using pkg/config. Replaces all UNKEY_* env vars with a structured api.toml config file. Changes: - Rewrite svc/api/config.go with tagged Config struct - Update svc/api/run.go to use new config fields - Update cmd/api/main.go to accept --config flag - Add dev/config/api.toml for docker-compose - Update dev/k8s/manifests/api.yaml with ConfigMap - Regenerate config docs from struct tags Amp-Thread-ID: https://ampcode.com/threads/T-019c672a-0e8e-7138-b0ab-27cdbeaca7ba Co-authored-by: Amp <amp@ampcode.com> * feat(vault): migrate Vault service to file-based TOML config (#5047) * feat(vault): migrate Vault service to file-based config Migrate the Vault service from environment variables to TOML file-based configuration using pkg/config. Changes: - Rewrite svc/vault/config.go with tagged Config struct - Update svc/vault/run.go to use new config fields - Update cmd/vault/main.go to accept --config flag - Add dev/config/vault.toml for docker-compose - Update dev/k8s/manifests/vault.yaml with ConfigMap - Remove UNKEY_* env vars from docker-compose and k8s Amp-Thread-ID: https://ampcode.com/threads/T-019c672a-0e8e-7138-b0ab-27cdbeaca7ba Co-authored-by: Amp <amp@ampcode.com> * feat(ctrl): migrate Ctrl API and Worker to file-based TOML config (#5048) * feat(ctrl): migrate Ctrl API and Worker services to file-based config Migrate both ctrl-api and ctrl-worker from environment variables to TOML file-based configuration using pkg/config. Changes: - Rewrite svc/ctrl/api/config.go and svc/ctrl/worker/config.go - Update run.go files to use new config fields - Update cmd/ctrl/api.go and worker.go to accept --config flag - Add dev/config/ctrl-api.toml and ctrl-worker.toml - Update dev/k8s/manifests/ctrl-api.yaml and ctrl-worker.yaml with ConfigMaps - Remove UNKEY_* env vars from docker-compose and k8s manifests * feat(krane): migrate Krane service to file-based TOML config (#5049) * feat(krane): migrate Krane service to file-based config Migrate the Krane container orchestrator from environment variables to TOML file-based configuration using pkg/config. Changes: - Rewrite svc/krane/config.go with tagged Config struct - Update svc/krane/run.go to use new config fields - Update cmd/krane/main.go to accept --config flag - Add dev/config/krane.toml for docker-compose - Update dev/k8s/manifests/krane.yaml with ConfigMap - Remove UNKEY_* env vars from docker-compose and k8s Amp-Thread-ID: https://ampcode.com/threads/T-019c672a-0e8e-7138-b0ab-27cdbeaca7ba Co-authored-by: Amp <amp@ampcode.com> * feat(frontline): migrate Frontline service to file-based TOML config (#5050) * feat(frontline): migrate Frontline service to file-based config Migrate the Frontline reverse proxy from environment variables to TOML file-based configuration using pkg/config. Changes: - Rewrite svc/frontline/config.go with tagged Config struct - Update svc/frontline/run.go to use new config fields - Update cmd/frontline/main.go to accept --config flag - Update dev/k8s/manifests/frontline.yaml with ConfigMap - Remove UNKEY_* env vars from k8s manifest Amp-Thread-ID: https://ampcode.com/threads/T-019c672a-0e8e-7138-b0ab-27cdbeaca7ba Co-authored-by: Amp <amp@ampcode.com> * feat(preflight): migrate Preflight service to file-based TOML config (#5051) * feat(preflight): migrate Preflight service to file-based config Migrate the Preflight webhook admission controller from environment variables to TOML file-based configuration using pkg/config. Changes: - Rewrite svc/preflight/config.go with tagged Config struct - Update svc/preflight/run.go to use new config fields - Update cmd/preflight/main.go to accept --config flag - Update dev/k8s/manifests/preflight.yaml with ConfigMap - Remove UNKEY_* env vars from k8s manifest Amp-Thread-ID: https://ampcode.com/threads/T-019c672a-0e8e-7138-b0ab-27cdbeaca7ba Co-authored-by: Amp <amp@ampcode.com> * feat(sentinel): migrate Sentinel service to file-based config (#5052) Migrate the Sentinel sidecar from environment variables to TOML file-based configuration using pkg/config. This is the final service migration in the config stack. Changes: - Rewrite svc/sentinel/config.go with tagged Config struct - Update svc/sentinel/run.go to use new config fields - Update cmd/sentinel/main.go to accept --config flag - Update dev/docker-compose.yaml: replace env vars with TOML volume mounts for all migrated services (api, vault, krane, ctrl-api, ctrl-worker) - Minor formatting fix in pkg/db generated code --------- Co-authored-by: Amp <amp@ampcode.com> --------- Co-authored-by: Amp <amp@ampcode.com> --------- Co-authored-by: Amp <amp@ampcode.com> --------- Co-authored-by: Amp <amp@ampcode.com> --------- Co-authored-by: Amp <amp@ampcode.com> --------- Co-authored-by: Amp <amp@ampcode.com> * fix: bad config * remove unnecessary tls config for ctrl api * fix: error * fix: do not log config content * ix: remove kafka * fix: replica * fix: return err * fix: only overwrite frontline id if missing * fix: observability * fix: otel * fix: redundant config * fix: reuse tls * fix: consolidate * fix: use shared configs * fix: config * fix: something * Update pkg/config/common.go Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix: vault startup * fix: instanceid * fix: vault config * fix: make configs required * fix: everything works again --------- Co-authored-by: Amp <amp@ampcode.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * clean deployment url label (#4976) * clean deployment url * fix conversion error and maintain single source of truth --------- Co-authored-by: Andreas Thomas <dev@chronark.com> Co-authored-by: Flo <53355483+Flo4604@users.noreply.github.com> * feat: New deploy settings (#5073) * feat: add github section * feat: Add icons * feat: add new sections * feat: add settingsgroup * feat: add region selection * feat: add instances * feat: add memory and cpu section * feat: add sections * feat: add health check * feat: add scaling * fix: get rid of redundant prop * refactor: Add toasts to mutations * refactor: rename component * feat: add port section * feat: fix overlapping borders * refactor: fix healthcheck tRPC * feat: add command section * feat: add env section * fix: finalize env-vars * refactor: finalize * feat: Add custom domains * fix: overflwo * feat: make tRPC route for each mutation * fix: displayValue styles * refactor: tidy * fix: revert accidental changes * feat: add cname table * fix: github styling issues * refactor: tidy * refactor: rename * fix: linter * fix: dynamic form issue * feat: allow env selection * chore: tidy * fix: use same chevron * fix: use certmanager if availiable otherwise certfile (#5076) * fix: use certmanager if availiable otherwise certfile * feat: make tls enabled by default now you need to explicitely pass tls.disabled=true if not, we fail during startup. also renamed some port vars to make it obvious what they are used for * chore: log candidates for easier debugging * fix: use static certs first --------- Co-authored-by: chronark <dev@chronark.com> * feat: sentinel key verification middleware (#5079) * feat: key-sentinel-middleware * fix error pages (#5083) * fix error pages * remove test * move some files * Update svc/frontline/internal/errorpage/error.go.tmpl Co-authored-by: Andreas Thomas <dev@chronark.com> * [autofix.ci] apply automated fixes --------- Co-authored-by: Andreas Thomas <dev@chronark.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * add rl headers. * feat: new ui and fixed a bunch of stuff * Update svc/sentinel/engine/match.go Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix: coderabbit --------- Co-authored-by: Andreas Thomas <dev@chronark.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * clean up after sentinel middleware (#5088) * feat: key-sentinel-middleware * fix error pages (#5083) * fix error pages * remove test * move some files * Update svc/frontline/internal/errorpage/error.go.tmpl Co-authored-by: Andreas Thomas <dev@chronark.com> * [autofix.ci] apply automated fixes --------- Co-authored-by: Andreas Thomas <dev@chronark.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * add rl headers. * feat: new ui and fixed a bunch of stuff * Update svc/sentinel/engine/match.go Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix: coderabbit * chore: clean up old columns * fix: db --------- Co-authored-by: Flo <flo@unkey.com> Co-authored-by: Flo <53355483+Flo4604@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix proto type (#5093) * fix: cleanup project side nav * feat: simplify deployment overview page only show build logs until it's built, then show domains and network * fix: runtime exception due to gaslighting type * fix: Modals with combo box work again (#5002) * chore: remove chproxy routes (#5101) * chore: remove chproxy routes * refactor: move prometheus metrics to scoped packages (#5102) * remove the hand holding (#5108) * feat: gossip metrics (#5107) * fix: Make identity slugs copyable (#5100) * fix: make me copy * Update web/apps/dashboard/app/(app)/[workspaceSlug]/authorization/permissions/components/table/components/assigned-items-cell.tsx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * refactor: useDeployment hook usage (#5086) * refactor: useDeployment hook usage * fix: remove redundant check * feat: i need more metrics (#5115) * docs: Python and Go examples (#5058) * Add Python and Go SDK documentation - Add Go quickstart guide with stdlib, Gin, and Echo examples - Add Python quickstart guide with FastAPI, Flask, Django - Add Go cookbook: stdlib, Gin, Echo middleware recipes - Add Python cookbook: FastAPI rate limiting recipe All content uses Unkey v2 API only. * Add final Python cookbook recipe and 5-minutes guide * Update docs.json sidebar navigation - Add Go and Python quickstart guides to Framework Guides - Add Go and Python cookbook recipes to Recipes section - Remove duplicate 5-minutes quickstart file * Add Go examples to quickstart and reorganize cookbook by language - Add Go code examples to /quickstart/quickstart.mdx for key creation and verification - Reorganize cookbook recipes into subsections: TypeScript, Go, Python, General - Keep existing TypeScript and Python examples in quickstart * Update cookbook index with new Go and Python recipes * Fix code issues in Go and Python documentation - Fix int to string conversion in go-gin-middleware (use strconv) - Fix middleware composition in go-stdlib-middleware - Fix wait calculation in python-fastapi-ratelimit (use total_seconds) - Fix headers attachment in python-fastapi-ratelimit (use JSONResponse) - Fix nil pointer dereference in quickstart/go - Fix unsafe type assertion in quickstart/go * Fix async/sync issue and nil pointer in quickstart docs - Use verify_key_async in Python async route - Add nil check for result.Code in Go quickstart * Fix more code issues in documentation - Fix GetUnkeyResult type assertion in go-gin-middleware - Fix imports in python-fastapi-ratelimit (add JSONResponse, remove unused timedelta) - Update basic rate limit example to use async API with context manager - Add missing os import in Django settings snippet * Fix missing os import in python-flask-auth.mdx * Fix unsafe type assertions in Go middleware docs - Fix RequirePermission in go-echo-middleware with safe type assertion - Fix GetUnkeyResult in go-echo-middleware with safe type assertion - Fix RequirePermission in go-gin-middleware with safe type assertion * Fix error handling in Python docs - replace ApiError with UnkeyError * Update legacy analytics documentation - Replace outdated /apis/features/analytics.mdx with minimal reference page - Remove analytics from API Keys sidebar in docs.json - Add redirect from /apis/features/analytics to /analytics/overview * fix * Update to mint * Fix critical type assertion issues in go-gin-middleware - Store pointer to struct in context (not value) for type assertion compatibility - Add checked type assertion in RequireRole with proper error handling * Add it back * fix the comma * revert * Update go examples * cookbook update * update quickstart * remove analytics page that is redirected * Update web/apps/docs/cookbook/go-echo-middleware.mdx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * Update web/apps/docs/cookbook/go-echo-middleware.mdx Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix --------- Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * fix: deploy quick fixes (#5085) * fix: fetch correct deployment+sentinel * fix: add missing team switcher hover indicator * refactor: use the same empty text * fix: lock network view and fix generate dummy network * fix: safari rendering issue of network * chore: fmt * fix: build * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: Flo <53355483+Flo4604@users.noreply.github.com> Co-authored-by: James P <james@unkey.com> * docs: remove duplicate onboarding page (#5035) Remove quickstart/onboarding/onboarding-api.mdx which duplicates content from the new quickstart. Redirects already exist in docs.json. Generated-By: mintlify-agent Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com> Co-authored-by: Andreas Thomas <dev@chronark.com> Co-authored-by: James P <james@unkey.com> * docs: remove deprecated Vercel integration page (#5034) The Vercel integration is currently not supported. Remove the page to avoid confusing users. Generated-By: mintlify-agent Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com> Co-authored-by: James P <james@unkey.com> * fix: schema cache (#5116) * fix: do background gossip connect (#5119) * fix: do background gossip connect * bazel happy * chore: debug wan failures (#5124) * chore: debug wan failures * add log writer * bazel .......... * bazel .......... * fix: a user cannot click outside of the org selection modal (#5031) * fix: a user cannot click outside of the org selection modal * use errorMessage instead of hard coding messages * restore x closing functionality * fix rabbit, fix flash of empty state * clear last used workspace when auto-selection fails * remove unused conditional --------- Co-authored-by: James P <james@unkey.com> * sentinel prewarm cache (#5071) * fix: cleanup project side nav * feat: simplify deployment overview page only show build logs until it's built, then show domains and network * feat: sentinels prewarm their cache it's not optmized, but pretty neat --------- Co-authored-by: Flo <53355483+Flo4604@users.noreply.github.com> * fix: ignore empty wan (#5122) Co-authored-by: Andreas Thomas <dev@chronark.com> Co-authored-by: James P <james@unkey.com> * docs: move docs (#5125) * refactor: deploy settings tanstack (#5104) * refactor: move them to tanstack * refactor: tidy up * feat: add env provider to decide what env we are on * refactor: tidy * feat: add scroll into view for settingcard * fix: bg * refactor: remove toasts from env-vars * chore: tidy * fix: build * feat: vault bulk en/decrypt (#5127) * feat: vault bulk en/decrypt * oops wrong file * cleanup proto * [autofix.ci] apply automated fixes * cleanup * cleanup --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * feat: trace generated rpc clients (#5128) * feat: trace generated rpc clients * ignore not found * fix: docs generator paths (#5136) * fix: retry memberlist creation (#5134) * fix: retry memberlist creation * remove comments * move to const * fix: Restore filtering on logs (#5138) * Restore filtering on logs Restores filtering on the logs. * [autofix.ci] apply automated fixes * fmt --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * fix: resolve dns to ip (#5139) * fix: resolve dns to ip * rabbit comments * Fix/issue 5132 billing section widths (#5140) * fix: Billing page has inconsistent section widths (#5132) Standardized all SettingCard components to use consistent width classes: - Updated Usage component: contentWidth changed from 'w-full lg:w-[320px]' to 'w-full' - Updated CancelAlert component: contentWidth changed from 'w-full lg:w-[320px]' to 'w-full' - Updated Billing Portal in client.tsx: contentWidth changed from 'w-full lg:w-[320px]' to 'w-full' - Updated CurrentPlanCard component: removed min-w-[200px] from className for consistency All billing sections now use contentWidth='w-full' for consistent layout. Fixes #5132 * Fix billing and setting cards * [autofix.ci] apply automated fixes --------- Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> * pnpm i * No virtualization * pagination footer * sorting and pagination changes * refactor * exports * move data-table to ui * install * fmt * Footer style changes * sorting and pagination changes * sorting and footer loading fix * cleanup * prefetch pages * changes for review comments from rabbit and meg * Ref fix and removed not needed import * [autofix.ci] apply automated fixes * sorting fix and key navigation * review changes mess * minor rabbit changes * Update loading-indicator animation delay * style change on pageination footer * ref type change --------- Co-authored-by: Andreas Thomas <dev@chronark.com> Co-authored-by: Meg Stepp <mcstepp@users.noreply.github.com> Co-authored-by: Flo <53355483+Flo4604@users.noreply.github.com> Co-authored-by: Oz <21091016+ogzhanolguncu@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: James P <james@unkey.com> Co-authored-by: mintlify[bot] <109931778+mintlify[bot]@users.noreply.github.com> Co-authored-by: gui martins <guilhermev2huehue@gmail.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: Amp <amp@ampcode.com> Co-authored-by: Vansh Malhotra <vansh.malhotra439@gmail.com> Co-authored-by: Flo <flo@unkey.com>
What does this PR do?
Fixes query timeouts on the API Requests page for users with extreme verification volumes (150M+ requests every 12 hours).
Problem
Users with high API traffic experienced 30+ second query timeouts when loading the verification logs table. The dashboard became completely unusable for monitoring API activity.
Root Cause: The ClickHouse query scanned all 150M verification rows within the time window, aggregated thousands of keys, then limited to 50 results. This meant 99.5% of aggregation work was wasted on every page load.
Solution
Implemented a materialized view optimization that provides 100-1000x performance improvement:
New Materialized View (keys_last_used_v1): Pre-aggregates the latest verification per key
Dual Query Strategy:
Hybrid Data Source:
Key Difference:
Changes
ClickHouse Schema:
Query Logic:
Dependencies
Required:
No Breaking Changes:
Fixes #4118
Type of change
How should this be tested?
Tested locally and in vercel preview environments with 150M verifications. Local clickhouse docker couldn't do more than 100M, so schema and query logic was tested locally, and time outs with higher volume was tested with clickhouse preview/vercel preview, using sentry errors for timeout confirmation.
Before: Timing out with 75M verification
After: 150M verifications loaded in under half of the timeout duration.
Since we're not backfilling this table, latest key activity should be extremely fast since there's less rows to scan in the new MV.
See screenshots for verification. I updated table names, so CH preview cluster will not have accurate data until populated.
Historical Timeframe:

Last 2 weeks:

Checklist
Required
pnpm buildpnpm fmtmake fmton/godirectoryconsole.logsgit pull origin mainAppreciated