We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
当我使用以下代码进行tcc事务时,无法正常进行事务回滚处理
我将使用方式和发现的问题一起记录下,如我的使用存在问题欢迎指正
wfName := "wf_test" err := workflow.Register2(wfName, func(wf *workflow.Workflow, data []byte) ([]byte, error) { _, err := wf.NewBranch().OnCommit(func(bb *dtmcli.BranchBarrier) error { db, err := sql.Open("mysql", "dtm_wr:737ab8ef38666796@tcp(rw-18cc7d.mysql.qihudb.net:4362)/dtm") tx, err := db.Begin() err = bb.Call(tx, func(tx *sql.Tx) error { fmt.Println("COMMIT") return nil }) return err }).OnRollback(func(bb *dtmcli.BranchBarrier) error { db, err := sql.Open("mysql", "dtm_wr:737ab8ef38666796@tcp(rw-18cc7d.mysql.qihudb.net:4362)/dtm") tx, err := db.Begin() err = bb.Call(tx, func(tx *sql.Tx) error { fmt.Println("ROLLBACK") return nil }) return err }).Do(func(bb *dtmcli.BranchBarrier) ([]byte, error) { db, err := sql.Open("mysql", "dtm_wr:737ab8ef38666796@tcp(rw-18cc7d.mysql.qihudb.net:4362)/dtm") tx, err := db.Begin() err = bb.Call(tx, func(tx *sql.Tx) error { err = errors.New("test-err") return dtmcli.ErrFailure }) if err != nil { return nil, err } return []byte("123"), nil }) if err != nil { return nil, err } return []byte("123"), nil }) if err != nil { fmt.Println(err) }
在wf.Do方法中会调用 wf.recordedDo方法,在 wf.recordedDo中有以下逻辑
if !wf.Options.CompensateErrorBranch && sr.Status == dtmcli.StatusFailed { lastFailed := len(wf.failedOps) - 1 if lastFailed >= 0 && wf.failedOps[lastFailed].branchID == wf.currentBranch { wf.failedOps = wf.failedOps[:lastFailed] } }
此时会将注册时注入的failedOps丢弃,这里感觉逻辑是只取一个failedOps所以数组截取应为 wf.failedOps = wf.failedOps[lastFailed:]
同时在OnRollback时
dtmimp.PanicIf(wf.currentRollbackAdded, fmt.Errorf("one branch can only add one rollback callback"))
此代码已保证回滚方法的唯一
此外,在调用事务Execute2方法后调用defaultFac.execute 在此方法中调用 wf.process,在 wf.process调用handler进行Do方法,根据Do方法返回的错误在 wf.processPhase2方法中进行回滚
func (wf *Workflow) processPhase2(err error) error { ops := wf.succeededOps if err == nil { wf.currentOp = dtmimp.OpCommit } else { wf.currentOp = dtmimp.OpRollback ops = wf.failedOps } for i := len(ops) - 1; i >= 0; i-- { op := ops[i] err1 := wf.callPhase2(op.branchID, op.fn) if err1 != nil { return err1 } } return err }
此方法的传参err后续会直接透传返回,导致回滚后的事务也返回failure状态
若错误不为dtmcli.ErrFailure则会在回调前被拦截并返回,重试prepare
除此之外 在调用回滚方法时,如果使用子事务屏障
err = bb.Call(tx, func(tx *sql.Tx) error { fmt.Println("ROLLBACK") return nil })
在bb.Call方法中存在代码逻辑
if (bb.Op == dtmimp.OpCancel || bb.Op == dtmimp.OpCompensate || bb.Op == dtmimp.OpRollback) && originAffected > 0 || // null compensate currentAffected == 0 { // repeated request or dangled request return }
此时originAffected ==1 且 currentAffected ==1 但因为 bb.Op == dtmimp.OpRollback直接过滤rollback方法
The text was updated successfully, but these errors were encountered:
一般报bug的的标准流程是,复现问题的步骤,预期结果和当前的错误结果。 能否按照这种结构给出你说的这个无法回滚的问题呢?
Sorry, something went wrong.
No branches or pull requests
当我使用以下代码进行tcc事务时,无法正常进行事务回滚处理
我将使用方式和发现的问题一起记录下,如我的使用存在问题欢迎指正
在wf.Do方法中会调用 wf.recordedDo方法,在 wf.recordedDo中有以下逻辑
此时会将注册时注入的failedOps丢弃,这里感觉逻辑是只取一个failedOps所以数组截取应为
wf.failedOps = wf.failedOps[lastFailed:]
同时在OnRollback时
dtmimp.PanicIf(wf.currentRollbackAdded, fmt.Errorf("one branch can only add one rollback callback"))
此代码已保证回滚方法的唯一
此外,在调用事务Execute2方法后调用defaultFac.execute 在此方法中调用 wf.process,在 wf.process调用handler进行Do方法,根据Do方法返回的错误在 wf.processPhase2方法中进行回滚
此方法的传参err后续会直接透传返回,导致回滚后的事务也返回failure状态
若错误不为dtmcli.ErrFailure则会在回调前被拦截并返回,重试prepare
除此之外
在调用回滚方法时,如果使用子事务屏障
在bb.Call方法中存在代码逻辑
此时originAffected ==1 且 currentAffected ==1
但因为 bb.Op == dtmimp.OpRollback直接过滤rollback方法
The text was updated successfully, but these errors were encountered: