serviceconfig.go 6.4 KB

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