github.com/weaviate/weaviate@v1.24.6/modules/text2vec-transformers/clients/startup.go (about)

     1  //                           _       _
     2  // __      _____  __ ___   ___  __ _| |_ ___
     3  // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
     4  //  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
     5  //   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
     6  //
     7  //  Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
     8  //
     9  //  CONTACT: hello@weaviate.io
    10  //
    11  
    12  package clients
    13  
    14  import (
    15  	"context"
    16  	"net/http"
    17  	"strings"
    18  	"sync"
    19  	"time"
    20  
    21  	enterrors "github.com/weaviate/weaviate/entities/errors"
    22  
    23  	"github.com/pkg/errors"
    24  	"github.com/weaviate/weaviate/modules/text2vec-transformers/ent"
    25  )
    26  
    27  func (v *vectorizer) WaitForStartup(initCtx context.Context,
    28  	interval time.Duration,
    29  ) error {
    30  	endpoints := map[string]string{}
    31  	if v.originPassage != v.originQuery {
    32  		endpoints["passage"] = v.urlPassage("/.well-known/ready", ent.VectorizationConfig{})
    33  		endpoints["query"] = v.urlQuery("/.well-known/ready", ent.VectorizationConfig{})
    34  	} else {
    35  		endpoints[""] = v.urlPassage("/.well-known/ready", ent.VectorizationConfig{})
    36  	}
    37  
    38  	ch := make(chan error, len(endpoints))
    39  	var wg sync.WaitGroup
    40  	for serviceName, endpoint := range endpoints {
    41  		serviceName, endpoint := serviceName, endpoint
    42  		wg.Add(1)
    43  		enterrors.GoWrapper(func() {
    44  			defer wg.Done()
    45  			if err := v.waitFor(initCtx, interval, endpoint, serviceName); err != nil {
    46  				ch <- err
    47  			}
    48  		}, v.logger)
    49  	}
    50  	wg.Wait()
    51  	close(ch)
    52  
    53  	if len(ch) > 0 {
    54  		var errs []string
    55  		for err := range ch {
    56  			errs = append(errs, err.Error())
    57  		}
    58  		return errors.Errorf(strings.Join(errs, ", "))
    59  	}
    60  	return nil
    61  }
    62  
    63  func (v *vectorizer) waitFor(initCtx context.Context, interval time.Duration, endpoint string, serviceName string) error {
    64  	ticker := time.NewTicker(interval)
    65  	defer ticker.Stop()
    66  	expired := initCtx.Done()
    67  	var lastErr error
    68  	prefix := ""
    69  	if serviceName != "" {
    70  		prefix = "[" + serviceName + "] "
    71  	}
    72  
    73  	for {
    74  		select {
    75  		case <-ticker.C:
    76  			lastErr = v.checkReady(initCtx, endpoint, serviceName)
    77  			if lastErr == nil {
    78  				return nil
    79  			}
    80  			v.logger.
    81  				WithField("action", "transformer_remote_wait_for_startup").
    82  				WithError(lastErr).Warnf("%stransformer remote inference service not ready", prefix)
    83  		case <-expired:
    84  			return errors.Wrapf(lastErr, "%sinit context expired before remote was ready", prefix)
    85  		}
    86  	}
    87  }
    88  
    89  func (v *vectorizer) checkReady(initCtx context.Context, endpoint string, serviceName string) error {
    90  	// spawn a new context (derived on the overall context) which is used to
    91  	// consider an individual request timed out
    92  	// due to parent timeout being superior over request's one, request can be cancelled by parent timeout
    93  	// resulting in "send check ready request" even if service is responding with non 2xx http code
    94  	requestCtx, cancel := context.WithTimeout(initCtx, 500*time.Millisecond)
    95  	defer cancel()
    96  
    97  	req, err := http.NewRequestWithContext(requestCtx, http.MethodGet, endpoint, nil)
    98  	if err != nil {
    99  		return errors.Wrap(err, "create check ready request")
   100  	}
   101  
   102  	res, err := v.httpClient.Do(req)
   103  	if err != nil {
   104  		return errors.Wrap(err, "send check ready request")
   105  	}
   106  
   107  	defer res.Body.Close()
   108  	if res.StatusCode > 299 {
   109  		return errors.Errorf("not ready: status %d", res.StatusCode)
   110  	}
   111  
   112  	return nil
   113  }