Prechádzať zdrojové kódy

fix: 修复错误规则版本更新后无法自动同步的问题

问题:当 DEFAULT_ERROR_RULES 更新(如从 7 条变成 8 条)后,
数据库中的旧规则不会自动同步,因为启动时使用的
initializeDefaultErrorRules() 使用 ON CONFLICT DO NOTHING。

解决方案:
- 启动时改用 syncDefaultErrorRules() 完整同步预置规则
- 每次启动都删除所有预置规则(isDefault=true)并重新插入
- 用户自定义规则(isDefault=false)不受影响
- 将 initializeDefaultErrorRules() 标记为 @deprecated

同时更新 UI 按钮文本从"刷新缓存"改为"同步规则"以更准确反映功能。

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <[email protected]>
ding113 2 mesiacov pred
rodič
commit
c70f87132b

+ 3 - 3
messages/en/settings.json

@@ -1419,9 +1419,9 @@
     "disable": "Error rule disabled",
     "toggleFailed": "Toggle failed",
     "toggleFailedError": "Toggle failed:",
-    "refreshCache": "Refresh Cache",
-    "refreshCacheSuccess": "Cache refreshed successfully, loaded {count} error rules",
-    "refreshCacheFailed": "Failed to refresh cache",
+    "refreshCache": "Sync Rules",
+    "refreshCacheSuccess": "Rules synced successfully, loaded {count} error rules",
+    "refreshCacheFailed": "Failed to sync rules",
     "cacheStats": "Cached {totalCount} error rules",
     "emptyState": "No error rules yet. Click 'Add Error Rule' in the top right to start configuration.",
     "confirmDelete": "Are you sure you want to delete error rule \"{pattern}\"?",

+ 3 - 3
messages/ja/settings.json

@@ -1320,9 +1320,9 @@
     "disable": "エラールールが無効になりました",
     "toggleFailed": "切り替えに失敗しました",
     "toggleFailedError": "切り替えに失敗しました:",
-    "refreshCache": "キャッシュを更新",
-    "refreshCacheSuccess": "キャッシュが正常に更新され、{count} 個のエラールールがロードされました",
-    "refreshCacheFailed": "キャッシュの更新に失敗しました",
+    "refreshCache": "ルールを同期",
+    "refreshCacheSuccess": "ルールが正常に同期され、{count} 個のエラールールがロードされました",
+    "refreshCacheFailed": "ルールの同期に失敗しました",
     "cacheStats": "キャッシュ: {totalCount}件のルール",
     "emptyState": "エラールールがまだありません。右上の「エラールールを追加」をクリックして設定を開始してください。",
     "confirmDelete": "エラールール \"{pattern}\" を削除してもよろしいですか?",

+ 3 - 3
messages/ru/settings.json

@@ -1320,9 +1320,9 @@
     "disable": "Правило ошибки отключено",
     "toggleFailed": "Переключение не удалось",
     "toggleFailedError": "Переключение не удалось:",
-    "refreshCache": "Обновить кэш",
-    "refreshCacheSuccess": "Кэш успешно обновлен, загружено {count} правил ошибок",
-    "refreshCacheFailed": "Не удалось обновить кэш",
+    "refreshCache": "Синхронизировать правила",
+    "refreshCacheSuccess": "Правила успешно синхронизированы, загружено {count} правил ошибок",
+    "refreshCacheFailed": "Не удалось синхронизировать правила",
     "cacheStats": "Кэшировано: {totalCount} правил",
     "emptyState": "Правил ошибок пока нет. Нажмите 'Добавить правило ошибки' в правом верхнем углу, чтобы начать настройку.",
     "confirmDelete": "Вы уверены, что хотите удалить правило ошибки \"{pattern}\"?",

+ 3 - 3
messages/zh-CN/settings.json

@@ -1438,9 +1438,9 @@
     "disable": "错误规则已禁用",
     "toggleFailed": "状态切换失败",
     "toggleFailedError": "状态切换失败:",
-    "refreshCache": "刷新缓存",
-    "refreshCacheSuccess": "缓存刷新成功,已加载 {count} 个错误规则",
-    "refreshCacheFailed": "刷新缓存失败",
+    "refreshCache": "同步规则",
+    "refreshCacheSuccess": "规则同步成功,已加载 {count} 个错误规则",
+    "refreshCacheFailed": "同步规则失败",
     "cacheStats": "缓存: 共 {totalCount} 条规则",
     "emptyState": "暂无错误规则,点击右上角\"添加错误规则\"开始配置。",
     "confirmDelete": "确定要删除错误规则\"{pattern}\"吗?",

+ 3 - 3
messages/zh-TW/settings.json

@@ -1365,9 +1365,9 @@
     "disable": "錯誤規則已停用",
     "toggleFailed": "狀態切換失敗",
     "toggleFailedError": "狀態切換失敗:",
-    "refreshCache": "重新整理快取",
-    "refreshCacheSuccess": "快取重新整理成功,已載入 {count} 個錯誤規則",
-    "refreshCacheFailed": "重新整理快取失敗",
+    "refreshCache": "同步規則",
+    "refreshCacheSuccess": "規則同步成功,已載入 {count} 個錯誤規則",
+    "refreshCacheFailed": "同步規則失敗",
     "cacheStats": "快取: 共 {totalCount} 條規則",
     "emptyState": "目前沒有錯誤規則,點擊右上角「新增錯誤規則」開始設定。",
     "confirmDelete": "確定要刪除錯誤規則「{pattern}」嗎?",

+ 10 - 8
scripts/init-error-rules.ts

@@ -1,23 +1,25 @@
 #!/usr/bin/env bun
 /**
- * Initialize default error rules
+ * Sync default error rules
  *
  * Usage: bun run scripts/init-error-rules.ts
  *
- * This script inserts 7 default error rules into the error_rules table.
- * It uses ON CONFLICT DO NOTHING to ensure idempotency.
+ * This script syncs DEFAULT_ERROR_RULES to the database:
+ * - Deletes all existing default rules (isDefault=true)
+ * - Re-inserts the latest default rules
+ * - User-created rules (isDefault=false) are preserved
  */
 
-import { initializeDefaultErrorRules } from "@/repository/error-rules";
+import { syncDefaultErrorRules } from "@/repository/error-rules";
 
 async function main() {
-  console.log("Initializing default error rules...");
+  console.log("Syncing default error rules...");
 
   try {
-    await initializeDefaultErrorRules();
-    console.log("✓ Default error rules initialized successfully");
+    const count = await syncDefaultErrorRules();
+    console.log(`✓ Default error rules synced successfully (${count} rules)`);
   } catch (error) {
-    console.error("✗ Failed to initialize default error rules:", error);
+    console.error("✗ Failed to sync default error rules:", error);
     process.exit(1);
   }
 }

+ 15 - 10
src/instrumentation.ts

@@ -6,16 +6,21 @@
 import { logger } from "@/lib/logger";
 
 /**
- * 初始化错误规则检测器
+ * 同步错误规则并初始化检测器
  * 提取为独立函数以避免代码重复
  *
+ * 每次启动都会同步 DEFAULT_ERROR_RULES 到数据库:
+ * - 删除所有预置规则(isDefault=true)
+ * - 重新插入最新的预置规则
+ * - 用户自定义规则(isDefault=false)保持不变
+ *
  * 注意: 此函数会传播关键错误,调用者应决定是否需要优雅降级
  */
-async function initializeErrorRuleDetector(): Promise<void> {
-  // 初始化默认错误规则 - 让关键错误传播
-  const { initializeDefaultErrorRules } = await import("@/repository/error-rules");
-  await initializeDefaultErrorRules();
-  logger.info("Default error rules initialized successfully");
+async function syncErrorRulesAndInitializeDetector(): Promise<void> {
+  // 同步默认错误规则到数据库 - 每次启动都完整同步
+  const { syncDefaultErrorRules } = await import("@/repository/error-rules");
+  const syncedCount = await syncDefaultErrorRules();
+  logger.info(`Default error rules synced successfully (${syncedCount} rules)`);
 
   // 加载错误规则缓存 - 让关键错误传播
   const { errorRuleDetector } = await import("@/lib/error-rule-detector");
@@ -54,9 +59,9 @@ export async function register() {
       const { ensurePriceTable } = await import("@/lib/price-sync/seed-initializer");
       await ensurePriceTable();
 
-      // 初始化错误规则检测器(非关键功能,允许优雅降级)
+      // 同步错误规则并初始化检测器(非关键功能,允许优雅降级)
       try {
-        await initializeErrorRuleDetector();
+        await syncErrorRulesAndInitializeDetector();
       } catch (error) {
         logger.error(
           "[Instrumentation] Non-critical: Error rule detector initialization failed",
@@ -92,9 +97,9 @@ export async function register() {
       const { ensurePriceTable } = await import("@/lib/price-sync/seed-initializer");
       await ensurePriceTable();
 
-      // 初始化错误规则检测器(非关键功能,允许优雅降级)
+      // 同步错误规则并初始化检测器(非关键功能,允许优雅降级)
       try {
-        await initializeErrorRuleDetector();
+        await syncErrorRulesAndInitializeDetector();
       } catch (error) {
         logger.error(
           "[Instrumentation] Non-critical: Error rule detector initialization failed",

+ 12 - 4
src/repository/error-rules.ts

@@ -253,13 +253,17 @@ const DEFAULT_ERROR_RULES = [
 ];
 
 /**
- * 同步默认错误规则
+ * 同步默认错误规则(推荐使用)
  *
  * 将代码中的默认规则同步到数据库:
  * - 删除所有已有的默认规则(isDefault=true)
- * - 重新插入最新的默认规则
+ * - 重新插入最新的 DEFAULT_ERROR_RULES
  * - 用户自定义规则(isDefault=false)保持不变
  *
+ * 使用场景:
+ * 1. 系统启动时自动同步(instrumentation.ts)
+ * 2. 用户点击"刷新缓存"按钮时手动同步
+ *
  * @returns 同步的规则数量
  */
 export async function syncDefaultErrorRules(): Promise<number> {
@@ -282,8 +286,12 @@ export async function syncDefaultErrorRules(): Promise<number> {
 /**
  * 初始化默认错误规则
  *
- * 使用 ON CONFLICT DO NOTHING 确保幂等性,避免重复插入
- * 用于首次部署时初始化默认规则
+ * @deprecated 请使用 syncDefaultErrorRules() 替代
+ *
+ * 此函数使用 ON CONFLICT DO NOTHING,只能插入新规则,无法更新已存在的规则。
+ * 当 DEFAULT_ERROR_RULES 更新时,数据库中的旧规则不会被同步。
+ *
+ * syncDefaultErrorRules() 会删除所有预置规则并重新插入,确保每次都同步最新版本。
  */
 export async function initializeDefaultErrorRules(): Promise<void> {
   // 使用事务批量插入,ON CONFLICT DO NOTHING 保证幂等性