perf: 筛选统计去掉 JSON 兜底,并补上 orders 覆盖索引
去掉 work_orders 堆访问后,JOIN 会把 orders 整表扫进 Hash Right Join。 领取页在快照新鲜时不再打上游;快手出网统一 10 秒超时。倒计时改为自适应间隔。 Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -23,6 +23,23 @@ test('保留清理必须覆盖 work_order_events,否则这张只增不减的
|
||||
)
|
||||
})
|
||||
|
||||
test('保留任务要回填漏写的付款派生列,并在有命中时打日志', async () => {
|
||||
const src = await readJobSource()
|
||||
assert.ok(
|
||||
src.includes('source_order_amount_fen IS NULL'),
|
||||
'只处理派生列为空的行,避免把合法 0 或已落列的金额改掉',
|
||||
)
|
||||
assert.ok(
|
||||
src.includes("material_json->'source'->>'orderAmountFen'"),
|
||||
'回填口径必须与 083 / resolveSourceOrderAmountFen 相同',
|
||||
)
|
||||
assert.ok(src.includes("~ '^-?[0-9]{1,15}$'"), '超长数字不能 ::bigint,否则整次保留任务失败')
|
||||
assert.ok(
|
||||
src.includes('source_order_amount_fen 出现漏写'),
|
||||
'有命中必须打日志,否则金额静默回退 orders.total_amount',
|
||||
)
|
||||
})
|
||||
|
||||
test('保留清理默认窗口:敏感报文/事件 180 天,审计 365 天,工单事件 180 天', async () => {
|
||||
const defaults = await readFile(new URL('../../config/defaults.ts', import.meta.url), 'utf8')
|
||||
for (const line of [
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { query } from '../../db/client.js'
|
||||
import { runtimeConfig } from '../../config/runtime.js'
|
||||
import { logWarn } from '../../utils/logger.js'
|
||||
import { getWorkerProductMatchConfig } from '../worker-platform/worker-product-match-config-service.js'
|
||||
import { pruneWorkProductMatchLogs } from '../../repositories/worker-platform/product-match-repo.js'
|
||||
|
||||
@@ -13,6 +14,7 @@ export type DataRetentionResult = {
|
||||
workOrderEventRows: number
|
||||
matchLogRows: number
|
||||
matchLogDeletedRows: number
|
||||
sourceOrderAmountBackfillRows: number
|
||||
}
|
||||
|
||||
/** 清理敏感原始报文并删除已过保留期的事件/审计记录。 */
|
||||
@@ -45,6 +47,14 @@ export async function runDataRetentionJob(): Promise<DataRetentionResult> {
|
||||
const webhookEventRows = await deleteOldRowsInBatches('webhook_events', webhookEventDays)
|
||||
const auditLogRows = await deleteOldRowsInBatches('admin_audit_logs', auditLogDays)
|
||||
const workOrderEventRows = await deleteOldRowsInBatches('work_order_events', workOrderEventDays)
|
||||
// 统计热路径已不再读 material_json。若将来有第三个写入点忘了维护派生列,
|
||||
// 金额会静默回退 orders.total_amount。这里把漏写补上并打日志,让口径变化可见。
|
||||
const sourceOrderAmountBackfillRows = await backfillMissingSourceOrderAmount()
|
||||
if (sourceOrderAmountBackfillRows > 0) {
|
||||
logWarn('[data-retention]', 'source_order_amount_fen 出现漏写,已按 JSON 回填', {
|
||||
rows: sourceOrderAmountBackfillRows,
|
||||
})
|
||||
}
|
||||
|
||||
return {
|
||||
status: 'ok',
|
||||
@@ -56,8 +66,23 @@ export async function runDataRetentionJob(): Promise<DataRetentionResult> {
|
||||
webhookEventRows,
|
||||
auditLogRows,
|
||||
workOrderEventRows,
|
||||
sourceOrderAmountBackfillRows,
|
||||
}
|
||||
}
|
||||
|
||||
/** 只补「列为 NULL 且 JSON 里仍有 1~15 位整数」的行。正常应为 0。 */
|
||||
async function backfillMissingSourceOrderAmount() {
|
||||
const result = await query(
|
||||
`
|
||||
UPDATE work_orders
|
||||
SET source_order_amount_fen = (material_json->'source'->>'orderAmountFen')::bigint
|
||||
WHERE source_order_amount_fen IS NULL
|
||||
AND COALESCE(material_json->'source'->>'orderAmountFen', '') ~ '^-?[0-9]{1,15}$'
|
||||
`,
|
||||
)
|
||||
return result.rowCount || 0
|
||||
}
|
||||
|
||||
async function scrubJsonColumnInBatches(
|
||||
table: 'orders' | 'kuaishou_industry_vouchers' | 'work_product_match_logs',
|
||||
dateColumn: 'created_at' | 'updated_at',
|
||||
|
||||
@@ -164,6 +164,7 @@ async function runJob(job: JsonObject, { manual = false }: { manual?: boolean }
|
||||
taskEventRows: Number(summary.taskEventRows || 0),
|
||||
webhookEventRows: Number(summary.webhookEventRows || 0),
|
||||
auditLogRows: Number(summary.auditLogRows || 0),
|
||||
sourceOrderAmountBackfillRows: Number(summary.sourceOrderAmountBackfillRows || 0),
|
||||
}
|
||||
: {}),
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user