/** * 数据完整性定期检查 Edge Function * * 功能: * 1. 定期运行数据一致性检查 * 2. 检测错误率是否超过阈值(万分之一) * 3. 发送告警通知 * 4. 生成检查报告 * * 触发方式: * - 定时任务(建议每小时执行一次) * - 手动调用 */ import { serve } from 'https://deno.land/std@0.168.0/http/server.ts'; import { createClient } from 'https://esm.sh/@supabase/supabase-js@2'; const corsHeaders = { 'Access-Control-Allow-Origin': '*', 'Access-Control-Allow-Headers': 'authorization, x-client-info, apikey, content-type', }; interface CheckResult { check_type: string; total_records: number; inconsistent_records: number; error_rate: number; status: 'PASS' | 'FAIL'; } interface IntegrityReport { timestamp: string; checks: CheckResult[]; overall_error_rate: number; overall_status: 'PASS' | 'FAIL'; target_threshold: number; // 万分比阈值 alerts: string[]; } serve(async (req) => { // 处理 CORS 预检请求 if (req.method === 'OPTIONS') { return new Response('ok', { headers: corsHeaders }); } try { // 创建 Supabase 客户端 const supabaseUrl = Deno.env.get('SUPABASE_URL')!; const supabaseServiceKey = Deno.env.get('SUPABASE_SERVICE_ROLE_KEY')!; const supabase = createClient(supabaseUrl, supabaseServiceKey); console.log('开始数据完整性检查...'); // 运行数据完整性检查 const { data: checkResults, error: checkError } = await supabase.rpc( 'run_data_integrity_check' ); if (checkError) { throw new Error(`数据检查失败: ${checkError.message}`); } // 构建报告 const report: IntegrityReport = { timestamp: new Date().toISOString(), checks: checkResults || [], overall_error_rate: 0, overall_status: 'PASS', target_threshold: 1, // 万分之一 alerts: [], }; // 计算总体错误率 let totalRecords = 0; let totalInconsistent = 0; for (const check of report.checks) { totalRecords += check.total_records; totalInconsistent += check.inconsistent_records; // 检查单项是否超标 if (check.error_rate > report.target_threshold) { report.alerts.push( `⚠️ ${check.check_type} 错误率 ${check.error_rate.toFixed(2)}/万 超过阈值 ${report.target_threshold}/万` ); } } report.overall_error_rate = totalRecords > 0 ? (totalInconsistent / totalRecords) * 10000 : 0; report.overall_status = report.overall_error_rate <= report.target_threshold ? 'PASS' : 'FAIL'; // 如果总体错误率超标,添加告警 if (report.overall_status === 'FAIL') { report.alerts.unshift( `🚨 系统错误率 ${report.overall_error_rate.toFixed(2)}/万 超过目标阈值 ${report.target_threshold}/万` ); } // 记录检查结果到审计日志 await supabase.from('data_audit_logs').insert({ table_name: 'system_integrity_check', record_id: '00000000-0000-0000-0000-000000000000', // 系统检查使用固定ID operation: 'INSERT', new_values: report, validation_passed: report.overall_status === 'PASS', error_message: report.overall_status === 'FAIL' ? report.alerts.join('; ') : null, }); // 如果有告警,可以发送通知(这里预留接口) if (report.alerts.length > 0) { console.warn('数据完整性告警:', report.alerts); // TODO: 集成邮件/短信/钉钉等告警通知 // await sendAlertNotification(report); } // 返回报告 return new Response( JSON.stringify({ success: true, report, message: report.overall_status === 'PASS' ? '✓ 数据完整性检查通过' : '✗ 数据完整性检查发现异常', }), { headers: { ...corsHeaders, 'Content-Type': 'application/json' }, status: report.overall_status === 'PASS' ? 200 : 500, } ); } catch (error) { console.error('数据完整性检查异常:', error); const errorMessage = error instanceof Error ? error.message : 'Unknown error'; return new Response( JSON.stringify({ success: false, error: errorMessage, }), { headers: { ...corsHeaders, 'Content-Type': 'application/json' }, status: 500, } ); } });