Hyperswitch状态机:支付状态流转管理
概述
在现代支付系统中,状态管理是确保交易完整性和一致性的核心机制。Hyperswitch作为开源支付基础设施,实现了高度精细化的支付状态机(State Machine)管理,为开发者提供了强大而灵活的支付状态流转控制能力。
本文将深入解析Hyperswitch的支付状态机设计,涵盖状态定义、流转规则、业务逻辑实现以及最佳实践。
核心状态枚举
支付意图状态(IntentStatus)
Hyperswitch定义了完善的支付意图状态枚举,每种状态都有明确的业务含义:
pub enum IntentStatus {
/// 支付成功,可发起退款和争议
Succeeded,
/// 支付失败,不可发起退款和争议
Failed,
/// 支付已取消
Cancelled,
/// 捕获后取消
CancelledPostCapture,
/// 支付处理中
Processing,
/// 需要客户操作
RequiresCustomerAction,
/// 需要商户操作(如人工欺诈审核)
RequiresMerchantAction,
/// 需要支付方法确认
RequiresPaymentMethod,
#[default]
/// 需要确认(默认状态)
RequiresConfirmation,
/// 需要捕获
RequiresCapture,
/// 部分捕获(剩余金额不可捕获)
PartiallyCaptured,
/// 部分捕获且剩余金额可捕获
PartiallyCapturedAndCapturable,
/// 部分授权且需要捕获
PartiallyAuthorizedAndRequiresCapture,
/// 请求与处理器接收的金额/货币存在差异
Conflicted,
/// 支付过期
Expired,
}
支付尝试状态(AttemptStatus)
支付尝试状态管理每次支付尝试的生命周期:
pub enum AttemptStatus {
Started, // 尝试开始
AuthenticationFailed, // 认证失败
RouterDeclined, // 路由拒绝
AuthenticationPending, // 认证挂起
AuthenticationSuccessful, // 认证成功
Authorized, // 已授权
AuthorizationFailed, // 授权失败
Charged, // 已扣款
Authorizing, // 授权中
CodInitiated, // COD初始化
Voided, // 已作废
VoidedPostCharge, // 扣款后作废
VoidInitiated, // 作废初始化
CaptureInitiated, // 捕获初始化
CaptureFailed, // 捕获失败
VoidFailed, // 作废失败
AutoRefunded, // 自动退款
PartialCharged, // 部分扣款
PartiallyAuthorized, // 部分授权
PartialChargedAndChargeable, // 部分扣款且可继续扣款
Unresolved, // 未解决
#[default]
Pending, // 挂起(默认)
Failure, // 失败
PaymentMethodAwaited, // 等待支付方法
ConfirmationAwaited, // 等待确认
DeviceDataCollectionPending, // 设备数据收集挂起
IntegrityFailure, // 完整性失败
Expired, // 过期
}
状态流转机制
状态机流程图
终端状态判定
Hyperswitch提供了明确的状态终端判定方法:
impl IntentStatus {
/// 判断支付意图是否处于终端状态
pub fn is_in_terminal_state(self) -> bool {
match self {
Self::Succeeded
| Self::Failed
| Self::Cancelled
| Self::CancelledPostCapture
| Self::PartiallyCaptured
| Self::Expired => true,
_ => false,
}
}
}
impl AttemptStatus {
/// 判断支付尝试是否处于终端状态
pub fn is_terminal_status(self) -> bool {
match self {
Self::RouterDeclined
| Self::Charged
| Self::AutoRefunded
| Self::Voided
| Self::VoidedPostCharge
| Self::VoidFailed
| Self::CaptureFailed
| Self::Failure
| Self::PartialCharged
| Self::Expired => true,
_ => false,
}
}
/// 判断支付尝试是否成功
pub fn is_success(self) -> bool {
matches!(self, Self::Charged | Self::PartialCharged)
}
}
状态转换逻辑
状态转换表
| 当前状态 | 可转换状态 | 触发条件 | 业务含义 |
|---|---|---|---|
| RequiresConfirmation | Processing | 支付确认 | 开始处理支付请求 |
| Processing | RequiresCustomerAction | 需要3DS认证 | 等待客户完成认证 |
| Processing | RequiresMerchantAction | 欺诈审核 | 等待商户人工审核 |
| Processing | RequiresCapture | 授权成功 | 等待捕获资金 |
| RequiresCapture | Succeeded | 捕获成功 | 支付完成 |
| RequiresCapture | PartiallyCaptured | 部分捕获 | 部分金额捕获完成 |
| Processing | Failed | 支付失败 | 终止支付流程 |
| Processing | Cancelled | 用户取消 | 支付被取消 |
状态转换实现
Hyperswitch使用模式匹配实现状态转换:
fn handle_payment_response(
current_status: IntentStatus,
connector_response: ConnectorResponse
) -> Result<IntentStatus, PaymentError> {
match (current_status, connector_response) {
(IntentStatus::Processing, ConnectorResponse::Authorized) => {
Ok(IntentStatus::RequiresCapture)
}
(IntentStatus::Processing, ConnectorResponse::Charged) => {
Ok(IntentStatus::Succeeded)
}
(IntentStatus::RequiresCapture, ConnectorResponse::CaptureSuccess) => {
Ok(IntentStatus::Succeeded)
}
(IntentStatus::Processing, ConnectorResponse::AuthenticationRequired) => {
Ok(IntentStatus::RequiresCustomerAction)
}
(_, ConnectorResponse::Failed) => {
Ok(IntentStatus::Failed)
}
_ => Err(PaymentError::InvalidStateTransition),
}
}
业务场景应用
场景1:标准支付流程
场景2:3D Secure认证流程
最佳实践
1. 状态监控与告警
// 监控长时间处于非终端状态的支付
async fn monitor_stuck_payments() {
let stuck_payments = payment_repository
.find_by_status_and_duration(
vec![
IntentStatus::Processing,
IntentStatus::RequiresCustomerAction,
IntentStatus::RequiresMerchantAction,
],
Duration::hours(1)
)
.await;
for payment in stuck_payments {
alert_system.notify_stuck_payment(payment.id);
}
}
2. 状态恢复机制
// 处理网络中断后的状态恢复
async fn recover_payment_state(payment_id: String) -> Result<(), RecoveryError> {
let payment = payment_repository.find_by_id(payment_id).await?;
if payment.status.is_in_terminal_state() {
return Ok(());
}
// 查询连接器获取最新状态
let latest_status = connector_client
.get_payment_status(&payment.connector_reference_id)
.await?;
// 更新本地状态
payment_repository
.update_status(payment_id, latest_status)
.await?;
Ok(())
}
3. 状态审计日志
// 记录状态变更历史
struct PaymentStateTransition {
payment_id: String,
from_status: IntentStatus,
to_status: IntentStatus,
timestamp: DateTime<Utc>,
reason: String,
actor: Option<String>,
}
impl PaymentStateTransition {
fn new(
payment_id: String,
from_status: IntentStatus,
to_status: IntentStatus,
reason: String
) -> Self {
Self {
payment_id,
from_status,
to_status,
timestamp: Utc::now(),
reason,
actor: None,
}
}
}
性能优化策略
状态查询优化
-- 创建状态索引加速查询
CREATE INDEX idx_payment_intent_status ON payment_intent (status);
CREATE INDEX idx_payment_attempt_status ON payment_attempt (status);
-- 状态统计查询
SELECT
status,
COUNT(*) as count,
AVG(EXTRACT(EPOCH FROM (updated_at - created_at))) as avg_duration_seconds
FROM payment_intent
WHERE created_at >= NOW() - INTERVAL '24 HOURS'
GROUP BY status
ORDER BY count DESC;
状态缓存策略
// 使用Redis缓存频繁访问的状态信息
#[derive(Clone, Serialize, Deserialize)]
struct CachedPaymentState {
payment_id: String,
status: IntentStatus,
last_updated: DateTime<Utc>,
attempt_count: u32,
}
impl CachedPaymentState {
async fn from_redis(
redis: &RedisClient,
payment_id: &str
) -> Option<Self> {
let key = format!("payment:state:{}", payment_id);
redis.get(&key).await.ok()?
}
async fn to_redis(
&self,
redis: &RedisClient,
ttl: Duration
) -> Result<(), RedisError> {
let key = format!("payment:state:{}", self.payment_id);
redis.set_ex(&key, self, ttl).await
}
}
总结
Hyperswitch的支付状态机设计体现了现代支付系统的最佳实践:
- 精细化的状态定义:27种支付尝试状态和16种支付意图状态,覆盖所有支付场景
- 明确的状态边界:通过
is_terminal_state()和is_success()方法提供清晰的状态判定 - 健壮的流转机制:基于模式匹配的状态转换,确保状态变更的合法性
- 完整的监控体系:状态审计、超时监控、异常恢复等全方位保障
- 高性能设计:索引优化、缓存策略、批量处理等性能优化措施
通过深入理解Hyperswitch的状态机设计,开发者可以更好地构建可靠、可扩展的支付系统,确保支付流程的完整性和一致性。
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考



