refactor: Business logic and dependencies updates
- 核心服务代码更新 (db, server, auth, proxy) - Agent 相关模块更新 (mindspace, experience) - 前端组件和 hooks 更新 - 数据库 schema 更新 - 依赖版本更新
This commit is contained in:
@@ -13,13 +13,27 @@ export function isDatabaseConfigured() {
|
||||
);
|
||||
}
|
||||
|
||||
// Pool size must scale with peak concurrent agent sessions: each session does
|
||||
// several queries per turn (session node lookup + policy + provider + reconcile).
|
||||
// The historical default of 10 starved at ~30 concurrent sessions. Tune via
|
||||
// MYSQL_POOL_SIZE per portal instance × expected concurrency.
|
||||
function resolvePoolOptions() {
|
||||
const connectionLimit = Math.max(1, Number(process.env.MYSQL_POOL_SIZE ?? 50));
|
||||
// queueLimit caps how many requests wait for a free connection before failing
|
||||
// fast, instead of piling up unboundedly under a connection-starvation storm.
|
||||
const queueLimit = Math.max(0, Number(process.env.MYSQL_POOL_QUEUE_LIMIT ?? 0));
|
||||
return { waitForConnections: true, connectionLimit, queueLimit };
|
||||
}
|
||||
|
||||
export function createDbPool() {
|
||||
if (!isDatabaseConfigured()) {
|
||||
throw new Error('MySQL 未配置,请设置 DATABASE_URL 或 MYSQL_* 环境变量');
|
||||
}
|
||||
|
||||
const poolOptions = resolvePoolOptions();
|
||||
|
||||
if (process.env.DATABASE_URL) {
|
||||
return mysql.createPool(process.env.DATABASE_URL);
|
||||
return mysql.createPool({ uri: process.env.DATABASE_URL, ...poolOptions });
|
||||
}
|
||||
|
||||
return mysql.createPool({
|
||||
@@ -28,8 +42,7 @@ export function createDbPool() {
|
||||
user: process.env.MYSQL_USER ?? 'boot',
|
||||
password: process.env.MYSQL_PASSWORD ?? '',
|
||||
database: process.env.MYSQL_DATABASE ?? 'tkmind',
|
||||
waitForConnections: true,
|
||||
connectionLimit: 10,
|
||||
...poolOptions,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -199,6 +212,26 @@ export async function migrateSchema(pool) {
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
`);
|
||||
|
||||
// Shared experience store (etat C). Keep in sync with schema.sql.
|
||||
await pool.query(`
|
||||
CREATE TABLE IF NOT EXISTS h5_experience (
|
||||
id CHAR(36) PRIMARY KEY,
|
||||
scope VARCHAR(64) NOT NULL DEFAULT 'global',
|
||||
kind VARCHAR(32) NOT NULL DEFAULT 'lesson',
|
||||
title VARCHAR(255) NOT NULL,
|
||||
body MEDIUMTEXT NOT NULL,
|
||||
tags_json JSON NULL,
|
||||
source_session_id VARCHAR(128) NULL,
|
||||
source_user_id CHAR(36) NULL,
|
||||
use_count BIGINT NOT NULL DEFAULT 0,
|
||||
embedding JSON NULL,
|
||||
created_at BIGINT NOT NULL,
|
||||
updated_at BIGINT NOT NULL,
|
||||
KEY idx_h5_experience_scope_updated (scope, updated_at),
|
||||
FULLTEXT KEY ftx_h5_experience (title, body)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci
|
||||
`);
|
||||
|
||||
const publishColumns = [
|
||||
['plaza_view_count', 'BIGINT NOT NULL DEFAULT 0'],
|
||||
['plaza_like_count', 'BIGINT NOT NULL DEFAULT 0'],
|
||||
@@ -239,6 +272,16 @@ export async function migrateSchema(pool) {
|
||||
);
|
||||
}
|
||||
|
||||
// goosed_target stores the resolved upstream URL a session is pinned to, so
|
||||
// routing survives reordering or resizing the goosed target list. The legacy
|
||||
// integer goosed_node is kept as a fallback for rows written before this column
|
||||
// existed (and for older bundles that still read it).
|
||||
if (!(await columnExists(pool, 'h5_user_sessions', 'goosed_target'))) {
|
||||
await pool.query(
|
||||
`ALTER TABLE h5_user_sessions ADD COLUMN goosed_target VARCHAR(255) NULL AFTER goosed_node`,
|
||||
);
|
||||
}
|
||||
|
||||
const oauthStateColumns = [
|
||||
['intent', "VARCHAR(16) NOT NULL DEFAULT 'login' AFTER utm_campaign"],
|
||||
['bind_user_id', 'CHAR(36) NULL AFTER intent'],
|
||||
|
||||
Reference in New Issue
Block a user