fix(replay): repair cleanup and add configurable cache TTL - #1400
Merged
Conversation
Introduce replayCacheTtlMinutes (5-120 min, default 30) as a database-backed system setting controlling how long completed Replay payloads remain reusable in the PostgreSQL durable layer. The Redis hot-layer TTL is capped to the same window so both tiers expire in sync. This replaces the removed REPLAY_COMPLETED_TTL_SECONDS environment variable, moving the durable TTL into the admin-editable settings surface with full validation, i18n labels, API schema, and UI input. Also fix the replay cleanup query to bind the cutoff Date through sql.param for correct PostgreSQL type coercion, and preserve wrapped database error causes in the cleanup scheduler logging.
📝 WalkthroughWalkthrough新增 Replay 缓存 TTL 系统设置,默认值为 30 分钟,范围为 5–120 分钟。配置贯穿数据库、校验、仓储、API、管理界面、本地化文本和 Replay 运行时清理流程。 ChangesReplay 缓存 TTL
Estimated code review effort: 4 (Complex) | ~45 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/lib/validation/schemas.ts (1)
24-28: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win使用
@/路径别名。将此导入改为
@/lib/validation/replay-settings。仓库规则要求 TypeScript 导入使用@/映射到./src/。🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@src/lib/validation/schemas.ts` around lines 24 - 28, Update the replay-settings import in the validation schemas module to use the repository’s `@/` alias, targeting `@/lib/validation/replay-settings` instead of the relative path, while preserving the imported symbols.Source: Coding guidelines
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Nitpick comments:
In `@src/lib/validation/schemas.ts`:
- Around line 24-28: Update the replay-settings import in the validation schemas
module to use the repository’s `@/` alias, targeting
`@/lib/validation/replay-settings` instead of the relative path, while preserving
the imported symbols.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro Plus
Run ID: a6718b1a-6334-46a6-afcc-e064c8c5c79f
📒 Files selected for processing (34)
drizzle/0119_tiresome_banshee.sqldrizzle/meta/0119_snapshot.jsondrizzle/meta/_journal.jsonmessages/en/settings/config.jsonmessages/ja/settings/config.jsonmessages/ru/settings/config.jsonmessages/zh-CN/settings/config.jsonmessages/zh-TW/settings/config.jsonsrc/actions/system-config.tssrc/app/[locale]/settings/config/_components/system-settings-form.tsxsrc/app/[locale]/settings/config/page.tsxsrc/app/api/v1/resources/system/router.tssrc/app/v1/_lib/proxy/replay/replay-store.tssrc/drizzle/schema.tssrc/instrumentation.tssrc/lib/api-client/v1/openapi-types.gen.tssrc/lib/api/v1/schemas/system-config.tssrc/lib/config/env.schema.tssrc/lib/config/system-settings-cache.tssrc/lib/system-settings/proxy-runtime.tssrc/lib/validation/replay-settings.tssrc/lib/validation/schemas.tssrc/repository/_shared/transformers.test.tssrc/repository/_shared/transformers.tssrc/repository/system-config.tssrc/types/system-config.tstests/api/v1/system/system-config.test.tstests/unit/actions/system-config-save.test.tstests/unit/instrumentation-replay-cleanup.test.tstests/unit/proxy/replay-store.test.tstests/unit/proxy/stream-gate-mode-resolution.test.tstests/unit/repository/system-config-degradation-ladder.test.tstests/unit/repository/system-config-update-missing-columns.test.tstests/unit/settings/system-settings-form-replay-cache-toggles.test.tsx
💤 Files with no reviewable changes (1)
- src/lib/config/env.schema.ts
Merged
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.
Summary
replayCacheTtlMinutessystem setting, defaulting to 30 minutes with an inclusive 5-120 minute range.REPLAY_TTL_SECONDSlimit.Root Cause
The cleanup scheduler bound a raw JavaScript
Datein this predicate:That raw SQL path did not select the
expires_attimestamp encoder. postgres.js failed during parameter binding with:Drizzle then wrapped it as
DrizzleQueryError: Failed query. This matches the report that hand-writtenexpires_at < now()SQL succeeds while the application scheduler repeatedly fails, and explains why the previous log did not expose the database-level cause.The fixed query uses:
Behavior
replayCacheTtlMinutes.min(REPLAY_TTL_SECONDS, replayCacheTtlMinutes * 60).REPLAY_CACHE_TTL_INVALIDfor localized UI handling.Validation
DEFAULT 30andNOT NULL.bun run lint: passed.bun run typecheck: passed.bun run openapi:check: passed.bun run build: passed.bun run test: 859 files passed, 2 skipped; 8399 tests passed, 13 skipped; 0 failures.git diff --check origin/dev...HEAD: passed.Production Recovery Note
This PR repairs future scheduler executions, but merging it will not immediately return the historical approximately 7GiB table/TOAST space to the host filesystem. Production recovery should still use a maintenance window: verify that the PostgreSQL backup is restorable, stop the application while keeping PostgreSQL running, confirm Replay is disabled, delete only
expires_at < now()rows in fixed small committed batches with short pauses, and finish withVACUUM (ANALYZE) replay_payloads.The existing scheduler deletes at most 500 rows every 10 minutes, so 32,404 rows require roughly 11 hours in the ideal case. Evaluate
VACUUM FULLor an online rewrite separately only when host-level disk reclamation is required and the locking/operational cost is acceptable.If Node RSS/heap still grows after Replay is disabled and the historical payloads are gone, investigate it as a separate memory issue.
Acceptance