tcc interface seems ok
This commit is contained in:
parent
486255034d
commit
94e8e4eff9
@ -162,7 +162,7 @@ func SdbExec(db *sql.DB, sql string, values ...interface{}) (affected int64, rer
|
|||||||
affected, rerr = r.RowsAffected()
|
affected, rerr = r.RowsAffected()
|
||||||
logrus.Printf("affected: %d for %s %v", affected, sql, values)
|
logrus.Printf("affected: %d for %s %v", affected, sql, values)
|
||||||
} else {
|
} else {
|
||||||
logrus.Printf("\x1b[31m\nexec error: %v for %s %v\x1b[0m\n", rerr, sql, values)
|
RedLogf("exec error: %v for %s %v", rerr, sql, values)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -174,7 +174,7 @@ func StxExec(tx *sql.Tx, sql string, values ...interface{}) (affected int64, rer
|
|||||||
affected, rerr = r.RowsAffected()
|
affected, rerr = r.RowsAffected()
|
||||||
logrus.Printf("affected: %d for %s %v", affected, sql, values)
|
logrus.Printf("affected: %d for %s %v", affected, sql, values)
|
||||||
} else {
|
} else {
|
||||||
logrus.Printf("\x1b[31m\nexec error: %v for %s %v\x1b[0m\n", rerr, sql, values)
|
RedLogf("exec error: %v for %s %v", rerr, sql, values)
|
||||||
}
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@ -205,6 +205,11 @@ func (f *formatter) Format(entry *logrus.Entry) ([]byte, error) {
|
|||||||
return b.Bytes(), nil
|
return b.Bytes(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// RedLogf 采用红色打印错误类信息
|
||||||
|
func RedLogf(fmt string, args ...interface{}) {
|
||||||
|
logrus.Errorf("\x1b[31m\n"+fmt+"\x1b[0m\n", args...)
|
||||||
|
}
|
||||||
|
|
||||||
// InitConfig init config
|
// InitConfig init config
|
||||||
func InitConfig(dir string, config interface{}) {
|
func InitConfig(dir string, config interface{}) {
|
||||||
logrus.SetFormatter(&formatter{})
|
logrus.SetFormatter(&formatter{})
|
||||||
|
|||||||
@ -2,11 +2,9 @@ package dtmcli
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/gin-gonic/gin"
|
"github.com/gin-gonic/gin"
|
||||||
"github.com/go-resty/resty/v2"
|
"github.com/go-resty/resty/v2"
|
||||||
"github.com/sirupsen/logrus"
|
|
||||||
"github.com/yedf/dtm/common"
|
"github.com/yedf/dtm/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -18,41 +16,38 @@ type Tcc struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TccGlobalFunc type of global tcc call
|
// TccGlobalFunc type of global tcc call
|
||||||
type TccGlobalFunc func(tcc *Tcc) error
|
type TccGlobalFunc func(tcc *Tcc) (interface{}, error)
|
||||||
|
|
||||||
// TccGlobalTransaction begin a tcc global transaction
|
// TccGlobalTransaction begin a tcc global transaction
|
||||||
// dtm dtm服务器地址
|
// dtm dtm服务器地址
|
||||||
// gid 全局事务id
|
// gid 全局事务id
|
||||||
// tccFunc tcc事务函数,里面会定义全局事务的分支
|
// tccFunc tcc事务函数,里面会定义全局事务的分支
|
||||||
func TccGlobalTransaction(dtm string, gid string, tccFunc TccGlobalFunc) (rerr error) {
|
func TccGlobalTransaction(dtm string, gid string, tccFunc TccGlobalFunc) (ret interface{}, rerr error) {
|
||||||
data := &M{
|
data := &M{
|
||||||
"gid": gid,
|
"gid": gid,
|
||||||
"trans_type": "tcc",
|
"trans_type": "tcc",
|
||||||
}
|
}
|
||||||
|
tcc := &Tcc{Dtm: dtm, Gid: gid}
|
||||||
|
resp, err := common.RestyClient.R().SetBody(data).Post(tcc.Dtm + "/prepare")
|
||||||
|
if IsFailure(resp, err) {
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
// 小概率情况下,prepare成功了,但是由于网络状况导致上面Failure,那么不执行下面defer的内容,等待超时后再回滚标记事务失败,也没有问题
|
||||||
defer func() {
|
defer func() {
|
||||||
var resp *resty.Response
|
|
||||||
var err error
|
|
||||||
var x interface{}
|
var x interface{}
|
||||||
if x = recover(); x != nil || rerr != nil {
|
if x = recover(); x != nil || IsFailure(ret, rerr) {
|
||||||
resp, err = common.RestyClient.R().SetBody(data).Post(dtm + "/abort")
|
resp, err = common.RestyClient.R().SetBody(data).Post(dtm + "/abort")
|
||||||
} else {
|
} else {
|
||||||
resp, err = common.RestyClient.R().SetBody(data).Post(dtm + "/submit")
|
resp, err = common.RestyClient.R().SetBody(data).Post(dtm + "/submit")
|
||||||
}
|
}
|
||||||
err2 := CheckDtmResponse(resp, err)
|
if IsFailure(resp, err) {
|
||||||
if err2 != nil {
|
common.RedLogf("submitting or abort global transaction error: %v resp: %s", err, resp.String())
|
||||||
logrus.Errorf("submitting or abort global transaction error: %v", err2)
|
|
||||||
}
|
}
|
||||||
if x != nil {
|
if x != nil {
|
||||||
panic(x)
|
panic(x)
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
tcc := &Tcc{Dtm: dtm, Gid: gid}
|
ret, rerr = tccFunc(tcc)
|
||||||
resp, err := common.RestyClient.R().SetBody(data).Post(tcc.Dtm + "/prepare")
|
|
||||||
rerr = CheckDtmResponse(resp, err)
|
|
||||||
if rerr != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
rerr = tccFunc(tcc)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,8 +80,7 @@ func (t *Tcc) CallBranch(body interface{}, tryURL string, confirmURL string, can
|
|||||||
"cancel": cancelURL,
|
"cancel": cancelURL,
|
||||||
}).
|
}).
|
||||||
Post(t.Dtm + "/registerTccBranch")
|
Post(t.Dtm + "/registerTccBranch")
|
||||||
err = CheckDtmResponse(resp, err)
|
if IsFailure(resp, err) {
|
||||||
if err != nil {
|
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
resp, err = common.RestyClient.R().
|
resp, err = common.RestyClient.R().
|
||||||
@ -99,8 +93,5 @@ func (t *Tcc) CallBranch(body interface{}, tryURL string, confirmURL string, can
|
|||||||
"branch_type": "try",
|
"branch_type": "try",
|
||||||
}).
|
}).
|
||||||
Post(tryURL)
|
Post(tryURL)
|
||||||
if err == nil && strings.Contains(resp.String(), "FAILURE") {
|
|
||||||
err = fmt.Errorf("branch return failure: %s", resp.String())
|
|
||||||
}
|
|
||||||
return resp, err
|
return resp, err
|
||||||
}
|
}
|
||||||
|
|||||||
@ -18,6 +18,21 @@ func MustGenGid(server string) string {
|
|||||||
return res["gid"]
|
return res["gid"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsFailure 如果err非空,或者ret是http的响应且包含FAILURE,那么返回true。此时认为业务调用失败
|
||||||
|
func IsFailure(res interface{}, err error) bool {
|
||||||
|
resp, ok := res.(*resty.Response)
|
||||||
|
return err != nil || ok && strings.Contains(resp.String(), "FAILURE")
|
||||||
|
}
|
||||||
|
|
||||||
|
// PanicIfFailure 如果err非空,或者ret是http的响应且包含FAILURE,那么Panic。此时认为业务调用失败
|
||||||
|
func PanicIfFailure(res interface{}, err error) {
|
||||||
|
resp, ok := res.(*resty.Response)
|
||||||
|
failure := err != nil || ok && strings.Contains(resp.String(), "FAILURE")
|
||||||
|
if failure {
|
||||||
|
panic(fmt.Errorf("dtm failure ret: %v err %v", res, err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// CheckDtmResponse check the response of dtm, if not ok ,generate error
|
// CheckDtmResponse check the response of dtm, if not ok ,generate error
|
||||||
func CheckDtmResponse(resp *resty.Response, err error) error {
|
func CheckDtmResponse(resp *resty.Response, err error) error {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|||||||
@ -7,6 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/sirupsen/logrus"
|
"github.com/sirupsen/logrus"
|
||||||
|
"github.com/yedf/dtm/common"
|
||||||
)
|
)
|
||||||
|
|
||||||
// CronTransOnce cron expired trans. use expireIn as expire time
|
// CronTransOnce cron expired trans. use expireIn as expire time
|
||||||
@ -53,7 +54,7 @@ func lockOneTrans(expireIn time.Duration) *TransGlobal {
|
|||||||
|
|
||||||
func handlePanic() {
|
func handlePanic() {
|
||||||
if err := recover(); err != nil {
|
if err := recover(); err != nil {
|
||||||
logrus.Errorf("\x1b[31m\n----panic %s handlered\x1b[0m\n%s", err.(error).Error(), string(debug.Stack()))
|
common.RedLogf("----panic %s handlered\n%s", err.(error).Error(), string(debug.Stack()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,35 +23,24 @@ func TestTccBarrier(t *testing.T) {
|
|||||||
|
|
||||||
func tccBarrierRollback(t *testing.T) {
|
func tccBarrierRollback(t *testing.T) {
|
||||||
gid := "tccBarrierRollback"
|
gid := "tccBarrierRollback"
|
||||||
err := dtmcli.TccGlobalTransaction(DtmServer, gid, func(tcc *dtmcli.Tcc) (rerr error) {
|
resp, err := dtmcli.TccGlobalTransaction(DtmServer, gid, func(tcc *dtmcli.Tcc) (interface{}, error) {
|
||||||
res1, rerr := tcc.CallBranch(&examples.TransReq{Amount: 30}, Busi+"/TccBTransOutTry", Busi+"/TccBTransOutConfirm", Busi+"/TccBTransOutCancel")
|
resp, err := tcc.CallBranch(&examples.TransReq{Amount: 30}, Busi+"/TccBTransOutTry", Busi+"/TccBTransOutConfirm", Busi+"/TccBTransOutCancel")
|
||||||
assert.Contains(t, res1.String(), "SUCCESS")
|
assert.True(t, !dtmcli.IsFailure(resp, err))
|
||||||
_, rerr = tcc.CallBranch(&examples.TransReq{Amount: 30, TransInResult: "FAILURE"}, Busi+"/TccBTransInTry", Busi+"/TccBTransInConfirm", Busi+"/TccBTransInCancel")
|
return tcc.CallBranch(&examples.TransReq{Amount: 30, TransInResult: "FAILURE"}, Busi+"/TccBTransInTry", Busi+"/TccBTransInConfirm", Busi+"/TccBTransInCancel")
|
||||||
assert.Error(t, rerr)
|
|
||||||
return
|
|
||||||
})
|
})
|
||||||
assert.Error(t, err)
|
assert.True(t, dtmcli.IsFailure(resp, err))
|
||||||
WaitTransProcessed(gid)
|
WaitTransProcessed(gid)
|
||||||
assert.Equal(t, "failed", getTransStatus(gid))
|
assert.Equal(t, "failed", getTransStatus(gid))
|
||||||
}
|
}
|
||||||
|
|
||||||
func tccBarrierNormal(t *testing.T) {
|
func tccBarrierNormal(t *testing.T) {
|
||||||
gid := "tccBarrierNormal"
|
gid := "tccBarrierNormal"
|
||||||
err := dtmcli.TccGlobalTransaction(DtmServer, gid, func(tcc *dtmcli.Tcc) (rerr error) {
|
resp, err := dtmcli.TccGlobalTransaction(DtmServer, gid, func(tcc *dtmcli.Tcc) (interface{}, error) {
|
||||||
res1, rerr := tcc.CallBranch(&examples.TransReq{Amount: 30}, Busi+"/TccBTransOutTry", Busi+"/TccBTransOutConfirm", Busi+"/TccBTransOutCancel")
|
resp, err := tcc.CallBranch(&examples.TransReq{Amount: 30}, Busi+"/TccBTransOutTry", Busi+"/TccBTransOutConfirm", Busi+"/TccBTransOutCancel")
|
||||||
e2p(rerr)
|
assert.True(t, !dtmcli.IsFailure(resp, err))
|
||||||
if res1.StatusCode() != 200 {
|
return tcc.CallBranch(&examples.TransReq{Amount: 30}, Busi+"/TccBTransInTry", Busi+"/TccBTransInConfirm", Busi+"/TccBTransInCancel")
|
||||||
return fmt.Errorf("bad status code: %d", res1.StatusCode())
|
|
||||||
}
|
|
||||||
res2, rerr := tcc.CallBranch(&examples.TransReq{Amount: 30}, Busi+"/TccBTransInTry", Busi+"/TccBTransInConfirm", Busi+"/TccBTransInCancel")
|
|
||||||
e2p(rerr)
|
|
||||||
if res2.StatusCode() != 200 {
|
|
||||||
return fmt.Errorf("bad status code: %d", res2.StatusCode())
|
|
||||||
}
|
|
||||||
logrus.Printf("tcc returns: %s, %s", res1.String(), res2.String())
|
|
||||||
return
|
|
||||||
})
|
})
|
||||||
e2p(err)
|
assert.True(t, !dtmcli.IsFailure(resp, err))
|
||||||
WaitTransProcessed(gid)
|
WaitTransProcessed(gid)
|
||||||
assert.Equal(t, "succeed", getTransStatus(gid))
|
assert.Equal(t, "succeed", getTransStatus(gid))
|
||||||
}
|
}
|
||||||
@ -60,7 +49,7 @@ func tccBarrierDisorder(t *testing.T) {
|
|||||||
timeoutChan := make(chan string, 2)
|
timeoutChan := make(chan string, 2)
|
||||||
finishedChan := make(chan string, 2)
|
finishedChan := make(chan string, 2)
|
||||||
gid := "tccBarrierDisorder"
|
gid := "tccBarrierDisorder"
|
||||||
err := dtmcli.TccGlobalTransaction(DtmServer, gid, func(tcc *dtmcli.Tcc) (rerr error) {
|
_, err := dtmcli.TccGlobalTransaction(DtmServer, gid, func(tcc *dtmcli.Tcc) (interface{}, error) {
|
||||||
body := &examples.TransReq{Amount: 30}
|
body := &examples.TransReq{Amount: 30}
|
||||||
tryURL := Busi + "/TccBTransOutTry"
|
tryURL := Busi + "/TccBTransOutTry"
|
||||||
confirmURL := Busi + "/TccBTransOutConfirm"
|
confirmURL := Busi + "/TccBTransOutConfirm"
|
||||||
@ -91,8 +80,7 @@ func tccBarrierDisorder(t *testing.T) {
|
|||||||
"cancel": cancelURL,
|
"cancel": cancelURL,
|
||||||
}).
|
}).
|
||||||
Post(tcc.Dtm + "/registerTccBranch")
|
Post(tcc.Dtm + "/registerTccBranch")
|
||||||
e2p(err)
|
assert.True(t, !dtmcli.IsFailure(r, err))
|
||||||
assert.True(t, strings.Contains(r.String(), "SUCCESS"))
|
|
||||||
go func() {
|
go func() {
|
||||||
logrus.Printf("sleeping to wait for tcc try timeout")
|
logrus.Printf("sleeping to wait for tcc try timeout")
|
||||||
<-timeoutChan
|
<-timeoutChan
|
||||||
@ -119,7 +107,7 @@ func tccBarrierDisorder(t *testing.T) {
|
|||||||
<-finishedChan
|
<-finishedChan
|
||||||
<-finishedChan
|
<-finishedChan
|
||||||
time.Sleep(100 * time.Millisecond)
|
time.Sleep(100 * time.Millisecond)
|
||||||
return fmt.Errorf("a cancelled tcc")
|
return nil, fmt.Errorf("a cancelled tcc")
|
||||||
})
|
})
|
||||||
assert.Error(t, err, fmt.Errorf("a cancelled tcc"))
|
assert.Error(t, err, fmt.Errorf("a cancelled tcc"))
|
||||||
assert.Equal(t, []string{"succeed", "prepared", "prepared"}, getBranchesStatus(gid))
|
assert.Equal(t, []string{"succeed", "prepared", "prepared"}, getBranchesStatus(gid))
|
||||||
|
|||||||
@ -18,28 +18,26 @@ func TestTcc(t *testing.T) {
|
|||||||
func tccNormal(t *testing.T) {
|
func tccNormal(t *testing.T) {
|
||||||
data := &examples.TransReq{Amount: 30}
|
data := &examples.TransReq{Amount: 30}
|
||||||
gid := "tccNormal"
|
gid := "tccNormal"
|
||||||
err := dtmcli.TccGlobalTransaction(examples.DtmServer, gid, func(tcc *dtmcli.Tcc) (rerr error) {
|
ret, err := dtmcli.TccGlobalTransaction(examples.DtmServer, gid, func(tcc *dtmcli.Tcc) (interface{}, error) {
|
||||||
_, rerr = tcc.CallBranch(data, Busi+"/TransOut", Busi+"/TransOutConfirm", Busi+"/TransOutRevert")
|
resp, err := tcc.CallBranch(data, Busi+"/TransOut", Busi+"/TransOutConfirm", Busi+"/TransOutRevert")
|
||||||
e2p(rerr)
|
if dtmcli.IsFailure(resp, err) {
|
||||||
_, rerr = tcc.CallBranch(data, Busi+"/TransIn", Busi+"/TransInConfirm", Busi+"/TransInRevert")
|
return resp, err
|
||||||
e2p(rerr)
|
}
|
||||||
return
|
return tcc.CallBranch(data, Busi+"/TransIn", Busi+"/TransInConfirm", Busi+"/TransInRevert")
|
||||||
})
|
})
|
||||||
e2p(err)
|
dtmcli.PanicIfFailure(ret, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
func tccRollback(t *testing.T) {
|
func tccRollback(t *testing.T) {
|
||||||
gid := "tccRollback"
|
gid := "tccRollback"
|
||||||
data := &examples.TransReq{Amount: 30, TransInResult: "FAILURE"}
|
data := &examples.TransReq{Amount: 30, TransInResult: "FAILURE"}
|
||||||
err := dtmcli.TccGlobalTransaction(examples.DtmServer, gid, func(tcc *dtmcli.Tcc) (rerr error) {
|
resp, err := dtmcli.TccGlobalTransaction(examples.DtmServer, gid, func(tcc *dtmcli.Tcc) (interface{}, error) {
|
||||||
resp, rerr := tcc.CallBranch(data, Busi+"/TransOut", Busi+"/TransOutConfirm", Busi+"/TransOutRevert")
|
resp, rerr := tcc.CallBranch(data, Busi+"/TransOut", Busi+"/TransOutConfirm", Busi+"/TransOutRevert")
|
||||||
assert.Contains(t, resp.String(), "SUCCESS")
|
assert.True(t, !dtmcli.IsFailure(resp, rerr))
|
||||||
examples.MainSwitch.TransOutRevertResult.SetOnce("PENDING")
|
examples.MainSwitch.TransOutRevertResult.SetOnce("PENDING")
|
||||||
_, rerr = tcc.CallBranch(data, Busi+"/TransIn", Busi+"/TransInConfirm", Busi+"/TransInRevert")
|
return tcc.CallBranch(data, Busi+"/TransIn", Busi+"/TransInConfirm", Busi+"/TransInRevert")
|
||||||
assert.Error(t, rerr)
|
|
||||||
return
|
|
||||||
})
|
})
|
||||||
assert.Error(t, err)
|
assert.True(t, dtmcli.IsFailure(resp, err))
|
||||||
WaitTransProcessed(gid)
|
WaitTransProcessed(gid)
|
||||||
assert.Equal(t, "aborting", getTransStatus(gid))
|
assert.Equal(t, "aborting", getTransStatus(gid))
|
||||||
CronTransOnce(60 * time.Second)
|
CronTransOnce(60 * time.Second)
|
||||||
|
|||||||
@ -12,9 +12,8 @@ func TccSetup(app *gin.Engine) {
|
|||||||
app.POST(BusiAPI+"/TransInTccParent", common.WrapHandler(func(c *gin.Context) (interface{}, error) {
|
app.POST(BusiAPI+"/TransInTccParent", common.WrapHandler(func(c *gin.Context) (interface{}, error) {
|
||||||
tcc, err := dtmcli.TccFromReq(c)
|
tcc, err := dtmcli.TccFromReq(c)
|
||||||
e2p(err)
|
e2p(err)
|
||||||
req := reqFrom(c)
|
|
||||||
logrus.Printf("TransInTccParent ")
|
logrus.Printf("TransInTccParent ")
|
||||||
_, rerr := tcc.CallBranch(&TransReq{Amount: req.Amount}, Busi+"/TransIn", Busi+"/TransInConfirm", Busi+"/TransInRevert")
|
_, rerr := tcc.CallBranch(&TransReq{Amount: reqFrom(c).Amount}, Busi+"/TransIn", Busi+"/TransInConfirm", Busi+"/TransInRevert")
|
||||||
e2p(rerr)
|
e2p(rerr)
|
||||||
return M{"dtm_result": "SUCCESS"}, nil
|
return M{"dtm_result": "SUCCESS"}, nil
|
||||||
}))
|
}))
|
||||||
@ -22,17 +21,15 @@ func TccSetup(app *gin.Engine) {
|
|||||||
|
|
||||||
// TccFireRequestNested 1
|
// TccFireRequestNested 1
|
||||||
func TccFireRequestNested() string {
|
func TccFireRequestNested() string {
|
||||||
logrus.Printf("tcc transaction begin")
|
|
||||||
gid := dtmcli.MustGenGid(DtmServer)
|
gid := dtmcli.MustGenGid(DtmServer)
|
||||||
err := dtmcli.TccGlobalTransaction(DtmServer, gid, func(tcc *dtmcli.Tcc) (rerr error) {
|
ret, err := dtmcli.TccGlobalTransaction(DtmServer, gid, func(tcc *dtmcli.Tcc) (interface{}, error) {
|
||||||
res1, rerr := tcc.CallBranch(&TransReq{Amount: 30}, Busi+"/TransOut", Busi+"/TransOutConfirm", Busi+"/TransOutRevert")
|
resp, err := tcc.CallBranch(&TransReq{Amount: 30}, Busi+"/TransOut", Busi+"/TransOutConfirm", Busi+"/TransOutRevert")
|
||||||
e2p(rerr)
|
if dtmcli.IsFailure(resp, err) {
|
||||||
res2, rerr := tcc.CallBranch(&TransReq{Amount: 30}, Busi+"/TransInTccParent", Busi+"/TransInConfirm", Busi+"/TransInRevert")
|
return resp, err
|
||||||
e2p(rerr)
|
}
|
||||||
logrus.Printf("tcc returns: %s, %s", res1.String(), res2.String())
|
return tcc.CallBranch(&TransReq{Amount: 30}, Busi+"/TransInTccParent", Busi+"/TransInConfirm", Busi+"/TransInRevert")
|
||||||
return
|
|
||||||
})
|
})
|
||||||
e2p(err)
|
dtmcli.PanicIfFailure(ret, err)
|
||||||
return gid
|
return gid
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -40,13 +37,13 @@ func TccFireRequestNested() string {
|
|||||||
func TccFireRequest() string {
|
func TccFireRequest() string {
|
||||||
logrus.Printf("tcc simple transaction begin")
|
logrus.Printf("tcc simple transaction begin")
|
||||||
gid := dtmcli.MustGenGid(DtmServer)
|
gid := dtmcli.MustGenGid(DtmServer)
|
||||||
err := dtmcli.TccGlobalTransaction(DtmServer, gid, func(tcc *dtmcli.Tcc) (rerr error) {
|
ret, err := dtmcli.TccGlobalTransaction(DtmServer, gid, func(tcc *dtmcli.Tcc) (interface{}, error) {
|
||||||
res1, rerr := tcc.CallBranch(&TransReq{Amount: 30}, Busi+"/TransOut", Busi+"/TransOutConfirm", Busi+"/TransOutRevert")
|
resp, err := tcc.CallBranch(&TransReq{Amount: 30}, Busi+"/TransOut", Busi+"/TransOutConfirm", Busi+"/TransOutRevert")
|
||||||
e2p(rerr)
|
if dtmcli.IsFailure(resp, err) {
|
||||||
res2, rerr := tcc.CallBranch(&TransReq{Amount: 30}, Busi+"/TransIn", Busi+"/TransInConfirm", Busi+"/TransInRevert")
|
return resp, err
|
||||||
logrus.Printf("tcc returns: %s, %s", res1.String(), res2.String())
|
}
|
||||||
return
|
return tcc.CallBranch(&TransReq{Amount: 30}, Busi+"/TransIn", Busi+"/TransInConfirm", Busi+"/TransInRevert")
|
||||||
})
|
})
|
||||||
e2p(err)
|
dtmcli.PanicIfFailure(ret, err)
|
||||||
return gid
|
return gid
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,15 +14,14 @@ import (
|
|||||||
func TccBarrierFireRequest() string {
|
func TccBarrierFireRequest() string {
|
||||||
logrus.Printf("tcc transaction begin")
|
logrus.Printf("tcc transaction begin")
|
||||||
gid := dtmcli.MustGenGid(DtmServer)
|
gid := dtmcli.MustGenGid(DtmServer)
|
||||||
err := dtmcli.TccGlobalTransaction(DtmServer, gid, func(tcc *dtmcli.Tcc) (rerr error) {
|
ret, err := dtmcli.TccGlobalTransaction(DtmServer, gid, func(tcc *dtmcli.Tcc) (interface{}, error) {
|
||||||
res1, rerr := tcc.CallBranch(&TransReq{Amount: 30}, Busi+"/TccBTransOutTry", Busi+"/TccBTransOutConfirm", Busi+"/TccBTransOutCancel")
|
resp, err := tcc.CallBranch(&TransReq{Amount: 30}, Busi+"/TccBTransOutTry", Busi+"/TccBTransOutConfirm", Busi+"/TccBTransOutCancel")
|
||||||
common.CheckRestySuccess(res1, rerr)
|
if dtmcli.IsFailure(resp, err) {
|
||||||
res2, rerr := tcc.CallBranch(&TransReq{Amount: 30}, Busi+"/TccBTransInTry", Busi+"/TccBTransInConfirm", Busi+"/TccBTransInCancel")
|
return resp, err
|
||||||
common.CheckRestySuccess(res1, rerr)
|
}
|
||||||
logrus.Printf("tcc returns: %s, %s", res1.String(), res2.String())
|
return tcc.CallBranch(&TransReq{Amount: 30}, Busi+"/TccBTransInTry", Busi+"/TccBTransInConfirm", Busi+"/TccBTransInCancel")
|
||||||
return
|
|
||||||
})
|
})
|
||||||
e2p(err)
|
dtmcli.PanicIfFailure(ret, err)
|
||||||
return gid
|
return gid
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -40,11 +40,10 @@ func XaFireRequest() string {
|
|||||||
|
|
||||||
func xaTransIn(c *gin.Context) (interface{}, error) {
|
func xaTransIn(c *gin.Context) (interface{}, error) {
|
||||||
err := XaClient.XaLocalTransaction(c, func(db *sql.DB, xa *dtmcli.Xa) (rerr error) {
|
err := XaClient.XaLocalTransaction(c, func(db *sql.DB, xa *dtmcli.Xa) (rerr error) {
|
||||||
req := reqFrom(c)
|
if reqFrom(c).TransInResult == "FAILURE" {
|
||||||
if req.TransInResult == "FAILURE" {
|
|
||||||
return fmt.Errorf("tranIn FAILURE")
|
return fmt.Errorf("tranIn FAILURE")
|
||||||
}
|
}
|
||||||
_, rerr = common.SdbExec(db, "update dtm_busi.user_account set balance=balance+? where user_id=?", req.Amount, 2)
|
_, rerr = common.SdbExec(db, "update dtm_busi.user_account set balance=balance+? where user_id=?", reqFrom(c).Amount, 2)
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
if err != nil && strings.Contains(err.Error(), "FAILURE") {
|
if err != nil && strings.Contains(err.Error(), "FAILURE") {
|
||||||
@ -56,11 +55,10 @@ func xaTransIn(c *gin.Context) (interface{}, error) {
|
|||||||
|
|
||||||
func xaTransOut(c *gin.Context) (interface{}, error) {
|
func xaTransOut(c *gin.Context) (interface{}, error) {
|
||||||
err := XaClient.XaLocalTransaction(c, func(db *sql.DB, xa *dtmcli.Xa) (rerr error) {
|
err := XaClient.XaLocalTransaction(c, func(db *sql.DB, xa *dtmcli.Xa) (rerr error) {
|
||||||
req := reqFrom(c)
|
if reqFrom(c).TransOutResult == "FAILURE" {
|
||||||
if req.TransOutResult == "FAILURE" {
|
|
||||||
return fmt.Errorf("tranOut failed")
|
return fmt.Errorf("tranOut failed")
|
||||||
}
|
}
|
||||||
_, rerr = common.SdbExec(db, "update dtm_busi.user_account set balance=balance-? where user_id=?", req.Amount, 1)
|
_, rerr = common.SdbExec(db, "update dtm_busi.user_account set balance=balance-? where user_id=?", reqFrom(c).Amount, 1)
|
||||||
return
|
return
|
||||||
})
|
})
|
||||||
e2p(err)
|
e2p(err)
|
||||||
|
|||||||
@ -38,10 +38,15 @@ func GenTransReq(amount int, outFailed bool, inFailed bool) *TransReq {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func reqFrom(c *gin.Context) *TransReq {
|
func reqFrom(c *gin.Context) *TransReq {
|
||||||
|
v, ok := c.Get("trans_req")
|
||||||
|
if !ok {
|
||||||
req := TransReq{}
|
req := TransReq{}
|
||||||
err := c.BindJSON(&req)
|
err := c.BindJSON(&req)
|
||||||
e2p(err)
|
e2p(err)
|
||||||
return &req
|
c.Set("trans_req", &req)
|
||||||
|
v = &req
|
||||||
|
}
|
||||||
|
return v.(*TransReq)
|
||||||
}
|
}
|
||||||
|
|
||||||
func infoFromContext(c *gin.Context) *dtmcli.TransInfo {
|
func infoFromContext(c *gin.Context) *dtmcli.TransInfo {
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user