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.

func_invoker.go 6.7 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225
  1. /*
  2. * Licensed to the Apache Software Foundation (ASF) under one or more
  3. * contributor license agreements. See the NOTICE file distributed with
  4. * this work for additional information regarding copyright ownership.
  5. * The ASF licenses this file to You under the Apache License, Version 2.0
  6. * (the "License"); you may not use this file except in compliance with
  7. * the License. You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. package invoker
  18. import (
  19. "context"
  20. "errors"
  21. "fmt"
  22. "reflect"
  23. "strings"
  24. "sync"
  25. "time"
  26. "github.com/seata/seata-go/pkg/saga/statemachine/statelang/state"
  27. "github.com/seata/seata-go/pkg/util/log"
  28. )
  29. type FuncInvoker struct {
  30. ServicesMapLock sync.Mutex
  31. servicesMap map[string]FuncService
  32. }
  33. func NewFuncInvoker() *FuncInvoker {
  34. return &FuncInvoker{
  35. servicesMap: make(map[string]FuncService),
  36. }
  37. }
  38. func (f *FuncInvoker) RegisterService(serviceName string, service FuncService) {
  39. f.ServicesMapLock.Lock()
  40. defer f.ServicesMapLock.Unlock()
  41. f.servicesMap[serviceName] = service
  42. }
  43. func (f *FuncInvoker) GetService(serviceName string) FuncService {
  44. f.ServicesMapLock.Lock()
  45. defer f.ServicesMapLock.Unlock()
  46. return f.servicesMap[serviceName]
  47. }
  48. func (f *FuncInvoker) Invoke(ctx context.Context, input []any, service state.ServiceTaskState) (output []reflect.Value, err error) {
  49. serviceTaskStateImpl := service.(*state.ServiceTaskStateImpl)
  50. FuncService := f.GetService(serviceTaskStateImpl.ServiceName())
  51. if FuncService == nil {
  52. return nil, errors.New("no func service " + serviceTaskStateImpl.ServiceName() + " for service task state")
  53. }
  54. if serviceTaskStateImpl.IsAsync() {
  55. go func() {
  56. _, err := FuncService.CallMethod(serviceTaskStateImpl, input)
  57. if err != nil {
  58. log.Errorf("invoke Service[%s].%s failed, err is %s", serviceTaskStateImpl.ServiceName(), serviceTaskStateImpl.ServiceMethod(), err.Error())
  59. }
  60. }()
  61. return nil, nil
  62. }
  63. return FuncService.CallMethod(serviceTaskStateImpl, input)
  64. }
  65. func (f *FuncInvoker) Close(ctx context.Context) error {
  66. return nil
  67. }
  68. type FuncService interface {
  69. CallMethod(ServiceTaskStateImpl *state.ServiceTaskStateImpl, input []any) ([]reflect.Value, error)
  70. }
  71. type FuncServiceImpl struct {
  72. serviceName string
  73. methodLock sync.Mutex
  74. method any
  75. }
  76. func NewFuncService(serviceName string, method any) *FuncServiceImpl {
  77. return &FuncServiceImpl{
  78. serviceName: serviceName,
  79. method: method,
  80. }
  81. }
  82. func (f *FuncServiceImpl) getMethod(serviceTaskStateImpl *state.ServiceTaskStateImpl) (*reflect.Value, error) {
  83. method := serviceTaskStateImpl.Method()
  84. if method == nil {
  85. return f.initMethod(serviceTaskStateImpl)
  86. }
  87. return method, nil
  88. }
  89. func (f *FuncServiceImpl) prepareArguments(input []any) []reflect.Value {
  90. args := make([]reflect.Value, len(input))
  91. for i, arg := range input {
  92. args[i] = reflect.ValueOf(arg)
  93. }
  94. return args
  95. }
  96. func (f *FuncServiceImpl) CallMethod(serviceTaskStateImpl *state.ServiceTaskStateImpl, input []any) ([]reflect.Value, error) {
  97. method, err := f.getMethod(serviceTaskStateImpl)
  98. if err != nil {
  99. return nil, err
  100. }
  101. args := f.prepareArguments(input)
  102. retryCountMap := make(map[state.Retry]int)
  103. for {
  104. res, err, shouldRetry := f.invokeMethod(method, args, serviceTaskStateImpl, retryCountMap)
  105. if !shouldRetry {
  106. if err != nil {
  107. return nil, errors.New("invoke service[" + serviceTaskStateImpl.ServiceName() + "]." + serviceTaskStateImpl.ServiceMethod() + " failed, err is " + err.Error())
  108. }
  109. return res, nil
  110. }
  111. }
  112. }
  113. func (f *FuncServiceImpl) initMethod(serviceTaskStateImpl *state.ServiceTaskStateImpl) (*reflect.Value, error) {
  114. methodName := serviceTaskStateImpl.ServiceMethod()
  115. f.methodLock.Lock()
  116. defer f.methodLock.Unlock()
  117. methodValue := reflect.ValueOf(f.method)
  118. if methodValue.IsZero() {
  119. return nil, errors.New("invalid method when func call, serviceName: " + f.serviceName)
  120. }
  121. if methodValue.Kind() == reflect.Func {
  122. serviceTaskStateImpl.SetMethod(&methodValue)
  123. return &methodValue, nil
  124. }
  125. method := methodValue.MethodByName(methodName)
  126. if method.IsZero() {
  127. return nil, errors.New("invalid method name when func call, serviceName: " + f.serviceName + ", methodName: " + methodName)
  128. }
  129. serviceTaskStateImpl.SetMethod(&method)
  130. return &method, nil
  131. }
  132. func (f *FuncServiceImpl) invokeMethod(method *reflect.Value, args []reflect.Value, serviceTaskStateImpl *state.ServiceTaskStateImpl, retryCountMap map[state.Retry]int) ([]reflect.Value, error, bool) {
  133. var res []reflect.Value
  134. var resErr error
  135. var shouldRetry bool
  136. defer func() {
  137. if r := recover(); r != nil {
  138. errStr := fmt.Sprintf("%v", r)
  139. retry := f.matchRetry(serviceTaskStateImpl, errStr)
  140. resErr = errors.New(errStr)
  141. if retry != nil {
  142. shouldRetry = f.needRetry(serviceTaskStateImpl, retryCountMap, retry, resErr)
  143. }
  144. }
  145. }()
  146. outs := method.Call(args)
  147. if err, ok := outs[len(outs)-1].Interface().(error); ok {
  148. resErr = err
  149. errStr := err.Error()
  150. retry := f.matchRetry(serviceTaskStateImpl, errStr)
  151. if retry != nil {
  152. shouldRetry = f.needRetry(serviceTaskStateImpl, retryCountMap, retry, resErr)
  153. }
  154. return nil, resErr, shouldRetry
  155. }
  156. res = outs
  157. return res, nil, false
  158. }
  159. func (f *FuncServiceImpl) matchRetry(impl *state.ServiceTaskStateImpl, str string) state.Retry {
  160. if impl.Retry() != nil {
  161. for _, retry := range impl.Retry() {
  162. if retry.Exceptions() != nil {
  163. for _, exception := range retry.Exceptions() {
  164. if strings.Contains(str, exception) {
  165. return retry
  166. }
  167. }
  168. }
  169. }
  170. }
  171. return nil
  172. }
  173. func (f *FuncServiceImpl) needRetry(impl *state.ServiceTaskStateImpl, countMap map[state.Retry]int, retry state.Retry, err error) bool {
  174. attempt, exist := countMap[retry]
  175. if !exist {
  176. countMap[retry] = 0
  177. }
  178. if attempt >= retry.MaxAttempt() {
  179. return false
  180. }
  181. interval := retry.IntervalSecond()
  182. backoffRate := retry.BackoffRate()
  183. curInterval := int64(interval * 1000)
  184. if attempt != 0 {
  185. curInterval = int64(interval * backoffRate * float64(attempt) * 1000)
  186. }
  187. log.Warnf("invoke service[%s.%s] failed, will retry after %s millis, current retry count: %s, current err: %s",
  188. impl.ServiceName(), impl.ServiceMethod(), curInterval, attempt, err)
  189. time.Sleep(time.Duration(curInterval) * time.Millisecond)
  190. countMap[retry] = attempt + 1
  191. return true
  192. }