Ver Fonte

fix: keep production writes available before bridge cutover

彭峰 há 1 mês atrás
pai
commit
7a9c668e67
1 ficheiros alterados com 5 adições e 1 exclusões
  1. 5 1
      scripts/deploy-admin-functions.mjs

+ 5 - 1
scripts/deploy-admin-functions.mjs

@@ -2974,6 +2974,7 @@ const LEGACY_MUTATIONS={
 };
 function requireSuperAdmin(context){if(!context.isSuperAdmin)fail(403,'只有超级管理员可以访问数据同步中心');}
 function syncConfig(){const env=typeof process!=='undefined'&&process.env?process.env:{};return{baseUrl:text(env.XIAOSHU_LEGACY_SYNC_BASE_URL).replace(/\/$/,''),keyId:text(env.XIAOSHU_LEGACY_SYNC_KEY_ID),secret:text(env.XIAOSHU_LEGACY_SYNC_SECRET)};}
+function syncBridgeConfigured(){const config=syncConfig();return Boolean(config.baseUrl&&config.keyId&&config.secret);}
 async function operationalSyncIndicator(context,input){const config=syncConfig();if(!config.baseUrl||!config.keyId||!config.secret)return{state:'not_configured',label:'尚未启用持续同步',lastSuccessAt:'',lagSeconds:null};const rows=await newClassObjects('LegacySyncCheckpoint',context,input,1000),critical=rows.filter((row)=>['users','appointments','lessons'].includes(text(row.get('dataset')))),lastSuccessAt=critical.map((row)=>dateIso(row.get('lastSuccessAt'))).filter(Boolean).sort()[0]||'',lagSeconds=lastSuccessAt?Math.max(0,Math.floor((Date.now()-new Date(lastSuccessAt).getTime())/1000)):null,healthy=critical.length===3&&critical.every((row)=>text(row.get('state'))==='healthy'||text(row.get('state'))==='catching_up')&&lagSeconds!==null&&lagSeconds<=120;return{state:healthy?'synced':'delayed',label:healthy?'核心数据刚刚同步':'数据同步延迟,正在追平',lastSuccessAt,lagSeconds};}
 async function syncBridgeRequest(path,options={}){
   const config=syncConfig();if(!config.baseUrl||!config.keyId||!config.secret)fail(503,'旧系统同步桥尚未配置');
@@ -3017,7 +3018,10 @@ async function handler(request,response) {
     if(operation==='ops/sync/status') return response.json({success:true,data:await syncStatus(context,input)});
     if(operation==='ops/sync/run') return response.json({success:true,data:await runSync(context,input)});
     if(operation==='ops/sync/retry') return response.json({success:true,data:await retrySync(context,input)});
-    if(LEGACY_MUTATIONS[operation]) return response.json({success:true,data:await bridgeFirstWrite(context,input,operation,payload)});
+    // Keep the current Parse implementation available until the old-server bridge is
+    // actually configured. Enforcing bridge-first writes before that point would turn
+    // a production deployment into an outage for scheduling and member operations.
+    if(LEGACY_MUTATIONS[operation]&&syncBridgeConfigured()) return response.json({success:true,data:await bridgeFirstWrite(context,input,operation,payload)});
     if(operation==='ops/dashboard/summary') return response.json({success:true,data:await professionalDashboard(context,input)});
     if(operation==='ops/dashboard/schedule-trend') return response.json({success:true,data:await scheduleTrendData(context,input)});
     if(operation==='ops/coaches/list') return response.json({success:true,data:await professionalCoachRows(context,input)});