fix(transfer): tolerate mtime precision drift in history gate

This commit is contained in:
jxxghp
2026-09-20 13:59:49 +08:00
parent f08be04f97
commit 9bcaed5dc1
4 changed files with 38 additions and 4 deletions

View File

@@ -2,6 +2,7 @@
from __future__ import annotations
import math
from typing import Any, Dict, Optional
from app.application.configuration import TransferRetryConfig, get_transfer_retry_config
@@ -17,6 +18,8 @@ from app.runtime.log import logger
MIN_FAILED_RETRIES = 1
MAX_FAILED_RETRIES = 10
FAILED_RETRY_TTL = 24 * 3600
# 不同存储后端对秒级修改时间的浮点和序列化误差可能达到毫秒;更大的变化仍视为新版本。
MODIFY_TIME_TOLERANCE = 1e-3
# 缓存值会同时保存文件指纹,使同一路径的新版本获得独立重试预算。
_failed_retry_counts = TTLCache(
@@ -140,14 +143,23 @@ def _is_file_version_changed(
recorded_fingerprint: Dict[str, Any],
current_fingerprint: Dict[str, Any],
) -> bool:
"""判断两个可比文件指纹是否指向不同版本。"""
"""判断两个可比文件指纹是否指向不同版本,忽略修改时间的毫秒级误差。"""
for field in ("fileid", "modify_time", "size"):
recorded_value = recorded_fingerprint.get(field)
current_value = current_fingerprint.get(field)
if (
recorded_value is not None
and current_value is not None
and recorded_value != current_value
and (
not math.isclose(
recorded_value,
current_value,
rel_tol=0.0,
abs_tol=MODIFY_TIME_TOLERANCE,
)
if field == "modify_time"
else recorded_value != current_value
)
):
return True
return False

View File

@@ -591,7 +591,7 @@ class TransferExecutionOwner(_TransferOwnerBase):
if task.mediainfo.tmdb_id:
error_message = "TMDB 信息未匹配到媒体分类,无法按媒体类别整理"
else:
error_message = "未识别到 TMDB 辅助信息,无法按媒体类别整理"
error_message = "媒体识别结果未匹配到媒体分类,无法按媒体类别整理"
logger.error(f"{task.fileitem.name} {error_message}")
if task.preview:
return False, error_message

View File

@@ -79,6 +79,28 @@ def test_evaluate_history_gate_skips_when_success_size_unchanged():
assert action == HistoryGateAction.SKIP
@pytest.mark.parametrize(
"current_modify_time, expected",
[
(100.0005, HistoryGateAction.SKIP),
(100.01, HistoryGateAction.PASS_SIZE_CHANGED),
],
)
def test_evaluate_history_gate_uses_tolerance_for_modify_time(
current_modify_time, expected,
):
"""修改时间仅有毫秒级浮点漂移时应保持原版本,明显变化仍应放行。"""
history = make_history(status=True, size=1024, modify_time=100.0)
action = evaluate_history_gate(
history,
file_size=1024,
file_modify_time=current_modify_time,
)
assert action == expected
def test_evaluate_history_gate_skips_when_recorded_size_missing():
"""成功记录缺少大小信息(如蓝光目录)时无法比对,保守跳过。"""
history = make_history(status=True, has_src_fileitem=False)

View File

@@ -161,7 +161,7 @@ def test_transfer_stops_when_automatic_category_has_no_tmdb_result(monkeypatch)
state, message = chain._TransferChain__handle_transfer(task)
assert not state
assert message == "未识别到 TMDB 辅助信息,无法按媒体类别整理"
assert message == "媒体识别结果未匹配到媒体分类,无法按媒体类别整理"
assert task.mediainfo.media_source == MediaSource.AniList
assert task.mediainfo.media_id == "1234"
assert task.plan_checkpoint is not None