dubbo.apache.org/dubbo-go/v3@v3.1.1/xds/utils/serviceconfig/serviceconfig.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 /* 19 * 20 * Copyright 2021 gRPC authors. 21 * 22 */ 23 24 // Package serviceconfig contains utility functions to parse service config. 25 package serviceconfig 26 27 import ( 28 "encoding/json" 29 "fmt" 30 "time" 31 ) 32 33 import ( 34 "github.com/dubbogo/gost/log/logger" 35 36 "google.golang.org/grpc/balancer" 37 38 "google.golang.org/grpc/codes" 39 40 externalserviceconfig "google.golang.org/grpc/serviceconfig" 41 ) 42 43 // BalancerConfig wraps the name and config associated with one load balancing 44 // policy. It corresponds to a single entry of the loadBalancingConfig field 45 // from ServiceConfig. 46 // 47 // It implements the json.Unmarshaler interface. 48 // 49 // https://github.com/grpc/grpc-proto/blob/54713b1e8bc6ed2d4f25fb4dff527842150b91b2/grpc/service_config/service_config.proto#L247 50 type BalancerConfig struct { 51 Name string 52 Config externalserviceconfig.LoadBalancingConfig 53 } 54 55 type intermediateBalancerConfig []map[string]json.RawMessage 56 57 // MarshalJSON implements the json.Marshaler interface. 58 // 59 // It marshals the balancer and config into a length-1 slice 60 // ([]map[string]config). 61 func (bc *BalancerConfig) MarshalJSON() ([]byte, error) { 62 if bc.Config == nil { 63 // If config is nil, return empty config `{}`. 64 return []byte(fmt.Sprintf(`[{%q: %v}]`, bc.Name, "{}")), nil 65 } 66 c, err := json.Marshal(bc.Config) 67 if err != nil { 68 return nil, err 69 } 70 return []byte(fmt.Sprintf(`[{%q: %s}]`, bc.Name, c)), nil 71 } 72 73 // UnmarshalJSON implements the json.Unmarshaler interface. 74 // 75 // ServiceConfig contains a list of loadBalancingConfigs, each with a name and 76 // config. This method iterates through that list in order, and stops at the 77 // first policy that is supported. 78 // - If the config for the first supported policy is invalid, the whole service 79 // config is invalid. 80 // - If the list doesn't contain any supported policy, the whole service config 81 // is invalid. 82 func (bc *BalancerConfig) UnmarshalJSON(b []byte) error { 83 var ir intermediateBalancerConfig 84 err := json.Unmarshal(b, &ir) 85 if err != nil { 86 return err 87 } 88 89 var names []string 90 for i, lbcfg := range ir { 91 if len(lbcfg) != 1 { 92 return fmt.Errorf("invalid loadBalancingConfig: entry %v does not contain exactly 1 policy/config pair: %q", i, lbcfg) 93 } 94 95 var ( 96 name string 97 jsonCfg json.RawMessage 98 ) 99 // Get the key:value pair from the map. We have already made sure that 100 // the map contains a single entry. 101 for name, jsonCfg = range lbcfg { 102 } 103 104 names = append(names, name) 105 builder := balancer.Get(name) 106 if builder == nil { 107 // If the balancer is not registered, move on to the next config. 108 // This is not an error. 109 continue 110 } 111 bc.Name = name 112 113 parser, ok := builder.(balancer.ConfigParser) 114 if !ok { 115 if string(jsonCfg) != "{}" { 116 logger.Warnf("non-empty balancer configuration %q, but balancer does not implement ParseConfig", string(jsonCfg)) 117 } 118 // Stop at this, though the builder doesn't support parsing config. 119 return nil 120 } 121 122 cfg, err := parser.ParseConfig(jsonCfg) 123 if err != nil { 124 return fmt.Errorf("error parsing loadBalancingConfig for policy %q: %v", name, err) 125 } 126 bc.Config = cfg 127 return nil 128 } 129 // This is reached when the for loop iterates over all entries, but didn't 130 // return. This means we had a loadBalancingConfig slice but did not 131 // encounter a registered policy. The config is considered invalid in this 132 // case. 133 return fmt.Errorf("invalid loadBalancingConfig: no supported policies found in %v", names) 134 } 135 136 // MethodConfig defines the configuration recommended by the service providers for a 137 // particular method. 138 type MethodConfig struct { 139 // WaitForReady indicates whether RPCs sent to this method should wait until 140 // the connection is ready by default (!failfast). The value specified via the 141 // gRPC client API will override the value set here. 142 WaitForReady *bool 143 // Timeout is the default timeout for RPCs sent to this method. The actual 144 // deadline used will be the minimum of the value specified here and the value 145 // set by the application via the gRPC client API. If either one is not set, 146 // then the other will be used. If neither is set, then the RPC has no deadline. 147 Timeout *time.Duration 148 // MaxReqSize is the maximum allowed payload size for an individual request in a 149 // stream (client->server) in bytes. The size which is measured is the serialized 150 // payload after per-message compression (but before stream compression) in bytes. 151 // The actual value used is the minimum of the value specified here and the value set 152 // by the application via the gRPC client API. If either one is not set, then the other 153 // will be used. If neither is set, then the built-in default is used. 154 MaxReqSize *int 155 // MaxRespSize is the maximum allowed payload size for an individual response in a 156 // stream (server->client) in bytes. 157 MaxRespSize *int 158 // RetryPolicy configures retry options for the method. 159 RetryPolicy *RetryPolicy 160 } 161 162 // RetryPolicy defines the go-native version of the retry policy defined by the 163 // service config here: 164 // https://github.com/grpc/proposal/blob/master/A6-client-retries.md#integration-with-service-config 165 type RetryPolicy struct { 166 // MaxAttempts is the maximum number of attempts, including the original RPC. 167 // 168 // This field is required and must be two or greater. 169 MaxAttempts int 170 171 // Exponential backoff parameters. The initial retry attempt will occur at 172 // random(0, initialBackoff). In general, the nth attempt will occur at 173 // random(0, 174 // min(initialBackoff*backoffMultiplier**(n-1), maxBackoff)). 175 // 176 // These fields are required and must be greater than zero. 177 InitialBackoff time.Duration 178 MaxBackoff time.Duration 179 BackoffMultiplier float64 180 181 // The set of status codes which may be retried. 182 // 183 // Status codes are specified as strings, e.g., "UNAVAILABLE". 184 // 185 // This field is required and must be non-empty. 186 // Note: a set is used to store this for easy lookup. 187 RetryableStatusCodes map[codes.Code]bool 188 }