gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

serviceconfig.go (6508B)


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