feat: 任务失败后继续执行下一条 (#170)
This commit is contained in:
@@ -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),
|
||||
)
|
||||
|
||||
Reference in New Issue
Block a user