saga should refactor next

This commit is contained in:
yedongfu 2021-05-28 20:29:33 +08:00
parent 60c5c95972
commit fa8abb239f
3 changed files with 42 additions and 40 deletions

View File

@ -5,6 +5,7 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/yedf/dtm/common" "github.com/yedf/dtm/common"
"gorm.io/gorm"
"gorm.io/gorm/clause" "gorm.io/gorm/clause"
) )
@ -47,9 +48,16 @@ func Branch(c *gin.Context) (interface{}, error) {
branch := TransBranch{} branch := TransBranch{}
err := c.BindJSON(&branch) err := c.BindJSON(&branch)
e2p(err) e2p(err)
db := dbGet() branches := []TransBranch{branch, branch}
db.Must().Clauses(clause.OnConflict{ err = dbGet().Transaction(func(tx *gorm.DB) error {
DoNothing: true, db := &common.MyDb{DB: tx}
}).Create(&branch) branches[0].BranchType = "rollback"
branches[1].BranchType = "commit"
db.Must().Clauses(clause.OnConflict{
DoNothing: true,
}).Create(branches)
return nil
})
e2p(err)
return M{"message": "SUCCESS"}, nil return M{"message": "SUCCESS"}, nil
} }

View File

@ -29,6 +29,7 @@ func TestDtmSvr(t *testing.T) {
go StartSvr() go StartSvr()
go examples.SagaStartSvr() go examples.SagaStartSvr()
go examples.XaStartSvr() go examples.XaStartSvr()
go examples.TccStartSvr()
time.Sleep(time.Duration(100 * 1000 * 1000)) time.Sleep(time.Duration(100 * 1000 * 1000))
// 清理数据 // 清理数据
@ -36,7 +37,8 @@ func TestDtmSvr(t *testing.T) {
e2p(dbGet().Exec("truncate trans_branch").Error) e2p(dbGet().Exec("truncate trans_branch").Error)
e2p(dbGet().Exec("truncate trans_log").Error) e2p(dbGet().Exec("truncate trans_log").Error)
examples.ResetXaData() examples.ResetXaData()
// tccNormal(t) tccNormal(t)
tccRollback(t)
sagaCommittedPending(t) sagaCommittedPending(t)
sagaPreparePending(t) sagaPreparePending(t)
xaRollback(t) xaRollback(t)
@ -58,7 +60,7 @@ func TestCover(t *testing.T) {
// 测试使用的全局对象 // 测试使用的全局对象
var initdb = dbGet() var initdb = dbGet()
func getSagaModel(gid string) *TransGlobal { func getTransStatus(gid string) *TransGlobal {
sm := TransGlobal{} sm := TransGlobal{}
dbr := dbGet().Model(&sm).Where("gid=?", gid).First(&sm) dbr := dbGet().Model(&sm).Where("gid=?", gid).First(&sm)
e2p(dbr.Error) e2p(dbr.Error)
@ -67,7 +69,7 @@ func getSagaModel(gid string) *TransGlobal {
func getBranchesStatus(gid string) []string { func getBranchesStatus(gid string) []string {
steps := []TransBranch{} steps := []TransBranch{}
dbr := dbGet().Model(&TransBranch{}).Where("gid=?", gid).Find(&steps) dbr := dbGet().Model(&TransBranch{}).Where("gid=?", gid).Order("id").Find(&steps)
e2p(dbr.Error) e2p(dbr.Error)
status := []string{} status := []string{}
for _, step := range steps { for _, step := range steps {
@ -95,7 +97,7 @@ func xaNormal(t *testing.T) {
}) })
e2p(err) e2p(err)
WaitTransProcessed(gid) WaitTransProcessed(gid)
assert.Equal(t, []string{"succeed", "succeed"}, getBranchesStatus(gid)) assert.Equal(t, []string{"prepared", "succeed", "prepared", "succeed"}, getBranchesStatus(gid))
} }
func xaRollback(t *testing.T) { func xaRollback(t *testing.T) {
@ -119,25 +121,31 @@ func xaRollback(t *testing.T) {
logrus.Errorf("global transaction failed, so rollback") logrus.Errorf("global transaction failed, so rollback")
} }
WaitTransProcessed(gid) WaitTransProcessed(gid)
assert.Equal(t, []string{"failed"}, getBranchesStatus(gid)) assert.Equal(t, []string{"succeed", "prepared"}, getBranchesStatus(gid))
assert.Equal(t, "failed", getTransStatus(gid).Status)
} }
func tccNormal(t *testing.T) { func tccNormal(t *testing.T) {
tcc := genTcc("gid-normal-tcc", false, false) tcc := genTcc("gid-tcc-normal", false, false)
tcc.Prepare(tcc.QueryPrepared) tcc.Prepare(tcc.QueryPrepared)
assert.Equal(t, "prepared", getSagaModel(tcc.Gid).Status) assert.Equal(t, "prepared", getTransStatus(tcc.Gid).Status)
tcc.Commit() tcc.Commit()
assert.Equal(t, "committed", getSagaModel(tcc.Gid).Status) assert.Equal(t, "committed", getTransStatus(tcc.Gid).Status)
WaitTransProcessed(tcc.Gid) WaitTransProcessed(tcc.Gid)
assert.Equal(t, []string{"prepared", "succeed", "succeed", "prepared", "succeed", "succeed"}, getBranchesStatus(tcc.Gid)) assert.Equal(t, []string{"prepared", "succeed", "succeed", "prepared", "succeed", "succeed"}, getBranchesStatus(tcc.Gid))
}
func tccRollback(t *testing.T) {
tcc := genTcc("gid-tcc-rollback", false, true)
tcc.Commit()
WaitTransProcessed(tcc.Gid)
assert.Equal(t, []string{"succeed", "prepared", "succeed", "succeed", "prepared", "failed"}, getBranchesStatus(tcc.Gid))
} }
func sagaNormal(t *testing.T) { func sagaNormal(t *testing.T) {
saga := genSaga("gid-noramlSaga", false, false) saga := genSaga("gid-noramlSaga", false, false)
saga.Prepare(saga.QueryPrepared) saga.Prepare(saga.QueryPrepared)
assert.Equal(t, "prepared", getSagaModel(saga.Gid).Status) assert.Equal(t, "prepared", getTransStatus(saga.Gid).Status)
saga.Commit() saga.Commit()
assert.Equal(t, "committed", getSagaModel(saga.Gid).Status) assert.Equal(t, "committed", getTransStatus(saga.Gid).Status)
WaitTransProcessed(saga.Gid) WaitTransProcessed(saga.Gid)
assert.Equal(t, []string{"prepared", "succeed", "prepared", "succeed"}, getBranchesStatus(saga.Gid)) assert.Equal(t, []string{"prepared", "succeed", "prepared", "succeed"}, getBranchesStatus(saga.Gid))
} }
@ -147,7 +155,7 @@ func sagaRollback(t *testing.T) {
saga.Commit() saga.Commit()
WaitTransProcessed(saga.Gid) WaitTransProcessed(saga.Gid)
saga.Prepare(saga.QueryPrepared) saga.Prepare(saga.QueryPrepared)
assert.Equal(t, "failed", getSagaModel(saga.Gid).Status) assert.Equal(t, "failed", getTransStatus(saga.Gid).Status)
assert.Equal(t, []string{"failed", "succeed", "failed", "failed"}, getBranchesStatus(saga.Gid)) assert.Equal(t, []string{"failed", "succeed", "failed", "failed"}, getBranchesStatus(saga.Gid))
} }
@ -159,7 +167,7 @@ func sagaPrepareCancel(t *testing.T) {
CronTransOnce(-10*time.Second, "prepared") CronTransOnce(-10*time.Second, "prepared")
examples.SagaTransQueryResult = "" examples.SagaTransQueryResult = ""
config.PreparedExpire = 60 config.PreparedExpire = 60
assert.Equal(t, "canceled", getSagaModel(saga.Gid).Status) assert.Equal(t, "canceled", getTransStatus(saga.Gid).Status)
} }
func sagaPreparePending(t *testing.T) { func sagaPreparePending(t *testing.T) {
@ -168,9 +176,9 @@ func sagaPreparePending(t *testing.T) {
examples.SagaTransQueryResult = "PENDING" examples.SagaTransQueryResult = "PENDING"
CronTransOnce(-10*time.Second, "prepared") CronTransOnce(-10*time.Second, "prepared")
examples.SagaTransQueryResult = "" examples.SagaTransQueryResult = ""
assert.Equal(t, "prepared", getSagaModel(saga.Gid).Status) assert.Equal(t, "prepared", getTransStatus(saga.Gid).Status)
CronTransOnce(-10*time.Second, "prepared") CronTransOnce(-10*time.Second, "prepared")
assert.Equal(t, "succeed", getSagaModel(saga.Gid).Status) assert.Equal(t, "succeed", getTransStatus(saga.Gid).Status)
} }
func sagaCommittedPending(t *testing.T) { func sagaCommittedPending(t *testing.T) {
@ -183,7 +191,7 @@ func sagaCommittedPending(t *testing.T) {
assert.Equal(t, []string{"prepared", "succeed", "prepared", "prepared"}, getBranchesStatus(saga.Gid)) assert.Equal(t, []string{"prepared", "succeed", "prepared", "prepared"}, getBranchesStatus(saga.Gid))
CronTransOnce(-10*time.Second, "committed") CronTransOnce(-10*time.Second, "committed")
assert.Equal(t, []string{"prepared", "succeed", "prepared", "succeed"}, getBranchesStatus(saga.Gid)) assert.Equal(t, []string{"prepared", "succeed", "prepared", "succeed"}, getBranchesStatus(saga.Gid))
assert.Equal(t, "succeed", getSagaModel(saga.Gid).Status) assert.Equal(t, "succeed", getTransStatus(saga.Gid).Status)
} }
func genSaga(gid string, outFailed bool, inFailed bool) *dtm.Saga { func genSaga(gid string, outFailed bool, inFailed bool) *dtm.Saga {

View File

@ -137,8 +137,7 @@ func (t *TransTccProcessor) ExecBranch(db *common.MyDb, branch *TransBranch) str
body := resp.String() body := resp.String()
t.touch(db) t.touch(db)
if strings.Contains(body, "SUCCESS") { if strings.Contains(body, "SUCCESS") {
status := common.If(branch.BranchType == "cancel", "failed", "succeed").(string) branch.changeStatus(db, "succeed")
branch.changeStatus(db, status)
return "SUCCESS" return "SUCCESS"
} }
if branch.BranchType == "try" && strings.Contains(body, "FAIL") { if branch.BranchType == "try" && strings.Contains(body, "FAIL") {
@ -193,7 +192,7 @@ func (t *TransXaProcessor) ExecBranch(db *common.MyDb, branch *TransBranch) stri
if !strings.Contains(body, "SUCCESS") { if !strings.Contains(body, "SUCCESS") {
panic(fmt.Errorf("bad response: %s", body)) panic(fmt.Errorf("bad response: %s", body))
} }
branch.changeStatus(db, common.If(t.Status == "prepared", "failed", "succeed").(string)) branch.changeStatus(db, "succeed")
return "SUCCESS" return "SUCCESS"
} }
@ -201,25 +200,12 @@ func (t *TransXaProcessor) ProcessOnce(db *common.MyDb, branches []TransBranch)
if t.Status == "succeed" { if t.Status == "succeed" {
return return
} }
if t.Status == "committed" { currentType := common.If(t.Status == "committed", "commit", "rollback").(string)
for _, branch := range branches { for _, branch := range branches {
if branch.Status == "succeed" { if branch.BranchType == currentType && branch.Status != "succeed" {
continue
}
_ = t.ExecBranch(db, &branch)
t.touch(db) // 更新update_time避免被定时任务再次
}
t.changeStatus(db, "succeed")
} else if t.Status == "prepared" { // 未commit直接处理的情况为回滚场景
for _, branch := range branches {
if branch.Status == "failed" {
continue
}
_ = t.ExecBranch(db, &branch) _ = t.ExecBranch(db, &branch)
t.touch(db) t.touch(db)
} }
t.changeStatus(db, "failed")
} else {
e2p(fmt.Errorf("bad trans status: %s", t.Status))
} }
t.changeStatus(db, common.If(t.Status == "committed", "succeed", "failed").(string))
} }