github.com/m3db/m3@v1.5.1-0.20231129193456-75a402aa583b/src/query/remote/static_resolver.go (about)

     1  // Copyright (c) 2018 Uber Technologies, Inc.
     2  //
     3  // Permission is hereby granted, free of charge, to any person obtaining a copy
     4  // of this software and associated documentation files (the "Software"), to deal
     5  // in the Software without restriction, including without limitation the rights
     6  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     7  // copies of the Software, and to permit persons to whom the Software is
     8  // furnished to do so, subject to the following conditions:
     9  //
    10  // The above copyright notice and this permission notice shall be included in
    11  // all copies or substantial portions of the Software.
    12  //
    13  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    14  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    15  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    16  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    17  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    18  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    19  // THE SOFTWARE.
    20  
    21  package remote
    22  
    23  import (
    24  	"fmt"
    25  
    26  	"google.golang.org/grpc/resolver"
    27  )
    28  
    29  const (
    30  	_staticResolverSchema = "static"
    31  	// staticResolverURL is the same regardless of which endpoints are being dialed. The expectation
    32  	// is that callers use grpc.WithResolver on a per grpc.Dial basis in order to get correct routing.
    33  	_staticResolverURL = _staticResolverSchema + ":///"
    34  )
    35  
    36  // Assert we implement resolver.Builder
    37  var _ resolver.Builder = (*staticResolverBuilder)(nil)
    38  
    39  // staticResolverBuilder implements resolver.Builder.
    40  // It constructs a staticResolver, which:
    41  //  - Always routes to a static list of endpoints (never updates)
    42  //  - Performs round-robin load balancing between them.
    43  type staticResolverBuilder struct {
    44  	addresses []string
    45  }
    46  
    47  func newStaticResolverBuilder(addresses []string) *staticResolverBuilder {
    48  	return &staticResolverBuilder{addresses: addresses}
    49  }
    50  
    51  func (b *staticResolverBuilder) Build(
    52  	target resolver.Target,
    53  	cc resolver.ClientConn,
    54  	opts resolver.BuildOptions,
    55  ) (resolver.Resolver, error) {
    56  	addrs := make([]resolver.Address, 0, len(b.addresses))
    57  	for _, a := range b.addresses {
    58  		addrs = append(addrs, resolver.Address{Addr: a})
    59  	}
    60  	r := staticResolver{}
    61  
    62  	// N.B.: we are configuring the service config using as described in
    63  	// https://github.com/grpc/grpc/blob/master/doc/service_config.md.
    64  	// Technically speaking, this JSON is defined by the proto structure ServiceConfig in:
    65  	// https://github.com/grpc/grpc-proto/blob/master/grpc/service_config/service_config.proto
    66  	// However, the grpc-go package doesn't include an exposed, generated version of that protobuf type,
    67  	// despite the fact that it very clearly relies on a specific version of it (e.g. it would fail if
    68  	// we had a separate version of the .proto file).
    69  	// Therefore, follow the example of:
    70  	// https://github.com/grpc/grpc-go/blob/master/examples/features/load_balancing/client/main.go#L75-L75
    71  	// and use a static config JSON representation here.
    72  	const pfc = `{"loadBalancingConfig": [{"round_robin":{}}]}`
    73  	scpr := cc.ParseServiceConfig(pfc)
    74  	if scpr.Err != nil {
    75  		return nil, fmt.Errorf(
    76  			"failed to parse static service config for GRPC: %w. Config was: %q",
    77  			scpr.Err,
    78  			pfc,
    79  		)
    80  	}
    81  	if err := cc.UpdateState(resolver.State{
    82  		Addresses:     addrs,
    83  		ServiceConfig: scpr,
    84  	}); err != nil {
    85  		return nil, fmt.Errorf("failed to update connection state while building resolver: %w", err)
    86  	}
    87  	return r, nil
    88  }
    89  
    90  func (b *staticResolverBuilder) Scheme() string { return _staticResolverSchema }
    91  
    92  var _ resolver.Resolver = staticResolver{}
    93  
    94  // staticResolver implements resolver.Resolver
    95  type staticResolver struct{}
    96  
    97  func (r staticResolver) ResolveNow(resolver.ResolveNowOptions) {}
    98  
    99  func (r staticResolver) Close() {}