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  }