Perf/high concurrency#794
Open
kenzouno1 wants to merge 15 commits intodecolua:masterfrom
Open
Conversation
Replaces file-level JSON rewrites with indexed SQLite tables backed by
better-sqlite3 (WAL mode). Public API of localDb/usageDb/requestDetailsDb
is preserved so the 35+ consumer sites keep working unchanged. Cloud /
Workers branch still runs on the in-memory lowdb stub.
- add src/lib/sqlite/{schema.sql,connection.js,migrate-from-json.js}
- rewrite localDb.js, usageDb.js, requestDetailsDb.js as SQLite-backed
facades (cloud path untouched)
- promote better-sqlite3 to a regular dependency
- auto-migrate legacy db.json / usage.json / request-details.json on
first boot and rename originals to *.bak (rollback = rename back)
- add scripts/migrate-json-to-sqlite.mjs CLI for explicit / forced
re-runs (supports --force and --data-dir)
- add vitest config + tests/unit/sqlite-migration.test.js
Resolved conflicts in src/lib/localDb.js, requestDetailsDb.js, usageDb.js by keeping SQLite-backed implementations and porting upstream additions: - Added custom_models table to SQLite schema - Ported getCustomModels/addCustomModel/deleteCustomModel to SQLite - Use shared DATA_DIR from src/lib/dataDir.js
- New POST /api/settings/migrate-sqlite endpoint (config only; skips usage/request-details logs to avoid duplicating history rows) - Profile page detects legacy db.json and exposes a Migrate button - Endpoint added to ALWAYS_PROTECTED guard list - exportDb/importDb now include customModels (was silently dropped) - migrate-from-json.js imports customModels from legacy config
better-sqlite3 native bindings aren't supported under Bun. Runtime-detect Bun and load bun:sqlite instead, with a pragma shim and computed module names to dodge webpack static resolution. Node path keeps better-sqlite3.
…lite
Computed module names weren't enough — Next's webpack still tried to
resolve bun:sqlite at runtime. eval('require') returns the runtime's
real require so the bundler never sees either driver name.
Sets DATA_DIR=/app/data so SQLite writes to the chowned dir from the Dockerfile, and mounts a named volume so the DB survives rebuilds.
Match server-side compose: relies on .env for runtime config and lets DATA_DIR default to /app/data via the Dockerfile, removing redundant explicit env.
eval('require') returned undefined inside Next's ESM bundle because the
local createRequire binding gets shadowed/rewritten and there is no
global require in the bundled output. Proper fix: declare bun:sqlite as
a server-side webpack external so the require call survives bundling
and is resolved by the runtime (Bun) at call time.
Next's file tracing only follows JS imports, so schema.sql was missing from the standalone Docker output, crashing on first DB open with ENOENT. Move the DDL into schema.js as an exported string — bundles correctly and removes the need for fs.readFileSync. Drop schema.sql to keep a single source of truth.
getUsageStats referenced an undefined 'history' variable left over from the lowdb→SQLite migration, causing /api/usage/stats to 500. Query the usage_history table for the active period and use those rows for the lastUsed ISO-timestamp overlay.
- 'daily token limit' text -> lock until 00:00 Asia/Saigon (UTC+7) - per-minute patterns (req/min, RPM, requests per minute, etc.) -> lock until next minute boundary - support regex patterns in ERROR_RULES alongside text/status matchers
- auth: remove global selectionMutex; in-memory round-robin rotation with debounced async DB persist; 1s TTL cache for active connections - usageDb: move log.txt to SQLite request_log table with batched async inserts (50 rows or 500ms); cache connection-name lookups; gate verbose PENDING console.log behind PENDING_LOG env; fix pending counter timeout zeroing all concurrent requests - usageDb: batch daily_summary upserts (500ms / 50 entries); keep usage_history insert synchronous for real-time dashboard - tokenRefresh: dedupe in-flight OAuth refresh per connectionId to prevent thundering herd - logger: configurable LOG_LEVEL env (default INFO) - sqlite: tune cache_size, mmap_size, temp_store, wal_autocheckpoint - schema: add request_log table
Replace work.finally(...) with work.then(cleanup, cleanup). The finally chain creates a separate promise that re-throws rejections; with no .catch attached it triggered UnhandledPromiseRejection when an OAuth refresh failed. then(onFulfilled, onRejected) consumes the rejection on the cleanup chain while the original promise still propagates errors to awaiting callers.
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.
optimize for high concurrency