在分散式系統中,網路的不確定性、第三方服務的不可預測、跨服務間的資源競爭,都讓錯誤更頻繁、更難排查;
在編排架構下,以分類並結構化的方式處理錯誤,讓開發者專注於業務決策。
下表為常見錯誤類型與對應策略:
類型 | 常見情境 | 是否適合重試 | 建議策略 |
---|---|---|---|
Transient | 短暫網路錯誤、第三方 5xx、逾時 | 是 | 可考慮自動重試 |
Permanent | 參數驗證失敗、資源不存在、卡號無效 | 否 | 快速失敗並回報呼叫端 |
Business Failure | 庫存不足、額度不足、黑名單 | 視情況 | 分支流程、人工介入或補償 |
System Failure | Worker crash、部署重新啟動 | 不需要手動 | 交由平台事件重播與任務續跑復原 |
public interface EmailActivities {
void sendEmail(String messageId, String to, String subject, String body);
}
public class EmailActivitiesImpl implements EmailActivities {
private final EmailClient client; // 外部 SMTP/API 客戶端
private final SentRepository sentRepository; // 紀錄已寄出的 messageId(冪等)
public EmailActivitiesImpl(EmailClient client, SentRepository sentRepository) {
this.client = client;
this.sentRepository = sentRepository;
}
@Override
public void sendEmail(String messageId, String to, String subject, String body) {
if (sentRepository.exists(messageId)) {
return; // 已寄出則直接返回(冪等)
}
if (!EmailValidator.isValid(to)) {
// 永久性錯誤:不重試,使用型別化的 ApplicationFailure
throw ApplicationFailure.newNonRetryableFailure("invalid recipient", "InvalidRecipient");
}
try {
client.send(to, subject, body); // 可能拋出暫時性錯誤(例如網路問題)
sentRepository.save(messageId);
} catch (IOException e) {
// 暫時性錯誤:記錄內部細節,對外拋出型別化錯誤(附安全細節)
Activity.getExecutionContext().getLogger()
.error("sendEmail transient failure: messageId={}, to={}", messageId, to, e);
throw ApplicationFailure.newFailure("transient email failure", "TransientEmail", messageId, to);
}
}
}
ActivityFailure
→ 取出 ApplicationFailure.type
分支(例如 InvalidRecipient
永久性、TransientEmail
暫時性),決定補償或替代路徑。ActivityFailure
進入下方 catch。try {
email.sendEmail(messageId, to, subject, body);
} catch (ActivityFailure af) {
Throwable cause = af.getCause();
if (!(cause instanceof ApplicationFailure)) {
throw af; // 非應用層錯誤:直接拋出
}
ApplicationFailure app = (ApplicationFailure) cause;
switch (app.getType()) {
case "InvalidRecipient":
// 永久性:Workflow 決策改走人工/替代路徑
return;
case "TransientEmail":
// 暫時性:Workflow 決策稍後再試或切換方案(具體策略下篇)
return;
default:
throw af; // 未識別:讓 Workflow 失敗由上層處理
}
}
ApplicationFailure
由 SDK 上報;可於 Activity/Workflow 加上 log/metrics 以利觀測。本篇整理了分類、機制與分層,讓錯誤處理成為一級公民並降低複雜度;
下一篇將深入 Retry Policy 與 Timeout Policy 的參數設計與實務。