Files
inkreach-prefect/scripts/backfill_riin_goods_status.py
T
yeuimu c030eca178
CI / test (pull_request) Successful in 1m35s
fix: RIIN 商品状态补 COMPLETE/PAUSE 映射,修复 Goods.status 大面积 NULL
问题:RIIN 商品级 goodsStatus 复用平台状态枚举,COMPLETE/PAUSE 无映射,
.get() 返回 None 落库为 NULL,累计 206 万行(占 RIIN 商品 33.75%),
终态订单不再被 refresh_pending 刷新而长期滞留。该缺口继承自
inkreach-bi-auth-mng TS 版,且 TS 的 warnUnknown 告警在移植时被省略,
导致从未暴露。

修复:
- RIIN_GOODS_STATUS_MAP 补 COMPLETE=已完成、PAUSE=暂停
- 对齐 TS 版 warnUnknown:四个状态映射函数对未知值告警(同值只报一次)
- docs/sql:Goods.status 约束新增允许"暂停"(原约束拒绝,已在库执行)
- scripts/backfill_riin_goods_status.py:存量 NULL 按"已发货"订单终态
  近似回填(幂等、分批);"已关闭"与非终态订单走 by-orders 重拉真值
- tests/test_mappers.py:9 个单测全过;实单 GSU1S555400MFLL e2e 验证
  4 行 NULL → 已完成/暂停
2026-09-28 03:02:05 +00:00

73 lines
2.5 KiB
Python

"""一次性回填:RIIN Goods.status 为 NULL 的历史行(终态"已发货"订单)。
背景:RIIN 商品级 goods_status 复用平台状态枚举,COMPLETE/PAUSE 此前无映射,
约 1/3 商品行 status 被写为 NULL(mappers.py 已补映射)。本脚本按订单终态
将近似值回填;"已关闭"与非终态订单不在此列,走 riin-by-orders 重拉取真值。
幂等:只更新 status IS NULL 的行。分批提交,避免长事务。
运行:uv run python scripts/backfill_riin_goods_status.py [--dry-run] [--batch N]
"""
from __future__ import annotations
import argparse
import os
import psycopg2
from dotenv import load_dotenv
load_dotenv(os.path.join(os.path.dirname(__file__), "..", ".env"))
DEFAULT_BATCH = 50_000
SQL_COUNT = """
SELECT count(*) FROM "Goods" g
JOIN "Orders" o ON o."orderNo" = g."orderNo" AND o."createdAt" = g."createdAt"
WHERE o."systemName" = 'RIIN' AND o."systemStatus" = '已发货' AND g."status" IS NULL
"""
# ctid 分批:PostgreSQL 的 UPDATE 不支持 LIMIT,用子查询圈定每批行
SQL_BACKFILL_BATCH = """
UPDATE "Goods" g SET "status" = '已发货'
WHERE g.ctid IN (
SELECT g2.ctid FROM "Goods" g2
JOIN "Orders" o ON o."orderNo" = g2."orderNo" AND o."createdAt" = g2."createdAt"
WHERE o."systemName" = 'RIIN' AND o."systemStatus" = '已发货' AND g2."status" IS NULL
LIMIT %s
)
"""
def main() -> None:
parser = argparse.ArgumentParser(description="回填 RIIN Goods.status NULL(已发货订单)")
parser.add_argument("--dry-run", action="store_true", help="只统计待回填行数,不写入")
parser.add_argument("--batch", type=int, default=DEFAULT_BATCH, help="每事务回填行数")
args = parser.parse_args()
conn = psycopg2.connect(os.environ["DB_DSN"])
try:
with conn.cursor() as cur:
cur.execute(SQL_COUNT)
(pending,) = cur.fetchone()
print(f"[backfill] 待回填(status IS NULL 且订单已发货): {pending} 行")
if args.dry_run or pending == 0:
return
total = 0
while True:
with conn.cursor() as cur:
cur.execute(SQL_BACKFILL_BATCH, (args.batch,))
updated = cur.rowcount
conn.commit()
total += updated
print(f"[backfill] 本批 {updated} 行,累计 {total}")
if updated < args.batch:
break
print(f"[backfill] 完成,共回填 {total} 行")
finally:
conn.close()
if __name__ == "__main__":
main()