You can not select more than 25 topics Topics must start with a chinese character,a letter or number, can include dashes ('-') and can be up to 35 characters long.

tcc_resource_manager.go 7.5 kB

5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
4 years ago
5 years ago
5 years ago
5 years ago
5 years ago
4 years ago
5 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. package tcc
  2. import (
  3. "encoding/json"
  4. "fmt"
  5. "strconv"
  6. )
  7. import (
  8. "github.com/pkg/errors"
  9. )
  10. import (
  11. "github.com/transaction-wg/seata-golang/pkg/base/meta"
  12. "github.com/transaction-wg/seata-golang/pkg/base/protocal"
  13. "github.com/transaction-wg/seata-golang/pkg/client/context"
  14. "github.com/transaction-wg/seata-golang/pkg/client/proxy"
  15. "github.com/transaction-wg/seata-golang/pkg/client/rm"
  16. "github.com/transaction-wg/seata-golang/pkg/client/rpc_client"
  17. "github.com/transaction-wg/seata-golang/pkg/util/log"
  18. )
  19. var (
  20. TCC_ACTION_CONTEXT = "actionContext"
  21. )
  22. var tccResourceManager TCCResourceManager
  23. func InitTCCResourceManager() {
  24. tccResourceManager = TCCResourceManager{
  25. AbstractResourceManager: rm.NewAbstractResourceManager(rpc_client.GetRpcRemoteClient()),
  26. }
  27. go tccResourceManager.handleBranchCommit()
  28. go tccResourceManager.handleBranchRollback()
  29. }
  30. type TCCResourceManager struct {
  31. rm.AbstractResourceManager
  32. }
  33. func (resourceManager TCCResourceManager) BranchCommit(branchType meta.BranchType, xid string, branchID int64,
  34. resourceID string, applicationData []byte) (meta.BranchStatus, error) {
  35. resource := resourceManager.ResourceCache[resourceID]
  36. if resource == nil {
  37. log.Errorf("TCC resource is not exist, resourceID: %s", resourceID)
  38. return 0, errors.Errorf("TCC resource is not exist, resourceID: %s", resourceID)
  39. }
  40. tccResource := resource.(*TCCResource)
  41. if tccResource.CommitMethod == nil {
  42. log.Errorf("TCC resource is not available, resourceID: %s", resourceID)
  43. return 0, errors.Errorf("TCC resource is not available, resourceID: %s", resourceID)
  44. }
  45. result := false
  46. businessActionContext := getBusinessActionContext(xid, branchID, resourceID, applicationData)
  47. args := make([]interface{}, 0)
  48. args = append(args, businessActionContext)
  49. returnValues := proxy.Invoke(tccResource.CommitMethod, nil, args)
  50. if returnValues != nil {
  51. log.Infof("TCC resource commit result : %v, XID: %s, BranchID: %d, ResourceID: %s", returnValues[0].Interface(), xid, branchID, resourceID)
  52. result = returnValues[0].Interface().(bool)
  53. }
  54. if result {
  55. return meta.BranchStatusPhaseTwoCommitted, nil
  56. } else {
  57. return meta.BranchStatusPhaseTwoCommitFailedRetryable, nil
  58. }
  59. }
  60. func (resourceManager TCCResourceManager) BranchRollback(branchType meta.BranchType, xid string, branchID int64,
  61. resourceID string, applicationData []byte) (meta.BranchStatus, error) {
  62. resource := resourceManager.ResourceCache[resourceID]
  63. if resource == nil {
  64. log.Errorf("TCC resource does not exist, resourceID: %s", resourceID)
  65. return 0, errors.Errorf("TCC resource does not exist, resourceID: %s", resourceID)
  66. }
  67. tccResource := resource.(*TCCResource)
  68. if tccResource.RollbackMethod == nil {
  69. log.Errorf("TCC resource does not available, resourceID: %s", resourceID)
  70. return 0, errors.Errorf("TCC resource does not available, resourceID: %s", resourceID)
  71. }
  72. result := false
  73. businessActionContext := getBusinessActionContext(xid, branchID, resourceID, applicationData)
  74. args := make([]interface{}, 0)
  75. args = append(args, businessActionContext)
  76. returnValues := proxy.Invoke(tccResource.RollbackMethod, nil, args)
  77. if returnValues != nil {
  78. log.Infof("TCC resource rollback result : %v, XID: %s, BranchID: %d, ResourceID: %s", returnValues[0].Interface(), xid, branchID, resourceID)
  79. result = returnValues[0].Interface().(bool)
  80. }
  81. if result {
  82. return meta.BranchStatusPhaseTwoRolledBack, nil
  83. } else {
  84. return meta.BranchStatusPhaseTwoRollbackFailedRetryable, nil
  85. }
  86. }
  87. func (resourceManager TCCResourceManager) GetBranchType() meta.BranchType {
  88. return meta.BranchTypeTCC
  89. }
  90. func getBusinessActionContext(xid string, branchID int64, resourceID string, applicationData []byte) *context.BusinessActionContext {
  91. var (
  92. tccContext = make(map[string]interface{})
  93. actionContextMap = make(map[string]interface{})
  94. )
  95. if len(applicationData) > 0 {
  96. err := json.Unmarshal(applicationData, &tccContext)
  97. if err != nil {
  98. log.Errorf("getBusinessActionContext, unmarshal applicationData err=%v", err)
  99. }
  100. }
  101. acMap := tccContext[TCC_ACTION_CONTEXT]
  102. if acMap != nil {
  103. actionContextMap = acMap.(map[string]interface{})
  104. }
  105. businessActionContext := &context.BusinessActionContext{
  106. XID: xid,
  107. BranchID: strconv.FormatInt(branchID, 10),
  108. ActionName: resourceID,
  109. ActionContext: actionContextMap,
  110. }
  111. return businessActionContext
  112. }
  113. func (resourceManager TCCResourceManager) handleBranchCommit() {
  114. for {
  115. rpcRMMessage := <-resourceManager.RpcClient.BranchCommitRequestChannel
  116. rpcMessage := rpcRMMessage.RpcMessage
  117. serviceAddress := rpcRMMessage.ServerAddress
  118. req := rpcMessage.Body.(protocal.BranchCommitRequest)
  119. resp := resourceManager.doBranchCommit(req)
  120. resourceManager.RpcClient.SendResponse(rpcMessage, serviceAddress, resp)
  121. }
  122. }
  123. func (resourceManager TCCResourceManager) handleBranchRollback() {
  124. for {
  125. rpcRMMessage := <-resourceManager.RpcClient.BranchRollbackRequestChannel
  126. rpcMessage := rpcRMMessage.RpcMessage
  127. serviceAddress := rpcRMMessage.ServerAddress
  128. req := rpcMessage.Body.(protocal.BranchRollbackRequest)
  129. resp := resourceManager.doBranchRollback(req)
  130. resourceManager.RpcClient.SendResponse(rpcMessage, serviceAddress, resp)
  131. }
  132. }
  133. func (resourceManager TCCResourceManager) doBranchCommit(request protocal.BranchCommitRequest) protocal.BranchCommitResponse {
  134. var resp = protocal.BranchCommitResponse{}
  135. log.Infof("Branch committing, XID: %s, BranchID: %d, ResourceID: %s, ApplicationData: %s", request.XID, request.BranchID, request.ResourceID, request.ApplicationData)
  136. status, err := resourceManager.BranchCommit(request.BranchType, request.XID, request.BranchID, request.ResourceID, request.ApplicationData)
  137. if err != nil {
  138. resp.ResultCode = protocal.ResultCodeFailed
  139. var trxException *meta.TransactionException
  140. if errors.As(err, &trxException) {
  141. resp.TransactionExceptionCode = trxException.Code
  142. resp.Msg = fmt.Sprintf("TransactionException[%s]", err.Error())
  143. log.Errorf("Catch TransactionException while do RPC, request: %v", request)
  144. return resp
  145. }
  146. resp.Msg = fmt.Sprintf("RuntimeException[%s]", err.Error())
  147. log.Errorf("Catch RuntimeException while do RPC, request: %v", request)
  148. return resp
  149. }
  150. resp.XID = request.XID
  151. resp.BranchID = request.BranchID
  152. resp.BranchStatus = status
  153. resp.ResultCode = protocal.ResultCodeSuccess
  154. return resp
  155. }
  156. func (resourceManager TCCResourceManager) doBranchRollback(request protocal.BranchRollbackRequest) protocal.BranchRollbackResponse {
  157. var resp = protocal.BranchRollbackResponse{}
  158. log.Infof("Branch rolling back: XID: %s, BranchID: %d, ResourceID: %s, ApplicationData: %s", request.XID, request.BranchID, request.ResourceID, request.ApplicationData)
  159. status, err := resourceManager.BranchRollback(request.BranchType, request.XID, request.BranchID, request.ResourceID, request.ApplicationData)
  160. if err != nil {
  161. resp.ResultCode = protocal.ResultCodeFailed
  162. var trxException *meta.TransactionException
  163. if errors.As(err, &trxException) {
  164. resp.TransactionExceptionCode = trxException.Code
  165. resp.Msg = fmt.Sprintf("TransactionException[%s]", err.Error())
  166. log.Errorf("Catch TransactionException while do RPC, request: %v", request)
  167. return resp
  168. }
  169. resp.Msg = fmt.Sprintf("RuntimeException[%s]", err.Error())
  170. log.Errorf("Catch RuntimeException while do RPC, request: %v", request)
  171. return resp
  172. }
  173. resp.XID = request.XID
  174. resp.BranchID = request.BranchID
  175. resp.BranchStatus = status
  176. resp.ResultCode = protocal.ResultCodeSuccess
  177. return resp
  178. }