feat(admin-perf): full Vue SPA migration + slow-query/memory monitoring gaps
Remove Jinja2 template fallback (1249 lines) — /admin/performance now serves Vue SPA exclusively via send_from_directory. Backend: - Add _SLOW_QUERY_WAITING counter with get_slow_query_waiting_count() - Record slow-path latency in read_sql_df_slow/iter via record_query_latency() - Extend metrics_history schema with slow_query_active, slow_query_waiting, worker_rss_bytes columns + ALTER TABLE migration for existing DBs - Add cleanup_archive_logs() with configurable ARCHIVE_LOG_DIR/KEEP_COUNT - Integrate archive cleanup into MetricsHistoryCollector 50-min cycle Frontend: - Add slow_query_active and slow_query_waiting StatCards to connection pool - Add slow_query_active trend line to pool trend chart - Add Worker memory (RSS MB) trend chart with preprocessing - Update modernization gate check path to frontend style.css Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -160,6 +160,8 @@
|
||||
<StatCard :value="poolTotalConnections" label="總連線數" />
|
||||
<StatCard :value="perfDetail.db_pool.status.max_capacity" label="最大容量" />
|
||||
<StatCard :value="poolOverflowDisplay" label="溢出連線" />
|
||||
<StatCard :value="perfDetail.db_pool.status.slow_query_active" label="慢查詢執行中" />
|
||||
<StatCard :value="perfDetail.db_pool.status.slow_query_waiting" label="慢查詢排隊中" />
|
||||
<StatCard :value="perfDetail.db_pool.config?.pool_size" label="池大小" />
|
||||
<StatCard :value="perfDetail.db_pool.config?.pool_recycle" label="回收週期 (s)" />
|
||||
<StatCard :value="perfDetail.db_pool.config?.pool_timeout" label="逾時 (s)" />
|
||||
@@ -175,6 +177,15 @@
|
||||
:series="poolTrendSeries"
|
||||
/>
|
||||
|
||||
<!-- Worker Memory Trend -->
|
||||
<TrendChart
|
||||
v-if="historyData.length > 1"
|
||||
title="Worker 記憶體趨勢"
|
||||
:snapshots="historyData"
|
||||
:series="memoryTrendSeries"
|
||||
yAxisLabel="MB"
|
||||
/>
|
||||
|
||||
<!-- Worker Control -->
|
||||
<section class="panel">
|
||||
<h2 class="panel-title">Worker 控制</h2>
|
||||
@@ -450,7 +461,12 @@ async function loadWorkerStatus() {
|
||||
async function loadPerformanceHistory() {
|
||||
try {
|
||||
const res = await apiGet('/admin/api/performance-history', { params: { minutes: 30 } });
|
||||
historyData.value = res?.data?.snapshots || [];
|
||||
const snapshots = res?.data?.snapshots || [];
|
||||
// Pre-process: convert worker_rss_bytes to worker_rss_mb for trend chart
|
||||
historyData.value = snapshots.map((s) => ({
|
||||
...s,
|
||||
worker_rss_mb: s.worker_rss_bytes ? Math.round(s.worker_rss_bytes / 1048576 * 10) / 10 : 0,
|
||||
}));
|
||||
} catch (e) {
|
||||
console.error('Failed to load performance history:', e);
|
||||
}
|
||||
@@ -460,6 +476,7 @@ async function loadPerformanceHistory() {
|
||||
const poolTrendSeries = [
|
||||
{ name: '飽和度', key: 'pool_saturation', color: '#6366f1' },
|
||||
{ name: '使用中', key: 'pool_checked_out', color: '#f59e0b' },
|
||||
{ name: '慢查詢執行中', key: 'slow_query_active', color: '#ef4444' },
|
||||
];
|
||||
|
||||
const latencyTrendSeries = [
|
||||
@@ -478,6 +495,10 @@ const hitRateTrendSeries = [
|
||||
{ name: 'L2 命中率', key: 'rc_l2_hit_rate', color: '#f59e0b' },
|
||||
];
|
||||
|
||||
const memoryTrendSeries = [
|
||||
{ name: 'RSS (MB)', key: 'worker_rss_mb', color: '#8b5cf6' },
|
||||
];
|
||||
|
||||
async function refreshAll() {
|
||||
loading.value = true;
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user