feat: 任务失败后继续执行下一条 (#170)

This commit is contained in:
chengma
2026-08-11 18:21:25 +08:00
parent b2c99840b3
commit 8b8a542cc5
14 changed files with 280 additions and 103 deletions
+36 -12
View File
@@ -56,6 +56,20 @@ LivePurchaseAdapterFactory = Callable[
[str, Callable[[], bool]], PddLivePurchaseAdapter
]
_QUEUE_BLOCKING_ERROR_CODES = frozenset(
{
"DEVICE_APP_START_FAILED",
"DEVICE_DISCONNECTED",
"DEVICE_SESSION_CLOSED",
"PDD_PAGE_CAPTCHA",
"PDD_PAGE_LOGIN_REQUIRED",
"PDD_PAGE_PAYMENT",
"PDD_PAGE_RISK_CONTROL",
"PDD_PAGE_UNKNOWN",
"PURCHASE_ADAPTER_ERROR",
}
)
class PurchaseTaskService:
"""只执行本地已保存的采购任务,不领取新任务。"""
@@ -108,7 +122,8 @@ class PurchaseTaskService:
self._started(remote_task_id)
adapter: PddPurchaseAdapter | None = None
step = "purchase_prepare"
business_failure_message = ""
failure_message = ""
failure_outcome_kind = ""
try:
target = self._target_from_task(started.task)
adapter = self._factory(self._device_address, self._cancelled)
@@ -184,6 +199,13 @@ class PurchaseTaskService:
remote_task_id, started.attempt_id, result
)
except PddPurchaseError as exc:
failure_message = exc.message
if exc.code == "PURCHASE_CANCELLED":
failure_outcome_kind = "cancelled"
elif exc.code in _QUEUE_BLOCKING_ERROR_CODES:
failure_outcome_kind = "global_failed"
else:
failure_outcome_kind = "task_failed"
event = self._save_failure(
remote_task_id,
started.attempt_id,
@@ -193,9 +215,9 @@ class PurchaseTaskService:
step,
exc.diagnostics,
)
if exc.code == "PDD_GOODS_UNAVAILABLE":
business_failure_message = exc.message
except Exception as exc:
failure_message = f"采购在“{step}”发生未知错误:{exc}"
failure_outcome_kind = "global_failed"
event = self._save_failure(
remote_task_id,
started.attempt_id,
@@ -209,9 +231,11 @@ class PurchaseTaskService:
if adapter is not None:
adapter.close()
outcome = self._submit(event)
if business_failure_message and outcome.kind == "failed":
if failure_message and outcome.kind == "failed":
return PurchaseTaskOutcome(
"business_failed", business_failure_message, remote_task_id
failure_outcome_kind,
f"任务 {remote_task_id} 采购失败:{failure_message}",
remote_task_id,
)
return outcome
@@ -488,25 +512,25 @@ class PurchaseTaskService:
attempt_id: str,
code: str,
message: str,
retryable: bool,
_retryable: bool,
step: str,
diagnostics: Mapping[str, object],
) -> OutboxEventRecord:
if code == "PURCHASE_CANCELLED":
status = TaskStatus.CANCELLED
elif code == "PDD_GOODS_UNAVAILABLE":
status = TaskStatus.FAILED
else:
# 采购没有手动“重新执行”入口。即使错误属于
# 技术上可重试,也先留给人工判断,避免隐式重复采购。
elif code in _QUEUE_BLOCKING_ERROR_CODES:
status = TaskStatus.MANUAL_REVIEW
else:
# 一次任务只自动执行一次;再次采购只能由用户明确发起,且仍需
# 通过不可逆标记等现有安全预检。
status = TaskStatus.FAILED
return self._repository.save_purchase_failure(
remote_task_id,
attempt_id,
status,
code,
message,
retryable,
False,
step,
dict(diagnostics),
)