102 lines
2.8 KiB
Go
102 lines
2.8 KiB
Go
package dtmsvr
|
||
|
||
import (
|
||
"fmt"
|
||
"math"
|
||
"math/rand"
|
||
"strings"
|
||
"time"
|
||
|
||
"github.com/sirupsen/logrus"
|
||
"github.com/yedf/dtm/common"
|
||
)
|
||
|
||
func CronPreparedOnce(expire time.Duration) {
|
||
db := dbGet()
|
||
ss := []TransGlobal{}
|
||
db.Must().Model(&TransGlobal{}).Where("update_time < date_sub(now(), interval ? second)", int(expire/time.Second)).Where("status = ?", "prepared").Find(&ss)
|
||
writeTransLog("", "saga fetch prepared", fmt.Sprint(len(ss)), "", "")
|
||
if len(ss) == 0 {
|
||
return
|
||
}
|
||
for _, sm := range ss {
|
||
writeTransLog(sm.Gid, "saga touch prepared", "", "", "")
|
||
db.Must().Model(&sm).Update("id", sm.ID)
|
||
resp, err := common.RestyClient.R().SetQueryParam("gid", sm.Gid).Get(sm.QueryPrepared)
|
||
e2p(err)
|
||
body := resp.String()
|
||
if strings.Contains(body, "FAIL") {
|
||
preparedExpire := time.Now().Add(time.Duration(-config.PreparedExpire) * time.Second)
|
||
logrus.Printf("create time: %s prepared expire: %s ", sm.CreateTime.Local(), preparedExpire.Local())
|
||
status := common.If(sm.CreateTime.Before(preparedExpire), "canceled", "prepared").(string)
|
||
writeTransLog(sm.Gid, "saga canceled", status, "", "")
|
||
db.Must().Model(&sm).Where("status = ?", "prepared").Update("status", status)
|
||
} else if strings.Contains(body, "SUCCESS") {
|
||
sm.Status = "committed"
|
||
sm.SaveNew(db)
|
||
sm.Process(db)
|
||
}
|
||
}
|
||
}
|
||
|
||
func CronPrepared() {
|
||
for {
|
||
defer handlePanic()
|
||
CronTransOnce(time.Duration(config.JobCronInterval)*time.Second, "prepared")
|
||
sleepCronTime()
|
||
}
|
||
}
|
||
|
||
func CronTransOnce(expire time.Duration, status string) bool {
|
||
trans := lockOneTrans(expire, status)
|
||
if trans == nil {
|
||
return false
|
||
}
|
||
trans.touch(dbGet())
|
||
branches := []TransBranch{}
|
||
db := dbGet()
|
||
db.Must().Where("gid=?", trans.Gid).Order("id asc").Find(&branches)
|
||
trans.getProcessor().ProcessOnce(db, branches)
|
||
if TransProcessedTestChan != nil {
|
||
TransProcessedTestChan <- trans.Gid
|
||
}
|
||
return true
|
||
}
|
||
|
||
func CronCommitted() {
|
||
for {
|
||
defer handlePanic()
|
||
processed := CronTransOnce(time.Duration(config.JobCronInterval)*time.Second, "commitetd")
|
||
if !processed {
|
||
sleepCronTime()
|
||
}
|
||
}
|
||
}
|
||
|
||
func lockOneTrans(expire time.Duration, status string) *TransGlobal {
|
||
trans := TransGlobal{}
|
||
owner := common.GenGid()
|
||
db := dbGet()
|
||
dbr := db.Must().Model(&trans).
|
||
Where("update_time < date_sub(now(), interval ? second) and status=?", int(expire/time.Second), status).
|
||
Limit(1).Update("owner", owner)
|
||
if dbr.RowsAffected == 0 {
|
||
return nil
|
||
}
|
||
dbr = db.Must().Where("owner=?", owner).Find(&trans)
|
||
return &trans
|
||
}
|
||
|
||
func handlePanic() {
|
||
if err := recover(); err != nil {
|
||
logrus.Printf("----panic %s handlered", err.(error).Error())
|
||
time.Sleep(3 * time.Second) // 出错后睡眠3s,避免无限循环
|
||
}
|
||
}
|
||
|
||
func sleepCronTime() {
|
||
delta := math.Min(3, float64(config.JobCronInterval))
|
||
interval := time.Duration(rand.Float64() * delta * float64(time.Second))
|
||
time.Sleep(interval)
|
||
}
|