兼容历史资源outbox关联标识

This commit is contained in:
zhx 2026-07-13 23:53:01 +08:00
parent 175ddbea7e
commit e0cd7c12c9
2 changed files with 77 additions and 2 deletions

View File

@ -151,11 +151,19 @@ func walletOutboxRocketMessage(topic string, tagMode config.WalletEventTagMode,
default: default:
return rocketmqx.Message{}, fmt.Errorf("unsupported wallet event tag mode %q", tagMode) return rocketmqx.Message{}, fmt.Errorf("unsupported wallet event tag mode %q", tagMode)
} }
transactionID := strings.TrimSpace(record.TransactionID)
if transactionID == "" && isHistoricalResourceOutboxRecord(record) {
// 2026-07-11 以前的资源事实没有金融 transaction_idevent_id 已由
// event_type+command_id+user_id+resource_id 稳定派生。发布时使用它作为
// correlation id 与当前写入逻辑一致,避免为了回放改写已提交的 payload
// 同时严格限制为 RESOURCE 和已知资源事件,绝不替金融事实补造交易号。
transactionID = strings.TrimSpace(record.EventID)
}
body, err := walletmq.EncodeWalletOutboxMessage(walletmq.WalletOutboxMessage{ body, err := walletmq.EncodeWalletOutboxMessage(walletmq.WalletOutboxMessage{
AppCode: record.AppCode, AppCode: record.AppCode,
EventID: record.EventID, EventID: record.EventID,
EventType: eventTag, EventType: eventTag,
TransactionID: record.TransactionID, TransactionID: transactionID,
CommandID: record.CommandID, CommandID: record.CommandID,
UserID: record.UserID, UserID: record.UserID,
AssetType: record.AssetType, AssetType: record.AssetType,
@ -170,11 +178,31 @@ func walletOutboxRocketMessage(topic string, tagMode config.WalletEventTagMode,
return rocketmqx.Message{ return rocketmqx.Message{
Topic: topic, Topic: topic,
Tag: publishTag, Tag: publishTag,
Keys: []string{record.EventID, record.TransactionID, record.CommandID}, Keys: []string{record.EventID, transactionID, record.CommandID},
Body: body, Body: body,
}, nil }, nil
} }
func isHistoricalResourceOutboxRecord(record mysqlstorage.WalletOutboxRecord) bool {
if strings.TrimSpace(record.EventID) == "" || !strings.EqualFold(strings.TrimSpace(record.AssetType), "RESOURCE") {
return false
}
switch strings.TrimSpace(record.EventType) {
case "GiftConfigChanged",
"ResourceChanged",
"ResourceGrantRevoked",
"ResourceGranted",
"ResourceGroupChanged",
"ResourceGroupGranted",
"UserResourceChanged",
"VipEffectiveChanged",
"VipTrialCardGranted":
return true
default:
return false
}
}
func deadWalletOutboxReason(record mysqlstorage.WalletOutboxRecord) string { func deadWalletOutboxReason(record mysqlstorage.WalletOutboxRecord) string {
last := strings.TrimSpace(record.LastError) last := strings.TrimSpace(record.LastError)
if last == "" { if last == "" {

View File

@ -79,6 +79,53 @@ func TestWalletOutboxRocketMessageRejectsUnsafeEventTypeTag(t *testing.T) {
} }
} }
func TestWalletOutboxRocketMessageRestoresHistoricalResourceCorrelationID(t *testing.T) {
for _, eventType := range []string{
"GiftConfigChanged",
"ResourceChanged",
"ResourceGrantRevoked",
"ResourceGranted",
"ResourceGroupChanged",
"ResourceGroupGranted",
"UserResourceChanged",
"VipEffectiveChanged",
"VipTrialCardGranted",
} {
t.Run(eventType, func(t *testing.T) {
record := validWalletOutboxRecord()
record.EventID = "wev-historical-resource"
record.EventType = eventType
record.TransactionID = ""
record.AssetType = "RESOURCE"
message, err := walletOutboxRocketMessage("hyapp_wallet_outbox", config.WalletEventTagModeEventType, record)
if err != nil {
t.Fatalf("historical resource fact was rejected: %v", err)
}
decoded, err := walletmq.DecodeWalletOutboxMessage(message.Body)
if err != nil {
t.Fatalf("DecodeWalletOutboxMessage failed: %v", err)
}
if decoded.TransactionID != record.EventID || message.Keys[1] != record.EventID {
t.Fatalf("correlation id mismatch: decoded=%q keys=%v", decoded.TransactionID, message.Keys)
}
})
}
}
func TestWalletOutboxRocketMessageDoesNotInventFinancialTransactionID(t *testing.T) {
record := validWalletOutboxRecord()
record.TransactionID = ""
if _, err := walletOutboxRocketMessage("hyapp_wallet_outbox", config.WalletEventTagModeEventType, record); err == nil {
t.Fatal("financial fact without transaction_id must remain invalid")
}
record.EventType = "UnknownResourceEvent"
record.AssetType = "RESOURCE"
if _, err := walletOutboxRocketMessage("hyapp_wallet_outbox", config.WalletEventTagModeEventType, record); err == nil {
t.Fatal("unknown resource fact must not receive a synthetic transaction_id")
}
}
func validWalletOutboxRecord() mysqlstorage.WalletOutboxRecord { func validWalletOutboxRecord() mysqlstorage.WalletOutboxRecord {
return mysqlstorage.WalletOutboxRecord{ return mysqlstorage.WalletOutboxRecord{
AppCode: "lalu", AppCode: "lalu",