dubbo.apache.org/dubbo-go/v3@v3.1.1/filter/adaptivesvc/filter.go (about) 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 18 // Package adaptivesvc providers AdaptiveService filter. 19 package adaptivesvc 20 21 import ( 22 "context" 23 "fmt" 24 "strings" 25 "sync" 26 ) 27 28 import ( 29 "github.com/dubbogo/gost/log/logger" 30 31 "github.com/pkg/errors" 32 ) 33 34 import ( 35 "dubbo.apache.org/dubbo-go/v3/common/constant" 36 "dubbo.apache.org/dubbo-go/v3/common/extension" 37 "dubbo.apache.org/dubbo-go/v3/filter" 38 "dubbo.apache.org/dubbo-go/v3/filter/adaptivesvc/limiter" 39 "dubbo.apache.org/dubbo-go/v3/protocol" 40 ) 41 42 var ( 43 adaptiveServiceProviderFilterOnce sync.Once 44 instance filter.Filter 45 46 ErrAdaptiveSvcInterrupted = fmt.Errorf("adaptive service interrupted") 47 ErrUpdaterNotFound = fmt.Errorf("updater not found") 48 ErrUnexpectedUpdaterType = fmt.Errorf("unexpected updater type") 49 ) 50 51 func init() { 52 extension.SetFilter(constant.AdaptiveServiceProviderFilterKey, newAdaptiveServiceProviderFilter) 53 } 54 55 // adaptiveServiceProviderFilter is for adaptive service on the provider side. 56 type adaptiveServiceProviderFilter struct{} 57 58 func newAdaptiveServiceProviderFilter() filter.Filter { 59 if instance == nil { 60 adaptiveServiceProviderFilterOnce.Do(func() { 61 instance = &adaptiveServiceProviderFilter{} 62 }) 63 } 64 return instance 65 } 66 67 func (f *adaptiveServiceProviderFilter) Invoke(ctx context.Context, invoker protocol.Invoker, 68 invocation protocol.Invocation) protocol.Result { 69 if invocation.GetAttachmentWithDefaultValue(constant.AdaptiveServiceEnabledKey, "") != 70 constant.AdaptiveServiceIsEnabled { 71 // the adaptive service is enabled on the invocation 72 return invoker.Invoke(ctx, invocation) 73 } 74 75 l, err := limiterMapperSingleton.getMethodLimiter(invoker.GetURL(), invocation.MethodName()) 76 if err != nil { 77 if errors.Is(err, ErrLimiterNotFoundOnMapper) { 78 // limiter is not found on the mapper, just create 79 // a new limiter 80 if l, err = limiterMapperSingleton.newAndSetMethodLimiter(invoker.GetURL(), 81 invocation.MethodName(), limiter.HillClimbingLimiter); err != nil { 82 return &protocol.RPCResult{Err: wrapErrAdaptiveSvcInterrupted(err)} 83 } 84 } else { 85 // unexpected errors 86 return &protocol.RPCResult{Err: wrapErrAdaptiveSvcInterrupted(err)} 87 } 88 } 89 90 updater, err := l.Acquire() 91 if err != nil { 92 return &protocol.RPCResult{Err: wrapErrAdaptiveSvcInterrupted(err)} 93 } 94 95 invocation.SetAttribute(constant.AdaptiveServiceUpdaterKey, updater) 96 return invoker.Invoke(ctx, invocation) 97 } 98 99 func (f *adaptiveServiceProviderFilter) OnResponse(_ context.Context, result protocol.Result, invoker protocol.Invoker, 100 invocation protocol.Invocation) protocol.Result { 101 var asEnabled string 102 asEnabledIface := result.Attachment(constant.AdaptiveServiceEnabledKey, nil) 103 if asEnabledIface != nil { 104 if str, strOK := asEnabledIface.(string); strOK { 105 asEnabled = str 106 } else if strArr, strArrOK := asEnabledIface.([]string); strArrOK && len(strArr) > 0 { 107 asEnabled = strArr[0] 108 } 109 } 110 if asEnabled != constant.AdaptiveServiceIsEnabled { 111 // the adaptive service is enabled on the invocation 112 return result 113 } 114 115 if isErrAdaptiveSvcInterrupted(result.Error()) { 116 // If the Invoke method of the adaptiveServiceProviderFilter returns an error, 117 // the OnResponse of the adaptiveServiceProviderFilter should not be performed. 118 return result 119 } 120 121 // get updater from the attributes 122 updaterIface, _ := invocation.GetAttribute(constant.AdaptiveServiceUpdaterKey) 123 if updaterIface == nil { 124 logger.Errorf("[adasvc filter] The updater is not found on the attributes: %#v", 125 invocation.Attributes()) 126 return &protocol.RPCResult{Err: ErrUpdaterNotFound} 127 } 128 updater, ok := updaterIface.(limiter.Updater) 129 if !ok { 130 logger.Errorf("[adasvc filter] The type of the updater is not unexpected, we got %#v", updaterIface) 131 return &protocol.RPCResult{Err: ErrUnexpectedUpdaterType} 132 } 133 134 err := updater.DoUpdate() 135 if err != nil { 136 logger.Errorf("[adasvc filter] The DoUpdate method was failed, err: %s.", err) 137 return &protocol.RPCResult{Err: err} 138 } 139 140 // get limiter for the mapper 141 l, err := limiterMapperSingleton.getMethodLimiter(invoker.GetURL(), invocation.MethodName()) 142 if err != nil { 143 logger.Errorf("[adasvc filter] The method limiter for \"%s\" is not found.", invocation.MethodName()) 144 return &protocol.RPCResult{Err: err} 145 } 146 147 // set attachments to inform consumer of provider status 148 result.AddAttachment(constant.AdaptiveServiceRemainingKey, fmt.Sprintf("%d", l.Remaining())) 149 result.AddAttachment(constant.AdaptiveServiceInflightKey, fmt.Sprintf("%d", l.Inflight())) 150 logger.Debugf("[adasvc filter] The attachments are set, %s: %d, %s: %d.", 151 constant.AdaptiveServiceRemainingKey, l.Remaining(), 152 constant.AdaptiveServiceInflightKey, l.Inflight()) 153 154 return result 155 } 156 157 func wrapErrAdaptiveSvcInterrupted(customizedErr interface{}) error { 158 return fmt.Errorf("%w: %v", ErrAdaptiveSvcInterrupted, customizedErr) 159 } 160 161 func isErrAdaptiveSvcInterrupted(err error) bool { 162 if err == nil { 163 return false 164 } 165 return strings.HasPrefix(err.Error(), ErrAdaptiveSvcInterrupted.Error()) 166 }