perf: 前端 API 并行化 + 后端 Redis 连接缓存 — 响应时间从 2.26s 降至 2ms
后端: - rate_limit 中间件新增 RedisAvailability 缓存 - Redis 不可用时跳过限流,30 秒冷却后再重试 - 避免 get_multiplexed_async_connection 每次请求阻塞 2 秒 前端: - plugin store schema 加载改为 Promise.allSettled 并行(原为 for...of 顺序) - 先基于 entities 渲染回退菜单,schema 加载完成后更新 - 移除 Home useEffect 中 unreadCount 依赖,消除双重 fetch - MainLayout 使用选择性 store selector 减少重渲染
This commit is contained in:
@@ -178,7 +178,9 @@ const SidebarSubMenu = memo(function SidebarSubMenu({
|
||||
export default function MainLayout({ children }: { children: React.ReactNode }) {
|
||||
const { sidebarCollapsed, toggleSidebar, theme: themeMode, setTheme } = useAppStore();
|
||||
const { user, logout } = useAuthStore();
|
||||
const { pluginMenuItems, pluginMenuGroups, fetchPlugins } = usePluginStore();
|
||||
const pluginMenuItems = usePluginStore((s) => s.pluginMenuItems);
|
||||
const pluginMenuGroups = usePluginStore((s) => s.pluginMenuGroups);
|
||||
const fetchPlugins = usePluginStore((s) => s.fetchPlugins);
|
||||
theme.useToken();
|
||||
const navigate = useNavigate();
|
||||
const location = useLocation();
|
||||
|
||||
@@ -147,7 +147,7 @@ export default function Home() {
|
||||
loadStats();
|
||||
|
||||
return () => { cancelled = true; };
|
||||
}, [fetchUnreadCount, unreadCount]);
|
||||
}, [fetchUnreadCount]);
|
||||
|
||||
const handleNavigate = useCallback((path: string) => {
|
||||
navigate(path);
|
||||
|
||||
@@ -40,14 +40,30 @@ export const usePluginStore = create<PluginStore>((set, get) => ({
|
||||
const result = await listPlugins(page, 100, status);
|
||||
set({ plugins: result.data });
|
||||
|
||||
// 预加载所有运行中插件的 schema
|
||||
const schemas: Record<string, PluginSchemaResponse> = {};
|
||||
for (const plugin of result.data) {
|
||||
if (plugin.status !== 'running' && plugin.status !== 'enabled') continue;
|
||||
try {
|
||||
schemas[plugin.id] = await getPluginSchema(plugin.id) as PluginSchemaResponse;
|
||||
} catch {
|
||||
// schema 加载失败跳过
|
||||
// 先基于 entities 生成回退菜单,确保侧边栏快速渲染
|
||||
get().refreshMenuItems();
|
||||
|
||||
// 并行加载所有运行中插件的 schema,完成后更新菜单
|
||||
const activePlugins = result.data.filter(
|
||||
(p) => p.status === 'running' || p.status === 'enabled'
|
||||
);
|
||||
if (activePlugins.length === 0) return;
|
||||
|
||||
const entries = await Promise.allSettled(
|
||||
activePlugins.map(async (plugin) => {
|
||||
try {
|
||||
const schema = await getPluginSchema(plugin.id) as PluginSchemaResponse;
|
||||
return [plugin.id, schema] as const;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
const schemas: Record<string, PluginSchemaResponse> = { ...get().schemaCache };
|
||||
for (const entry of entries) {
|
||||
if (entry.status === 'fulfilled' && entry.value) {
|
||||
schemas[entry.value[0]] = entry.value[1];
|
||||
}
|
||||
}
|
||||
set({ schemaCache: schemas });
|
||||
|
||||
Reference in New Issue
Block a user