Allow to tap multiple function services at one time (#1434)
The router taps function service one by one which is inefficient and increases the burden of executor. This PR aggregates all requests into one to solve the problem mentioned above.
This commit is contained in:
+45
-1
@@ -20,6 +20,8 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/hashicorp/go-multierror"
|
||||||
|
"github.com/pkg/errors"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -32,6 +34,7 @@ import (
|
|||||||
|
|
||||||
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
|
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
|
||||||
ferror "github.com/fission/fission/pkg/error"
|
ferror "github.com/fission/fission/pkg/error"
|
||||||
|
"github.com/fission/fission/pkg/executor/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
func (executor *Executor) getServiceForFunctionApi(w http.ResponseWriter, r *http.Request) {
|
func (executor *Executor) getServiceForFunctionApi(w http.ResponseWriter, r *http.Request) {
|
||||||
@@ -115,6 +118,7 @@ func (executor *Executor) getServiceForFunction(fn *fv1.Function) (string, error
|
|||||||
}
|
}
|
||||||
|
|
||||||
// find funcSvc and update its atime
|
// find funcSvc and update its atime
|
||||||
|
// TODO: Deprecated tapService
|
||||||
func (executor *Executor) tapService(w http.ResponseWriter, r *http.Request) {
|
func (executor *Executor) tapService(w http.ResponseWriter, r *http.Request) {
|
||||||
body, err := ioutil.ReadAll(r.Body)
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -137,6 +141,45 @@ func (executor *Executor) tapService(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// find funcSvc and update its atime
|
||||||
|
func (executor *Executor) tapServices(w http.ResponseWriter, r *http.Request) {
|
||||||
|
body, err := ioutil.ReadAll(r.Body)
|
||||||
|
if err != nil {
|
||||||
|
executor.logger.Error("failed to read tap service request", zap.Error(err))
|
||||||
|
http.Error(w, "Failed to read request", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
tapSvcReqs := []client.TapServiceRequest{}
|
||||||
|
err = json.Unmarshal(body, &tapSvcReqs)
|
||||||
|
if err != nil {
|
||||||
|
executor.logger.Error("failed to decode tap service request",
|
||||||
|
zap.Error(err),
|
||||||
|
zap.String("request-payload", string(body)))
|
||||||
|
http.Error(w, "Failed to decode tap service request", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
errs := &multierror.Error{}
|
||||||
|
for _, req := range tapSvcReqs {
|
||||||
|
svcHost := strings.TrimPrefix(req.ServiceUrl, "http://")
|
||||||
|
err = executor.fsCache.TouchByAddress(svcHost)
|
||||||
|
if err != nil {
|
||||||
|
errs = multierror.Append(errs,
|
||||||
|
errors.Wrapf(err, "'%v' failed to tap function '%v/%v' with service url '%v'",
|
||||||
|
req.FnMetadata.Namespace, req.FnMetadata.Name, req.ServiceUrl, req.FnExecutorType))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if errs.ErrorOrNil() != nil {
|
||||||
|
executor.logger.Error("error tapping function service", zap.Error(errs))
|
||||||
|
http.Error(w, "Not found", http.StatusNotFound)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
w.WriteHeader(http.StatusOK)
|
||||||
|
}
|
||||||
|
|
||||||
func (executor *Executor) healthHandler(w http.ResponseWriter, r *http.Request) {
|
func (executor *Executor) healthHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
w.WriteHeader(http.StatusOK)
|
w.WriteHeader(http.StatusOK)
|
||||||
}
|
}
|
||||||
@@ -144,7 +187,8 @@ func (executor *Executor) healthHandler(w http.ResponseWriter, r *http.Request)
|
|||||||
func (executor *Executor) GetHandler() http.Handler {
|
func (executor *Executor) GetHandler() http.Handler {
|
||||||
r := mux.NewRouter()
|
r := mux.NewRouter()
|
||||||
r.HandleFunc("/v2/getServiceForFunction", executor.getServiceForFunctionApi).Methods("POST")
|
r.HandleFunc("/v2/getServiceForFunction", executor.getServiceForFunctionApi).Methods("POST")
|
||||||
r.HandleFunc("/v2/tapService", executor.tapService).Methods("POST")
|
r.HandleFunc("/v2/tapService", executor.tapService).Methods("POST") // for backward compatibility
|
||||||
|
r.HandleFunc("/v2/tapServices", executor.tapServices).Methods("POST")
|
||||||
r.HandleFunc("/healthz", executor.healthHandler).Methods("GET")
|
r.HandleFunc("/healthz", executor.healthHandler).Methods("GET")
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,29 +26,36 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
fv1 "github.com/fission/fission/pkg/apis/fission.io/v1"
|
||||||
|
ferror "github.com/fission/fission/pkg/error"
|
||||||
"github.com/pkg/errors"
|
"github.com/pkg/errors"
|
||||||
"go.opencensus.io/plugin/ochttp"
|
"go.opencensus.io/plugin/ochttp"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"golang.org/x/net/context/ctxhttp"
|
"golang.org/x/net/context/ctxhttp"
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
|
|
||||||
ferror "github.com/fission/fission/pkg/error"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type Client struct {
|
type (
|
||||||
logger *zap.Logger
|
Client struct {
|
||||||
executorUrl string
|
logger *zap.Logger
|
||||||
tappedByUrl map[string]bool
|
executorUrl string
|
||||||
requestChan chan string
|
tappedByUrl map[string]TapServiceRequest
|
||||||
httpClient *http.Client
|
requestChan chan TapServiceRequest
|
||||||
}
|
httpClient *http.Client
|
||||||
|
}
|
||||||
|
TapServiceRequest struct {
|
||||||
|
FnMetadata metav1.ObjectMeta
|
||||||
|
FnExecutorType fv1.ExecutorType
|
||||||
|
ServiceUrl string
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
func MakeClient(logger *zap.Logger, executorUrl string) *Client {
|
func MakeClient(logger *zap.Logger, executorUrl string) *Client {
|
||||||
c := &Client{
|
c := &Client{
|
||||||
logger: logger.Named("executor_client"),
|
logger: logger.Named("executor_client"),
|
||||||
executorUrl: strings.TrimSuffix(executorUrl, "/"),
|
executorUrl: strings.TrimSuffix(executorUrl, "/"),
|
||||||
tappedByUrl: make(map[string]bool),
|
tappedByUrl: make(map[string]TapServiceRequest),
|
||||||
requestChan: make(chan string),
|
requestChan: make(chan TapServiceRequest),
|
||||||
httpClient: &http.Client{
|
httpClient: &http.Client{
|
||||||
Transport: &ochttp.Transport{},
|
Transport: &ochttp.Transport{},
|
||||||
},
|
},
|
||||||
@@ -87,40 +94,64 @@ func (c *Client) service() {
|
|||||||
ticker := time.NewTicker(time.Second * 5)
|
ticker := time.NewTicker(time.Second * 5)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case serviceUrl := <-c.requestChan:
|
case svcReq := <-c.requestChan:
|
||||||
c.tappedByUrl[serviceUrl] = true
|
c.tappedByUrl[svcReq.ServiceUrl] = svcReq
|
||||||
case <-ticker.C:
|
case <-ticker.C:
|
||||||
urls := c.tappedByUrl
|
if len(c.tappedByUrl) == 0 {
|
||||||
c.tappedByUrl = make(map[string]bool)
|
continue
|
||||||
if len(urls) > 0 {
|
|
||||||
go func() {
|
|
||||||
for u := range urls {
|
|
||||||
err := c._tapService(u)
|
|
||||||
if err != nil {
|
|
||||||
c.logger.Error("error tapping function service address", zap.Error(err), zap.String("address", u))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
c.logger.Debug("tapped services in batch", zap.Int("service_count", len(urls)))
|
|
||||||
}()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
urls := c.tappedByUrl
|
||||||
|
c.tappedByUrl = make(map[string]TapServiceRequest)
|
||||||
|
|
||||||
|
go func() {
|
||||||
|
svcReqs := []TapServiceRequest{}
|
||||||
|
for _, req := range urls {
|
||||||
|
svcReqs = append(svcReqs, req)
|
||||||
|
}
|
||||||
|
c.logger.Debug("tapped services in batch", zap.Int("service_count", len(urls)))
|
||||||
|
|
||||||
|
err := c._tapService(svcReqs)
|
||||||
|
if err != nil {
|
||||||
|
c.logger.Error("error tapping function service address", zap.Error(err))
|
||||||
|
}
|
||||||
|
}()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) TapService(serviceUrl *url.URL) {
|
func (c *Client) TapService(fnMeta metav1.ObjectMeta, executorType fv1.ExecutorType, serviceUrl *url.URL) {
|
||||||
c.requestChan <- serviceUrl.String()
|
c.requestChan <- TapServiceRequest{
|
||||||
|
FnMetadata: metav1.ObjectMeta{
|
||||||
|
Name: fnMeta.Name,
|
||||||
|
Namespace: fnMeta.Namespace,
|
||||||
|
ResourceVersion: fnMeta.ResourceVersion,
|
||||||
|
UID: fnMeta.UID,
|
||||||
|
},
|
||||||
|
FnExecutorType: executorType,
|
||||||
|
// service url is for executor to know which
|
||||||
|
// pod/service is currently used to serve user function.
|
||||||
|
ServiceUrl: serviceUrl.String(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Client) _tapService(serviceUrlStr string) error {
|
func (c *Client) _tapService(tapSvcReqs []TapServiceRequest) error {
|
||||||
executorUrl := c.executorUrl + "/v2/tapService"
|
executorUrl := c.executorUrl + "/v2/tapServices"
|
||||||
|
|
||||||
resp, err := http.Post(executorUrl, "application/octet-stream", bytes.NewReader([]byte(serviceUrlStr)))
|
body, err := json.Marshal(tapSvcReqs)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
resp, err := http.Post(executorUrl, "application/json", bytes.NewReader(body))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
if resp.StatusCode != 200 {
|
if resp.StatusCode != 200 {
|
||||||
return ferror.MakeErrorFromHTTP(resp)
|
return ferror.MakeErrorFromHTTP(resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,9 +54,9 @@ type (
|
|||||||
logger *zap.Logger
|
logger *zap.Logger
|
||||||
fmap *functionServiceMap
|
fmap *functionServiceMap
|
||||||
executor *executorClient.Client
|
executor *executorClient.Client
|
||||||
function *metav1.ObjectMeta
|
function *fv1.Function
|
||||||
httpTrigger *fv1.HTTPTrigger
|
httpTrigger *fv1.HTTPTrigger
|
||||||
functionMetadataMap map[string]*metav1.ObjectMeta
|
functionMap map[string]*fv1.Function
|
||||||
fnWeightDistributionList []FunctionWeightDistribution
|
fnWeightDistributionList []FunctionWeightDistribution
|
||||||
tsRoundTripperParams *tsRoundTripperParams
|
tsRoundTripperParams *tsRoundTripperParams
|
||||||
isDebugEnv bool
|
isDebugEnv bool
|
||||||
@@ -150,7 +150,7 @@ func (roundTripper *RetryingRoundTripper) RoundTrip(req *http.Request) (*http.Re
|
|||||||
// Set forwarded host header if not exists
|
// Set forwarded host header if not exists
|
||||||
roundTripper.addForwardedHostHeader(req)
|
roundTripper.addForwardedHostHeader(req)
|
||||||
|
|
||||||
fnMeta := roundTripper.funcHandler.function
|
fnMeta := &roundTripper.funcHandler.function.Metadata
|
||||||
|
|
||||||
// Metrics stuff
|
// Metrics stuff
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
@@ -239,7 +239,7 @@ func (roundTripper *RetryingRoundTripper) RoundTrip(req *http.Request) (*http.Re
|
|||||||
|
|
||||||
// tapService before invoking roundTrip for the serviceUrl
|
// tapService before invoking roundTrip for the serviceUrl
|
||||||
if serviceUrlFromCache {
|
if serviceUrlFromCache {
|
||||||
go roundTripper.funcHandler.tapService(serviceUrl)
|
go roundTripper.funcHandler.tapService(roundTripper.funcHandler.function, serviceUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
// modify the request to reflect the service url
|
// modify the request to reflect the service url
|
||||||
@@ -388,25 +388,25 @@ func (roundTripper *RetryingRoundTripper) closeContext() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fh *functionHandler) tapService(serviceUrl *url.URL) {
|
func (fh *functionHandler) tapService(fn *fv1.Function, serviceUrl *url.URL) {
|
||||||
if fh.executor == nil {
|
if fh.executor == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fh.executor.TapService(serviceUrl)
|
fh.executor.TapService(fn.Metadata, fn.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType, serviceUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (fh functionHandler) handler(responseWriter http.ResponseWriter, request *http.Request) {
|
func (fh functionHandler) handler(responseWriter http.ResponseWriter, request *http.Request) {
|
||||||
if fh.httpTrigger != nil && fh.httpTrigger.Spec.FunctionReference.Type == types.FunctionReferenceTypeFunctionWeights {
|
if fh.httpTrigger != nil && fh.httpTrigger.Spec.FunctionReference.Type == types.FunctionReferenceTypeFunctionWeights {
|
||||||
// canary deployment. need to determine the function to send request to now
|
// canary deployment. need to determine the function to send request to now
|
||||||
fnMetadata := getCanaryBackend(fh.functionMetadataMap, fh.fnWeightDistributionList)
|
fn := getCanaryBackend(fh.functionMap, fh.fnWeightDistributionList)
|
||||||
if fnMetadata == nil {
|
if fn == nil {
|
||||||
fh.logger.Error("could not get canary backend",
|
fh.logger.Error("could not get canary backend",
|
||||||
zap.Any("metadataMap", fh.functionMetadataMap),
|
zap.Any("fnMap", fh.functionMap),
|
||||||
zap.Any("distributionList", fh.fnWeightDistributionList))
|
zap.Any("distributionList", fh.fnWeightDistributionList))
|
||||||
// TODO : write error to responseWrite and return response
|
// TODO : write error to responseWrite and return response
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
fh.function = fnMetadata
|
fh.function = fn
|
||||||
fh.logger.Debug("chosen function backend's metadata", zap.Any("metadata", fh.function))
|
fh.logger.Debug("chosen function backend's metadata", zap.Any("metadata", fh.function))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -414,7 +414,7 @@ func (fh functionHandler) handler(responseWriter http.ResponseWriter, request *h
|
|||||||
setPathInfoToHeader(request)
|
setPathInfoToHeader(request)
|
||||||
|
|
||||||
// system params
|
// system params
|
||||||
setFunctionMetadataToHeader(fh.function, request)
|
setFunctionMetadataToHeader(&fh.function.Metadata, request)
|
||||||
|
|
||||||
director := func(req *http.Request) {
|
director := func(req *http.Request) {
|
||||||
if _, ok := req.Header["User-Agent"]; !ok {
|
if _, ok := req.Header["User-Agent"]; !ok {
|
||||||
@@ -423,7 +423,7 @@ func (fh functionHandler) handler(responseWriter http.ResponseWriter, request *h
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fnTimeout := fh.functionTimeoutMap[fh.function.GetUID()]
|
fnTimeout := fh.functionTimeoutMap[fh.function.Metadata.GetUID()]
|
||||||
if fnTimeout == 0 {
|
if fnTimeout == 0 {
|
||||||
fnTimeout = fv1.DEFAULT_FUNCTION_TIMEOUT
|
fnTimeout = fv1.DEFAULT_FUNCTION_TIMEOUT
|
||||||
}
|
}
|
||||||
@@ -437,7 +437,7 @@ func (fh functionHandler) handler(responseWriter http.ResponseWriter, request *h
|
|||||||
proxy := &httputil.ReverseProxy{
|
proxy := &httputil.ReverseProxy{
|
||||||
Director: director,
|
Director: director,
|
||||||
Transport: rrt,
|
Transport: rrt,
|
||||||
ErrorHandler: getProxyErrorHandler(fh.logger, fh.function),
|
ErrorHandler: getProxyErrorHandler(fh.logger, &fh.function.Metadata),
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func() {
|
defer func() {
|
||||||
@@ -483,12 +483,10 @@ func findCeil(randomNumber int, wtDistrList []FunctionWeightDistribution) string
|
|||||||
}
|
}
|
||||||
|
|
||||||
// picks a function to route to based on a random number generated
|
// picks a function to route to based on a random number generated
|
||||||
func getCanaryBackend(fnMetadatamap map[string]*metav1.ObjectMeta, fnWtDistributionList []FunctionWeightDistribution) *metav1.ObjectMeta {
|
func getCanaryBackend(fnMap map[string]*fv1.Function, fnWtDistributionList []FunctionWeightDistribution) *fv1.Function {
|
||||||
randomNumber := rand.Intn(fnWtDistributionList[len(fnWtDistributionList)-1].sumPrefix + 1)
|
randomNumber := rand.Intn(fnWtDistributionList[len(fnWtDistributionList)-1].sumPrefix + 1)
|
||||||
|
|
||||||
fnName := findCeil(randomNumber, fnWtDistributionList)
|
fnName := findCeil(randomNumber, fnWtDistributionList)
|
||||||
|
return fnMap[fnName]
|
||||||
return fnMetadatamap[fnName]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// getProxyErrorHandler returns a reverse proxy error handler
|
// getProxyErrorHandler returns a reverse proxy error handler
|
||||||
@@ -574,28 +572,30 @@ func (fh *functionHandler) getServiceEntry() (serviceUrl *url.URL, serviceUrlFro
|
|||||||
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
||||||
defer cancel()
|
defer cancel()
|
||||||
|
|
||||||
|
fnMeta := &fh.function.Metadata
|
||||||
|
|
||||||
// Use throttle to limit the total amount of requests sent
|
// Use throttle to limit the total amount of requests sent
|
||||||
// to the executor to prevent it from overloaded.
|
// to the executor to prevent it from overloaded.
|
||||||
recordObj, err := fh.svcAddrUpdateThrottler.RunOnce(
|
recordObj, err := fh.svcAddrUpdateThrottler.RunOnce(
|
||||||
crd.CacheKey(fh.function),
|
crd.CacheKey(fnMeta),
|
||||||
func(firstToTheLock bool) (interface{}, error) {
|
func(firstToTheLock bool) (interface{}, error) {
|
||||||
var u *url.URL
|
var u *url.URL
|
||||||
// Get service entry from executor and update cache if its the first goroutine
|
// Get service entry from executor and update cache if its the first goroutine
|
||||||
if firstToTheLock { // first to the service url
|
if firstToTheLock { // first to the service url
|
||||||
fh.logger.Debug("calling getServiceForFunction",
|
fh.logger.Debug("calling getServiceForFunction",
|
||||||
zap.String("function_name", fh.function.Name))
|
zap.String("function_name", fnMeta.Name))
|
||||||
u, err = fh.getServiceEntryFromExecutor(ctx)
|
u, err = fh.getServiceEntryFromExecutor(ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fh.logger.Error("error getting service url from executor",
|
fh.logger.Error("error getting service url from executor",
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
zap.String("function_name", fh.function.Name))
|
zap.String("function_name", fnMeta.Name))
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
// add the address in router's cache
|
// add the address in router's cache
|
||||||
fh.logger.Info("assigning service url for function",
|
fh.logger.Info("assigning service url for function",
|
||||||
zap.String("url", u.String()),
|
zap.String("url", u.String()),
|
||||||
zap.String("function_name", fh.function.Name))
|
zap.String("function_name", fnMeta.Name))
|
||||||
fh.fmap.assign(fh.function, u)
|
fh.fmap.assign(fnMeta, u)
|
||||||
} else {
|
} else {
|
||||||
u, err = fh.getServiceEntryFromCache()
|
u, err = fh.getServiceEntryFromCache()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -613,9 +613,9 @@ func (fh *functionHandler) getServiceEntry() (serviceUrl *url.URL, serviceUrlFro
|
|||||||
e := "error updating service address entry for function"
|
e := "error updating service address entry for function"
|
||||||
fh.logger.Error(e,
|
fh.logger.Error(e,
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
zap.String("function_name", fh.function.Name),
|
zap.String("function_name", fnMeta.Name),
|
||||||
zap.String("function_namespace", fh.function.Namespace))
|
zap.String("function_namespace", fnMeta.Namespace))
|
||||||
return nil, false, errors.Wrapf(err, "%s %s_%s", e, fh.function.Name, fh.function.Namespace)
|
return nil, false, errors.Wrapf(err, "%s %s_%s", e, fnMeta.Name, fnMeta.Namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
record, ok := recordObj.(svcEntryRecord)
|
record, ok := recordObj.(svcEntryRecord)
|
||||||
@@ -629,7 +629,7 @@ func (fh *functionHandler) getServiceEntry() (serviceUrl *url.URL, serviceUrlFro
|
|||||||
// getServiceEntryFromCache returns service url entry returns from cache
|
// getServiceEntryFromCache returns service url entry returns from cache
|
||||||
func (fh *functionHandler) getServiceEntryFromCache() (serviceUrl *url.URL, err error) {
|
func (fh *functionHandler) getServiceEntryFromCache() (serviceUrl *url.URL, err error) {
|
||||||
// cache lookup to get serviceUrl
|
// cache lookup to get serviceUrl
|
||||||
serviceUrl, err = fh.fmap.lookup(fh.function)
|
serviceUrl, err = fh.fmap.lookup(&fh.function.Metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
var errMsg string
|
var errMsg string
|
||||||
|
|
||||||
@@ -642,7 +642,7 @@ func (fh *functionHandler) getServiceEntryFromCache() (serviceUrl *url.URL, err
|
|||||||
if e.Code == ferror.ErrorNotFound {
|
if e.Code == ferror.ErrorNotFound {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
errMsg = fmt.Sprintf("Error getting function %v;s service entry from cache: %v", fh.function.Name, err)
|
errMsg = fmt.Sprintf("Error getting function %v;s service entry from cache: %v", fh.function.Metadata.Name, err)
|
||||||
}
|
}
|
||||||
return nil, ferror.MakeError(http.StatusInternalServerError, errMsg)
|
return nil, ferror.MakeError(http.StatusInternalServerError, errMsg)
|
||||||
}
|
}
|
||||||
@@ -652,7 +652,7 @@ func (fh *functionHandler) getServiceEntryFromCache() (serviceUrl *url.URL, err
|
|||||||
// getServiceEntryFromExecutor returns service url entry returns from executor
|
// getServiceEntryFromExecutor returns service url entry returns from executor
|
||||||
func (fh *functionHandler) getServiceEntryFromExecutor(ctx context.Context) (*url.URL, error) {
|
func (fh *functionHandler) getServiceEntryFromExecutor(ctx context.Context) (*url.URL, error) {
|
||||||
// send a request to executor to specialize a new pod
|
// send a request to executor to specialize a new pod
|
||||||
service, err := fh.executor.GetServiceForFunction(ctx, fh.function)
|
service, err := fh.executor.GetServiceForFunction(ctx, &fh.function.Metadata)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
statusCode, errMsg := ferror.GetHTTPError(err)
|
statusCode, errMsg := ferror.GetHTTPError(err)
|
||||||
fh.logger.Error("error from GetServiceForFunction",
|
fh.logger.Error("error from GetServiceForFunction",
|
||||||
|
|||||||
@@ -57,12 +57,12 @@ func TestFunctionProxying(t *testing.T) {
|
|||||||
backendURL := createBackendService(testResponseString)
|
backendURL := createBackendService(testResponseString)
|
||||||
log.Printf("Created backend svc at %v", backendURL)
|
log.Printf("Created backend svc at %v", backendURL)
|
||||||
|
|
||||||
fn := &metav1.ObjectMeta{Name: "foo", Namespace: metav1.NamespaceDefault}
|
fnMeta := metav1.ObjectMeta{Name: "foo", Namespace: metav1.NamespaceDefault}
|
||||||
logger, err := zap.NewDevelopment()
|
logger, err := zap.NewDevelopment()
|
||||||
panicIf(err)
|
panicIf(err)
|
||||||
|
|
||||||
fmap := makeFunctionServiceMap(logger, 0)
|
fmap := makeFunctionServiceMap(logger, 0)
|
||||||
fmap.assign(fn, backendURL)
|
fmap.assign(&fnMeta, backendURL)
|
||||||
|
|
||||||
httpTrigger := &fv1.HTTPTrigger{
|
httpTrigger := &fv1.HTTPTrigger{
|
||||||
Metadata: metav1.ObjectMeta{
|
Metadata: metav1.ObjectMeta{
|
||||||
@@ -78,9 +78,11 @@ func TestFunctionProxying(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fh := &functionHandler{
|
fh := &functionHandler{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
fmap: fmap,
|
fmap: fmap,
|
||||||
function: fn,
|
function: &fv1.Function{
|
||||||
|
Metadata: metav1.ObjectMeta{Name: "foo", Namespace: metav1.NamespaceDefault},
|
||||||
|
},
|
||||||
tsRoundTripperParams: &tsRoundTripperParams{
|
tsRoundTripperParams: &tsRoundTripperParams{
|
||||||
timeout: 50 * time.Millisecond,
|
timeout: 50 * time.Millisecond,
|
||||||
timeoutExponent: 2,
|
timeoutExponent: 2,
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ type (
|
|||||||
// a distribution of requests across two functions.
|
// a distribution of requests across two functions.
|
||||||
resolveResult struct {
|
resolveResult struct {
|
||||||
resolveResultType
|
resolveResultType
|
||||||
functionMetadataMap map[string]*metav1.ObjectMeta
|
functionMap map[string]*fv1.Function
|
||||||
functionWtDistributionList []FunctionWeightDistribution
|
functionWtDistributionList []FunctionWeightDistribution
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -134,12 +134,13 @@ func (frr *functionReferenceResolver) resolveByName(namespace, name string) (*re
|
|||||||
}
|
}
|
||||||
|
|
||||||
f := obj.(*fv1.Function)
|
f := obj.(*fv1.Function)
|
||||||
functionMetadataMap := make(map[string]*metav1.ObjectMeta, 1)
|
functionMap := map[string]*fv1.Function{
|
||||||
functionMetadataMap[f.Metadata.Name] = &f.Metadata
|
f.Metadata.Name: f,
|
||||||
|
}
|
||||||
|
|
||||||
rr := resolveResult{
|
rr := resolveResult{
|
||||||
resolveResultType: resolveResultSingleFunction,
|
resolveResultType: resolveResultSingleFunction,
|
||||||
functionMetadataMap: functionMetadataMap,
|
functionMap: functionMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
return &rr, nil
|
return &rr, nil
|
||||||
@@ -147,7 +148,7 @@ func (frr *functionReferenceResolver) resolveByName(namespace, name string) (*re
|
|||||||
|
|
||||||
func (frr *functionReferenceResolver) resolveByFunctionWeights(namespace string, fr *fv1.FunctionReference) (*resolveResult, error) {
|
func (frr *functionReferenceResolver) resolveByFunctionWeights(namespace string, fr *fv1.FunctionReference) (*resolveResult, error) {
|
||||||
|
|
||||||
functionMetadataMap := make(map[string]*metav1.ObjectMeta)
|
functionMap := make(map[string]*fv1.Function)
|
||||||
fnWtDistrList := make([]FunctionWeightDistribution, 0)
|
fnWtDistrList := make([]FunctionWeightDistribution, 0)
|
||||||
sumPrefix := 0
|
sumPrefix := 0
|
||||||
|
|
||||||
@@ -167,19 +168,18 @@ func (frr *functionReferenceResolver) resolveByFunctionWeights(namespace string,
|
|||||||
}
|
}
|
||||||
|
|
||||||
f := obj.(*fv1.Function)
|
f := obj.(*fv1.Function)
|
||||||
functionMetadataMap[f.Metadata.Name] = &f.Metadata
|
functionMap[f.Metadata.Name] = f
|
||||||
sumPrefix = sumPrefix + functionWeight
|
sumPrefix = sumPrefix + functionWeight
|
||||||
fnWtDistrList = append(fnWtDistrList, FunctionWeightDistribution{
|
fnWtDistrList = append(fnWtDistrList, FunctionWeightDistribution{
|
||||||
name: functionName,
|
name: functionName,
|
||||||
weight: functionWeight,
|
weight: functionWeight,
|
||||||
sumPrefix: sumPrefix,
|
sumPrefix: sumPrefix,
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rr := resolveResult{
|
rr := resolveResult{
|
||||||
resolveResultType: resolveResultMultipleFunctions,
|
resolveResultType: resolveResultMultipleFunctions,
|
||||||
functionMetadataMap: functionMetadataMap,
|
functionMap: functionMap,
|
||||||
functionWtDistributionList: fnWtDistrList,
|
functionWtDistributionList: fnWtDistrList,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+10
-11
@@ -142,7 +142,7 @@ func (ts *HTTPTriggerSet) getRouter(fnTimeoutMap map[types.UID]int) *mux.Router
|
|||||||
fmap: ts.functionServiceMap,
|
fmap: ts.functionServiceMap,
|
||||||
executor: ts.executor,
|
executor: ts.executor,
|
||||||
httpTrigger: &trigger,
|
httpTrigger: &trigger,
|
||||||
functionMetadataMap: rr.functionMetadataMap,
|
functionMap: rr.functionMap,
|
||||||
fnWeightDistributionList: rr.functionWtDistributionList,
|
fnWeightDistributionList: rr.functionWtDistributionList,
|
||||||
tsRoundTripperParams: ts.tsRoundTripperParams,
|
tsRoundTripperParams: ts.tsRoundTripperParams,
|
||||||
isDebugEnv: ts.isDebugEnv,
|
isDebugEnv: ts.isDebugEnv,
|
||||||
@@ -158,8 +158,8 @@ func (ts *HTTPTriggerSet) getRouter(fnTimeoutMap map[types.UID]int) *mux.Router
|
|||||||
// deployment. For more details, please check "handler" function of functionHandler.
|
// deployment. For more details, please check "handler" function of functionHandler.
|
||||||
|
|
||||||
if rr.resolveResultType == resolveResultSingleFunction {
|
if rr.resolveResultType == resolveResultSingleFunction {
|
||||||
for _, metadata := range fh.functionMetadataMap {
|
for _, fn := range fh.functionMap {
|
||||||
fh.function = metadata
|
fh.function = fn
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,20 +185,19 @@ func (ts *HTTPTriggerSet) getRouter(fnTimeoutMap map[types.UID]int) *mux.Router
|
|||||||
|
|
||||||
// Internal triggers for each function by name. Non-http
|
// Internal triggers for each function by name. Non-http
|
||||||
// triggers route into these.
|
// triggers route into these.
|
||||||
for _, function := range ts.functions {
|
for i := range ts.functions {
|
||||||
m := function.Metadata
|
fn := ts.functions[i]
|
||||||
|
|
||||||
fh := &functionHandler{
|
fh := &functionHandler{
|
||||||
logger: ts.logger.Named(m.Name),
|
logger: ts.logger.Named(fn.Metadata.Name),
|
||||||
fmap: ts.functionServiceMap,
|
fmap: ts.functionServiceMap,
|
||||||
function: &m,
|
function: &fn,
|
||||||
executor: ts.executor,
|
executor: ts.executor,
|
||||||
tsRoundTripperParams: ts.tsRoundTripperParams,
|
tsRoundTripperParams: ts.tsRoundTripperParams,
|
||||||
isDebugEnv: ts.isDebugEnv,
|
isDebugEnv: ts.isDebugEnv,
|
||||||
svcAddrUpdateThrottler: ts.svcAddrUpdateThrottler,
|
svcAddrUpdateThrottler: ts.svcAddrUpdateThrottler,
|
||||||
functionTimeoutMap: fnTimeoutMap,
|
functionTimeoutMap: fnTimeoutMap,
|
||||||
}
|
}
|
||||||
muxRouter.HandleFunc(utils.UrlForFunction(function.Metadata.Name, function.Metadata.Namespace), fh.handler)
|
muxRouter.HandleFunc(utils.UrlForFunction(fn.Metadata.Name, fn.Metadata.Namespace), fh.handler)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Healthz endpoint for the router.
|
// Healthz endpoint for the router.
|
||||||
@@ -263,8 +262,8 @@ func (ts *HTTPTriggerSet) initFunctionController() (k8sCache.Store, k8sCache.Con
|
|||||||
// update resolver function reference cache
|
// update resolver function reference cache
|
||||||
for key, rr := range ts.resolver.copy() {
|
for key, rr := range ts.resolver.copy() {
|
||||||
if key.namespace == fn.Metadata.Namespace &&
|
if key.namespace == fn.Metadata.Namespace &&
|
||||||
rr.functionMetadataMap[fn.Metadata.Name] != nil &&
|
rr.functionMap[fn.Metadata.Name] != nil &&
|
||||||
rr.functionMetadataMap[fn.Metadata.Name].ResourceVersion != fn.Metadata.ResourceVersion {
|
rr.functionMap[fn.Metadata.Name].Metadata.ResourceVersion != fn.Metadata.ResourceVersion {
|
||||||
// invalidate resolver cache
|
// invalidate resolver cache
|
||||||
ts.logger.Debug("invalidating resolver cache")
|
ts.logger.Debug("invalidating resolver cache")
|
||||||
err := ts.resolver.delete(key.namespace, key.triggerName, key.triggerResourceVersion)
|
err := ts.resolver.delete(key.namespace, key.triggerName, key.triggerResourceVersion)
|
||||||
|
|||||||
@@ -32,12 +32,12 @@ import (
|
|||||||
|
|
||||||
func TestRouter(t *testing.T) {
|
func TestRouter(t *testing.T) {
|
||||||
// metadata for a fake function
|
// metadata for a fake function
|
||||||
fn := &metav1.ObjectMeta{Name: "foo", Namespace: metav1.NamespaceDefault}
|
fnMeta := metav1.ObjectMeta{Name: "foo", Namespace: metav1.NamespaceDefault}
|
||||||
|
|
||||||
// and a reference to it
|
// and a reference to it
|
||||||
fr := fv1.FunctionReference{
|
fr := fv1.FunctionReference{
|
||||||
Type: types.FunctionReferenceTypeFunctionName,
|
Type: types.FunctionReferenceTypeFunctionName,
|
||||||
Name: fn.Name,
|
Name: fnMeta.Name,
|
||||||
}
|
}
|
||||||
|
|
||||||
// start a fake service
|
// start a fake service
|
||||||
@@ -49,7 +49,7 @@ func TestRouter(t *testing.T) {
|
|||||||
|
|
||||||
// set up the cache with this fake service
|
// set up the cache with this fake service
|
||||||
fmap := makeFunctionServiceMap(logger, 0)
|
fmap := makeFunctionServiceMap(logger, 0)
|
||||||
fmap.assign(fn, testServiceUrl)
|
fmap.assign(&fnMeta, testServiceUrl)
|
||||||
|
|
||||||
// HTTP trigger set with a trigger for this function
|
// HTTP trigger set with a trigger for this function
|
||||||
triggers, _, _ := makeHTTPTriggerSet(logger, fmap, nil, nil, nil, nil,
|
triggers, _, _ := makeHTTPTriggerSet(logger, fmap, nil, nil, nil, nil,
|
||||||
@@ -81,12 +81,14 @@ func TestRouter(t *testing.T) {
|
|||||||
triggerResourceVersion: "1234",
|
triggerResourceVersion: "1234",
|
||||||
}
|
}
|
||||||
|
|
||||||
fnMetaMap := make(map[string]*metav1.ObjectMeta, 1)
|
fnMetaMap := make(map[string]*fv1.Function, 1)
|
||||||
fnMetaMap[fn.Name] = fn
|
fnMetaMap[fnMeta.Name] = &fv1.Function{
|
||||||
|
Metadata: fnMeta,
|
||||||
|
}
|
||||||
|
|
||||||
rr := resolveResult{
|
rr := resolveResult{
|
||||||
resolveResultType: resolveResultSingleFunction,
|
resolveResultType: resolveResultSingleFunction,
|
||||||
functionMetadataMap: fnMetaMap,
|
functionMap: fnMetaMap,
|
||||||
}
|
}
|
||||||
frr.refCache.Set(nfr, rr)
|
frr.refCache.Set(nfr, rr)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user