By creating this pull request, I grant the project maintainers an unlimited,
perpetual license to use, modify, and redistribute these contributions under any terms they
choose, including both the AGPLv3 and the Fossorial Commercial license terms. I
represent that I have the right to grant this license for all contributed content.
Description
Followup to #3148. As discussed in that thread, this adds a cache-aside to queryUniqueFilterAttributes so that dashboard refreshes within the same minute don't re-run the six selectDistinct queries that populate the audit log filter dropdowns.
Implementation:
Import: regionalCache as cache from #dynamic/lib/cache, matching the dynamic pattern from d1fb2e19.
Cache key: cache:audit-log-facets:v1:{orgId}:{timeStartBucket}:{timeEndBucket}, with timestamps bucketed to 60s boundaries so refresh-within-the-minute hits cache. The v1 segment guards against future shape changes.
Failure isolation: get/set errors are caught and logged via logger.warn; the request never 500s on cache failure.
Combined effect: facet dropdowns become approximate to within ~60s. The six underlying queries are unchanged - the prior bench in #3148 showed their current SELECT DISTINCT LIMIT 501 shape already short-circuits via hash dedup with early exit, so a query rewrite would have regressed.
Branch note: this PR is based on dev, so the file still references primaryLogsDb rather than logsDb. #3148's routing fix landed on main; the changes are independent and will compose cleanly when the branches sync.
How to test?
npx tsc --noEmit — no new errors in the changed file (22 pre-existing errors counted before and after).
Manual smoke on an OSS-SQLite stack: load /[orgId]/settings/logs/request in the dashboard, then refresh within 60 seconds. Confirm filter dropdowns populate identically on both requests and that DB query counters don't double. Avoid testing across minute boundaries — bucket rollover would look like a miss.
SaaS verification (optional): with enable_redis: true, confirm cache.getCurrentBackend() returns "redis" for the facet keys.
🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.
## 📋 Pull Request Information
**Original PR:** https://github.com/fosrl/pangolin/pull/3160
**Author:** [@bishnubista](https://github.com/bishnubista)
**Created:** 5/26/2026
**Status:** 🔄 Open
**Base:** `dev` ← **Head:** `feat-cache-audit-log-facets`
---
### 📝 Commits (1)
- [`648cf1a`](https://github.com/fosrl/pangolin/commit/648cf1a9af5bc3ae4f422ee62215e68e23330a17) feat(audit-logs): cache request audit log filter facets
### 📊 Changes
**1 file changed** (+52 additions, -2 deletions)
<details>
<summary>View changed files</summary>
📝 `server/routers/auditLogs/queryRequestAuditLog.ts` (+52 -2)
</details>
### 📄 Description
## Community Contribution License Agreement
By creating this pull request, I grant the project maintainers an unlimited,
perpetual license to use, modify, and redistribute these contributions under any terms they
choose, including both the AGPLv3 and the Fossorial Commercial license terms. I
represent that I have the right to grant this license for all contributed content.
## Description
Followup to #3148. As discussed in that thread, this adds a cache-aside to `queryUniqueFilterAttributes` so that dashboard refreshes within the same minute don't re-run the six `selectDistinct` queries that populate the audit log filter dropdowns.
Implementation:
- **Import**: `regionalCache as cache` from `#dynamic/lib/cache`, matching the dynamic pattern from d1fb2e19.
- **Cache key**: `cache:audit-log-facets:v1:{orgId}:{timeStartBucket}:{timeEndBucket}`, with timestamps bucketed to 60s boundaries so refresh-within-the-minute hits cache. The `v1` segment guards against future shape changes.
- **TTL**: 60s, per "Lets try 60?" in #3148.
- **Failure isolation**: get/set errors are caught and logged via `logger.warn`; the request never 500s on cache failure.
- **Combined effect**: facet dropdowns become approximate to within ~60s. The six underlying queries are unchanged - the prior bench in #3148 showed their current `SELECT DISTINCT LIMIT 501` shape already short-circuits via hash dedup with early exit, so a query rewrite would have regressed.
Branch note: this PR is based on `dev`, so the file still references `primaryLogsDb` rather than `logsDb`. #3148's routing fix landed on `main`; the changes are independent and will compose cleanly when the branches sync.
## How to test?
1. `npx tsc --noEmit` — no new errors in the changed file (22 pre-existing errors counted before and after).
2. Manual smoke on an OSS-SQLite stack: load `/[orgId]/settings/logs/request` in the dashboard, then refresh within 60 seconds. Confirm filter dropdowns populate identically on both requests and that DB query counters don't double. Avoid testing across minute boundaries — bucket rollover would look like a miss.
3. SaaS verification (optional): with `enable_redis: true`, confirm `cache.getCurrentBackend()` returns `"redis"` for the facet keys.
---
<sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
📋 Pull Request Information
Original PR: https://github.com/fosrl/pangolin/pull/3160
Author: @bishnubista
Created: 5/26/2026
Status: 🔄 Open
Base:
dev← Head:feat-cache-audit-log-facets📝 Commits (1)
648cf1afeat(audit-logs): cache request audit log filter facets📊 Changes
1 file changed (+52 additions, -2 deletions)
View changed files
📝
server/routers/auditLogs/queryRequestAuditLog.ts(+52 -2)📄 Description
Community Contribution License Agreement
By creating this pull request, I grant the project maintainers an unlimited,
perpetual license to use, modify, and redistribute these contributions under any terms they
choose, including both the AGPLv3 and the Fossorial Commercial license terms. I
represent that I have the right to grant this license for all contributed content.
Description
Followup to #3148. As discussed in that thread, this adds a cache-aside to
queryUniqueFilterAttributesso that dashboard refreshes within the same minute don't re-run the sixselectDistinctqueries that populate the audit log filter dropdowns.Implementation:
regionalCache as cachefrom#dynamic/lib/cache, matching the dynamic pattern fromd1fb2e19.cache:audit-log-facets:v1:{orgId}:{timeStartBucket}:{timeEndBucket}, with timestamps bucketed to 60s boundaries so refresh-within-the-minute hits cache. Thev1segment guards against future shape changes.logger.warn; the request never 500s on cache failure.SELECT DISTINCT LIMIT 501shape already short-circuits via hash dedup with early exit, so a query rewrite would have regressed.Branch note: this PR is based on
dev, so the file still referencesprimaryLogsDbrather thanlogsDb. #3148's routing fix landed onmain; the changes are independent and will compose cleanly when the branches sync.How to test?
npx tsc --noEmit— no new errors in the changed file (22 pre-existing errors counted before and after)./[orgId]/settings/logs/requestin the dashboard, then refresh within 60 seconds. Confirm filter dropdowns populate identically on both requests and that DB query counters don't double. Avoid testing across minute boundaries — bucket rollover would look like a miss.enable_redis: true, confirmcache.getCurrentBackend()returns"redis"for the facet keys.🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.