feat: home growth auto(7→1) and hourly recent-video snapshot
- Add analytics.home_growth_days (auto|1|7); API growth_days=auto tries 7 then 1 - Homepage shows active window and growth-board link; clearer empty reason - New snapshot_recent scheduler task (schedule.recent_snapshot_minutes/days) - run_recent_videos refreshes new aids only; never touches completed/backup - Full 00:01 job keeps ok=1 skip (covers hourly refresh within 1h); mutex with recent
This commit is contained in:
1 parent
04716aec1b
commit
9163f47b76
15 files changed
+496
-22
No files matched your search
@@ -436,6 +436,100 @@ def test_backup_failure_retries_without_api():
|
||||
db.close()
|
||||
|
||||
|
||||
def test_run_recent_videos_refreshes_without_completion_markers():
|
||||
"""小时任务只刷新近窗新片,不写完成日 / 备份。"""
|
||||
clock = 1_800_000_000
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
transport = SnapshotTransport({
|
||||
1: view_for(1, view=111),
|
||||
2: view_for(2, view=222),
|
||||
3: view_for(3, view=333),
|
||||
})
|
||||
db, repo, service = make_service(tmp, transport, track_fans=())
|
||||
try:
|
||||
# 1/2 在墙钟近 2 天内;3 为旧片
|
||||
add_video(repo, 1)
|
||||
add_video(repo, 2)
|
||||
add_video(repo, 3)
|
||||
repo.db.write(lambda conn: conn.executemany(
|
||||
"UPDATE video SET pubdate = ? WHERE aid = ?",
|
||||
[
|
||||
(clock - 3600, 1),
|
||||
(clock - 86400, 2),
|
||||
(clock - 10 * 86400, 3),
|
||||
],
|
||||
))
|
||||
# 预置同日 ok=1,验证小时任务可覆盖刷新
|
||||
repo.upsert_snapshot(
|
||||
DATE, 1,
|
||||
metrics={"view": 1, "like": 0, "coin": 0, "favorite": 0,
|
||||
"share": 0, "reply": 0, "danmaku": 0},
|
||||
ok=True, err=None, captured_at=clock - 100,
|
||||
)
|
||||
assert repo.kv_get(service.completed_key(DATE)) is None
|
||||
|
||||
summary = service.run_recent_videos(date=DATE, recent_days=2)
|
||||
assert summary.total == 2
|
||||
assert summary.success == 2
|
||||
assert summary.failed == 0
|
||||
assert set(repo.video_aids_recent_for_snapshot(
|
||||
since_pubdate=clock - 2 * 86400
|
||||
)) == {1, 2}
|
||||
|
||||
row = repo.db.read(lambda conn: dict(conn.execute(
|
||||
"SELECT view, ok, captured_at FROM snapshot WHERE stat_date=? AND aid=1",
|
||||
(DATE,),
|
||||
).fetchone()))
|
||||
assert row["view"] == 111
|
||||
assert row["ok"] == 1
|
||||
assert row["captured_at"] == clock
|
||||
|
||||
# 完成日 / 备份标记保持原样
|
||||
assert repo.kv_get(service.completed_key(DATE)) is None
|
||||
assert repo.kv_get("snapshot:last_completed") is None
|
||||
assert repo.kv_get(service.backup_key(DATE)) is None
|
||||
assert transport.count("/web-interface/view") == 2
|
||||
|
||||
# 全量任务随后才写完成日;且已 ok=1 的跳过
|
||||
full = service.run_videos(date=DATE)
|
||||
assert full.skipped >= 2 # 1、2 已被小时任务写过
|
||||
assert full.success >= 1 # 至少旧片 3
|
||||
assert repo.kv_get(service.completed_key(DATE)) == "1"
|
||||
assert repo.kv_get("snapshot:last_completed") == DATE
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
def test_full_snapshot_skips_ok_rows_including_hourly_refresh():
|
||||
"""00:01 全量:同日 ok=1(含小时任务刚刷)直接跳过。"""
|
||||
clock = 1_800_000_000
|
||||
with tempfile.TemporaryDirectory() as tmp:
|
||||
transport = SnapshotTransport({1: view_for(1), 2: view_for(2)})
|
||||
db, repo, service = make_service(tmp, transport, track_fans=())
|
||||
try:
|
||||
add_video(repo, 1)
|
||||
add_video(repo, 2)
|
||||
repo.upsert_snapshot(
|
||||
DATE, 1,
|
||||
metrics={"view": 9, "like": 0, "coin": 0, "favorite": 0,
|
||||
"share": 0, "reply": 0, "danmaku": 0},
|
||||
ok=True, err=None, captured_at=clock - 30, # 「1 小时内」
|
||||
)
|
||||
result = service.run_videos(date=DATE)
|
||||
assert result.skipped == 1
|
||||
assert result.success == 1
|
||||
# aid=1 保持小时任务写入的 view=9,未被全量覆盖
|
||||
row = repo.db.read(lambda conn: dict(conn.execute(
|
||||
"SELECT view FROM snapshot WHERE stat_date=? AND aid=1",
|
||||
(DATE,),
|
||||
).fetchone()))
|
||||
assert row["view"] == 9
|
||||
assert transport.count("/web-interface/view") == 1
|
||||
finally:
|
||||
db.close()
|
||||
|
||||
|
||||
|
||||
def main():
|
||||
test_snapshot_success_resume_and_force()
|
||||
test_resume_skips_ok_and_retries_failed()
|
||||
@@ -449,6 +543,8 @@ def main():
|
||||
test_fan_resume_preserves_successful_value()
|
||||
test_force_interrupt_leaves_incomplete_marker()
|
||||
test_backup_failure_retries_without_api()
|
||||
test_run_recent_videos_refreshes_without_completion_markers()
|
||||
test_full_snapshot_skips_ok_rows_including_hourly_refresh()
|
||||
print("OK: 每日快照、断点续跑、失败占位与粉丝采集测试全部通过")
|
||||
|
||||
|
||||
|
||||
Reference in new issue
Block a user