github.com/milvus-io/milvus-sdk-go/v2@v2.4.1/client/config.go (about)

     1  package client
     2  
     3  import (
     4  	"context"
     5  	"crypto/tls"
     6  	"fmt"
     7  	"math"
     8  	"net/url"
     9  	"regexp"
    10  	"strings"
    11  	"time"
    12  
    13  	"github.com/cockroachdb/errors"
    14  	grpc_retry "github.com/grpc-ecosystem/go-grpc-middleware/retry"
    15  	"google.golang.org/grpc"
    16  	"google.golang.org/grpc/backoff"
    17  	"google.golang.org/grpc/codes"
    18  	"google.golang.org/grpc/credentials"
    19  	"google.golang.org/grpc/credentials/insecure"
    20  	"google.golang.org/grpc/keepalive"
    21  )
    22  
    23  const (
    24  	disableDatabase uint64 = 1 << iota
    25  	disableJSON
    26  	disableDynamicSchema
    27  	disableParitionKey
    28  )
    29  
    30  var regexValidScheme = regexp.MustCompile(`^https?:\/\/`)
    31  
    32  // DefaultGrpcOpts is GRPC options for milvus client.
    33  var DefaultGrpcOpts = []grpc.DialOption{
    34  	grpc.WithBlock(),
    35  	grpc.WithKeepaliveParams(keepalive.ClientParameters{
    36  		Time:                5 * time.Second,
    37  		Timeout:             10 * time.Second,
    38  		PermitWithoutStream: true,
    39  	}),
    40  	grpc.WithConnectParams(grpc.ConnectParams{
    41  		Backoff: backoff.Config{
    42  			BaseDelay:  100 * time.Millisecond,
    43  			Multiplier: 1.6,
    44  			Jitter:     0.2,
    45  			MaxDelay:   3 * time.Second,
    46  		},
    47  		MinConnectTimeout: 3 * time.Second,
    48  	}),
    49  }
    50  
    51  // Config for milvus client.
    52  type Config struct {
    53  	Address       string // Remote address, "localhost:19530".
    54  	Username      string // Username for auth.
    55  	Password      string // Password for auth.
    56  	DBName        string // DBName for this client.
    57  	Identifier    string // Identifier for this connection
    58  	EnableTLSAuth bool   // Enable TLS Auth for transport security.
    59  	APIKey        string // API key
    60  	ServerVersion string // ServerVersion
    61  
    62  	DialOptions []grpc.DialOption // Dial options for GRPC.
    63  
    64  	parsedAddress *url.URL
    65  
    66  	RetryRateLimit *RetryRateLimitOption // option for retry on rate limit inteceptor
    67  
    68  	DisableConn bool
    69  
    70  	flags uint64 // internal flags
    71  }
    72  
    73  type RetryRateLimitOption struct {
    74  	MaxRetry   uint
    75  	MaxBackoff time.Duration
    76  }
    77  
    78  // Copy a new config, dialOption may shared with old config.
    79  func (c *Config) Copy() Config {
    80  	newConfig := Config{
    81  		Address:       c.Address,
    82  		Username:      c.Username,
    83  		Password:      c.Password,
    84  		DBName:        c.DBName,
    85  		EnableTLSAuth: c.EnableTLSAuth,
    86  	}
    87  	newConfig.DialOptions = make([]grpc.DialOption, 0, len(c.DialOptions))
    88  	newConfig.DialOptions = append(newConfig.DialOptions, c.DialOptions...)
    89  	return newConfig
    90  }
    91  
    92  func (c *Config) parse() error {
    93  	// Prepend default fake tcp:// scheme for remote address.
    94  	address := c.Address
    95  	if !regexValidScheme.MatchString(address) {
    96  		address = fmt.Sprintf("tcp://%s", address)
    97  	}
    98  
    99  	remoteURL, err := url.Parse(address)
   100  	if err != nil {
   101  		return errors.Wrap(err, "milvus address parse fail")
   102  	}
   103  	// Remote Host should never be empty.
   104  	if remoteURL.Host == "" {
   105  		return errors.New("empty remote host of milvus address")
   106  	}
   107  	// Use DBName in remote url path.
   108  	if c.DBName == "" {
   109  		c.DBName = strings.TrimLeft(remoteURL.Path, "/")
   110  	}
   111  	// Always enable tls auth for https remote url.
   112  	if remoteURL.Scheme == "https" {
   113  		c.EnableTLSAuth = true
   114  	}
   115  	if remoteURL.Port() == "" && c.EnableTLSAuth {
   116  		remoteURL.Host += ":443"
   117  	}
   118  	c.parsedAddress = remoteURL
   119  	return nil
   120  }
   121  
   122  // Get parsed remote milvus address, should be called after parse was called.
   123  func (c *Config) getParsedAddress() string {
   124  	return c.parsedAddress.Host
   125  }
   126  
   127  // useDatabase change the inner db name.
   128  func (c *Config) useDatabase(dbName string) {
   129  	c.DBName = dbName
   130  }
   131  
   132  // useDatabase change the inner db name.
   133  func (c *Config) setIdentifier(identifier string) {
   134  	c.Identifier = identifier
   135  }
   136  
   137  // Get parsed grpc dial options, should be called after parse was called.
   138  func (c *Config) getDialOption() []grpc.DialOption {
   139  	var options []grpc.DialOption
   140  	// Construct dial option.
   141  	if c.EnableTLSAuth {
   142  		options = append(options, grpc.WithTransportCredentials(credentials.NewTLS(&tls.Config{})))
   143  	} else {
   144  		options = append(options, grpc.WithTransportCredentials(insecure.NewCredentials()))
   145  	}
   146  
   147  	if c.DialOptions == nil {
   148  		// Add default connection options.
   149  		options = append(options, DefaultGrpcOpts...)
   150  	} else {
   151  		options = append(options, c.DialOptions...)
   152  	}
   153  
   154  	options = append(options,
   155  		grpc.WithChainUnaryInterceptor(grpc_retry.UnaryClientInterceptor(
   156  			grpc_retry.WithMax(6),
   157  			grpc_retry.WithBackoff(func(attempt uint) time.Duration {
   158  				return 60 * time.Millisecond * time.Duration(math.Pow(3, float64(attempt)))
   159  			}),
   160  			grpc_retry.WithCodes(codes.Unavailable, codes.ResourceExhausted)),
   161  			c.getRetryOnRateLimitInterceptor(),
   162  		))
   163  
   164  	options = append(options, grpc.WithChainUnaryInterceptor(
   165  		createMetaDataUnaryInterceptor(c),
   166  	))
   167  	return options
   168  }
   169  
   170  func (c *Config) getRetryOnRateLimitInterceptor() grpc.UnaryClientInterceptor {
   171  	if c.RetryRateLimit == nil {
   172  		c.RetryRateLimit = c.defaultRetryRateLimitOption()
   173  	}
   174  
   175  	return RetryOnRateLimitInterceptor(c.RetryRateLimit.MaxRetry, c.RetryRateLimit.MaxBackoff, func(ctx context.Context, attempt uint) time.Duration {
   176  		return 10 * time.Millisecond * time.Duration(math.Pow(3, float64(attempt)))
   177  	})
   178  }
   179  
   180  func (c *Config) defaultRetryRateLimitOption() *RetryRateLimitOption {
   181  	return &RetryRateLimitOption{
   182  		MaxRetry:   75,
   183  		MaxBackoff: 3 * time.Second,
   184  	}
   185  }
   186  
   187  // addFlags set internal flags
   188  func (c *Config) addFlags(flags uint64) {
   189  	c.flags |= flags
   190  }
   191  
   192  // hasFlags check flags is set
   193  func (c *Config) hasFlags(flags uint64) bool {
   194  	return (c.flags & flags) > 0
   195  }
   196  
   197  func (c *Config) resetFlags(flags uint64) {
   198  	c.flags &= ^flags
   199  }