Feature request per pod (#1946)

This feature enables routing more than one request to a pod at the same time. This is the first draft of the work and might involve more optimizations later.
This commit is contained in:
Rahul Bhati
2021-03-31 12:35:30 +05:30
committed by GitHub
parent 3e6dae9616
commit 25acd7fd16
39 changed files with 511 additions and 264 deletions
+58 -40
View File
@@ -50,25 +50,60 @@ func (executor *Executor) getServiceForFunctionAPI(w http.ResponseWriter, r *htt
}
t := fn.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType
et, exists := executor.executorTypes[t]
if !exists {
http.Error(w, fmt.Sprintf("Unknown executor type '%v'", t), http.StatusNotFound)
return
}
et := executor.executorTypes[t]
executor.logger.Debug(fmt.Sprintf("active instances: %v", et.GetTotalAvailable(fn)))
conncurrency := fn.Spec.Concurrency
if conncurrency == 0 {
// set to default conncurrency
conncurrency = 5
executor.logger.Debug(fmt.Sprintf("concurrency specified in function: %v", fn.Spec.Concurrency))
executor.logger.Debug("setting concurrency to 5")
}
if t == fv1.ExecutorTypePoolmgr && et.GetTotalAvailable(fn) >= conncurrency {
errMsg := fmt.Sprintf("max concurrency reached for %v. All %v instance are active", fn.ObjectMeta.Name, conncurrency)
executor.logger.Error("error occurred", zap.String("error", errMsg))
http.Error(w, errMsg, http.StatusTooManyRequests)
return
// Check function -> svc cache
executor.logger.Debug("checking for cached function service",
zap.String("function_name", fn.ObjectMeta.Name),
zap.String("function_namespace", fn.ObjectMeta.Namespace))
if t == fv1.ExecutorTypePoolmgr {
concurrency := fn.Spec.Concurrency
if concurrency == 0 {
concurrency = 5
}
requestsPerpod := fn.Spec.RequestsPerPod
if requestsPerpod == 0 {
requestsPerpod = 1
}
fsvc, active, err := et.GetFuncSvcFromPoolCache(fn, requestsPerpod)
// check if its a cache hit (check if there is already specialized function pod that can serve another request)
if err == nil {
// if a pod is already serving request then it already exists else validated
executor.logger.Debug("from cache", zap.Int("active", active))
if active > 1 || et.IsValid(fsvc) {
// Cached, return svc address
executor.logger.Debug("served from cache", zap.String("name", fsvc.Name), zap.String("address", fsvc.Address))
executor.writeResponse(w, fsvc.Address, fn.ObjectMeta.Name)
return
}
executor.logger.Debug("deleting cache entry for invalid address",
zap.String("function_name", fn.ObjectMeta.Name),
zap.String("function_namespace", fn.ObjectMeta.Namespace),
zap.String("address", fsvc.Address))
et.DeleteFuncSvcFromCache(fsvc)
active--
}
if active >= concurrency {
errMsg := fmt.Sprintf("max concurrency reached for %v. All %v instance are active", fn.ObjectMeta.Name, concurrency)
executor.logger.Error("error occurred", zap.String("error", errMsg))
http.Error(w, errMsg, http.StatusTooManyRequests)
return
}
} else {
fsvc, err := et.GetFuncSvcFromCache(fn)
if err == nil {
if et.IsValid(fsvc) {
// Cached, return svc address
executor.writeResponse(w, fsvc.Address, fn.ObjectMeta.Name)
return
}
executor.logger.Debug("deleting cache entry for invalid address",
zap.String("function_name", fn.ObjectMeta.Name),
zap.String("function_namespace", fn.ObjectMeta.Namespace),
zap.String("address", fsvc.Address))
et.DeleteFuncSvcFromCache(fsvc)
}
}
serviceName, err := executor.getServiceForFunction(fn)
@@ -81,12 +116,15 @@ func (executor *Executor) getServiceForFunctionAPI(w http.ResponseWriter, r *htt
http.Error(w, msg, code)
return
}
executor.writeResponse(w, serviceName, fn.ObjectMeta.Name)
}
_, err = w.Write([]byte(serviceName))
func (executor *Executor) writeResponse(w http.ResponseWriter, serviceName string, fnName string) {
_, err := w.Write([]byte(serviceName))
if err != nil {
executor.logger.Error(
"error writing HTTP response",
zap.String("function", fn.ObjectMeta.Name),
zap.String("function", fnName),
zap.Error(err),
)
}
@@ -102,26 +140,6 @@ func (executor *Executor) getServiceForFunctionAPI(w http.ResponseWriter, r *htt
// To make it optimal, plan is to add an eager cache invalidator function that watches for pod deletion events and
// invalidates the cache entry if the pod address was cached.
func (executor *Executor) getServiceForFunction(fn *fv1.Function) (string, error) {
t := fn.Spec.InvokeStrategy.ExecutionStrategy.ExecutorType
et := executor.executorTypes[t]
// Check function -> svc cache
executor.logger.Debug("checking for cached function service",
zap.String("function_name", fn.ObjectMeta.Name),
zap.String("function_namespace", fn.ObjectMeta.Namespace))
fsvc, err := et.GetFuncSvcFromCache(fn)
if err == nil {
if et.IsValid(fsvc) {
// Cached, return svc address
return fsvc.Address, nil
}
executor.logger.Debug("deleting cache entry for invalid address",
zap.String("function_name", fn.ObjectMeta.Name),
zap.String("function_namespace", fn.ObjectMeta.Namespace),
zap.String("address", fsvc.Address))
et.DeleteFuncSvcFromCache(fsvc)
}
respChan := make(chan *createFuncServiceResponse)
executor.requestChan <- &createFuncServiceRequest{
function: fn,
+2 -2
View File
@@ -238,7 +238,7 @@ func serveMetric(logger *zap.Logger) {
// StartExecutor Starts executor and the executor components such as Poolmgr,
// deploymgr and potential future executor types
func StartExecutor(logger *zap.Logger, functionNamespace string, envBuilderNamespace string, port int) error {
fissionClient, kubernetesClient, _, err := crd.MakeFissionClient()
fissionClient, kubernetesClient, _, metricsClient, err := crd.MakeFissionClient()
if err != nil {
return errors.Wrap(err, "failed to get kubernetes client")
}
@@ -259,7 +259,7 @@ func StartExecutor(logger *zap.Logger, functionNamespace string, envBuilderNames
gpm := poolmgr.MakeGenericPoolManager(
logger,
fissionClient, kubernetesClient,
fissionClient, kubernetesClient, metricsClient,
functionNamespace, fetcherConfig, executorInstanceID)
ndm := newdeploy.MakeNewDeploy(
+1 -1
View File
@@ -115,7 +115,7 @@ func TestExecutor(t *testing.T) {
// connect to k8s
// and get CRD client
fissionClient, kubeClient, apiExtClient, err := crd.MakeFissionClient()
fissionClient, kubeClient, apiExtClient, _, err := crd.MakeFissionClient()
if err != nil {
log.Panicf("failed to connect: %v", err)
}
+3 -3
View File
@@ -38,6 +38,9 @@ type ExecutorType interface {
// GetFuncSvcFromCache retrieves function service from cache.
GetFuncSvcFromCache(*fv1.Function) (*fscache.FuncSvc, error)
// GetFuncSvcFromPoolCache retrieves function service and number of active instances after filtering on requestsPerPod and CPULimit
GetFuncSvcFromPoolCache(fn *fv1.Function, requestsPerPod int) (*fscache.FuncSvc, int, error)
// DeleteFuncSvcFromCache deletes function service entry in cache.
DeleteFuncSvcFromCache(*fscache.FuncSvc)
@@ -60,7 +63,4 @@ type ExecutorType interface {
// CleanupOldExecutorObjects cleans up resources created by old executor instances
CleanupOldExecutorObjects()
// getTotalAvailable returns total active instances of particular function
GetTotalAvailable(*fv1.Function) int
}
@@ -165,10 +165,10 @@ func (deploy *NewDeploy) UnTapService(key string, svcHost string) {
// Not Implemented for NewDeployment. Will be used when support of concurrent specialization of same function is added.
}
// GetTotalAvailable has not been implemented for NewDeployment.
func (deploy *NewDeploy) GetTotalAvailable(fn *fv1.Function) int {
// GetFuncSvcFromPoolCache has not been implemented for NewDeployment
func (deploy *NewDeploy) GetFuncSvcFromPoolCache(fn *fv1.Function, requestsPerPod int) (*fscache.FuncSvc, int, error) {
// Not Implemented for NewDeployment. Will be used when support of concurrent specialization of same function is added.
return 0
return nil, 0, nil
}
// TapService makes a TouchByAddress request to the cache.
+61 -2
View File
@@ -20,9 +20,11 @@ import (
"context"
"encoding/json"
"fmt"
"math"
"net"
"os"
"strings"
"sync"
"time"
"github.com/dchest/uniuri"
@@ -32,13 +34,16 @@ import (
appsv1 "k8s.io/api/apps/v1"
apiv1 "k8s.io/api/core/v1"
k8sErrs "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
k8sTypes "k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/client-go/kubernetes"
"k8s.io/client-go/tools/cache"
"k8s.io/client-go/util/workqueue"
metricsclient "k8s.io/metrics/pkg/client/clientset/versioned"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/crd"
@@ -63,6 +68,7 @@ type (
useIstio bool
runtimeImagePullPolicy apiv1.PullPolicy // pull policy for generic pool to created env deployment
kubernetesClient *kubernetes.Clientset
metricsClient *metricsclient.Clientset
fissionClient *crd.FissionClient
fetcherConfig *fetcherConfig.Config
stopReadyPodControllerCh chan struct{}
@@ -71,6 +77,7 @@ type (
readyPodQueue workqueue.DelayingInterface
poolInstanceID string // small random string to uniquify pod names
instanceID string // poolmgr instance id
podFSVCMap sync.Map
}
)
@@ -79,6 +86,7 @@ func MakeGenericPool(
logger *zap.Logger,
fissionClient *crd.FissionClient,
kubernetesClient *kubernetes.Clientset,
metricsClient *metricsclient.Clientset,
env *fv1.Environment,
initialReplicas int32,
namespace string,
@@ -110,6 +118,7 @@ func MakeGenericPool(
replicas: initialReplicas, // TODO make this an env param instead?
fissionClient: fissionClient,
kubernetesClient: kubernetesClient,
metricsClient: metricsClient,
namespace: namespace,
functionNamespace: functionNamespace,
podReadyTimeout: podReadyTimeout,
@@ -120,6 +129,7 @@ func MakeGenericPool(
stopReadyPodControllerCh: make(chan struct{}),
poolInstanceID: uniuri.NewLen(8),
instanceID: instanceID,
podFSVCMap: sync.Map{},
}
gp.runtimeImagePullPolicy = utils.GetImagePullPolicy(os.Getenv("RUNTIME_IMAGE_PULL_POLICY"))
@@ -141,7 +151,7 @@ func MakeGenericPool(
gpLogger.Info("deployment created", zap.Any("environment", env.ObjectMeta))
go gp.startReadyPodController()
go gp.updateCPUUtilizationSvc()
return gp, nil
}
@@ -161,6 +171,35 @@ func (gp *GenericPool) getDeployAnnotations() map[string]string {
}
}
func (gp *GenericPool) updateCPUUtilizationSvc() {
for {
podMetricsList, err := gp.metricsClient.MetricsV1beta1().PodMetricses(gp.namespace).List(v1.ListOptions{
LabelSelector: "managed=false",
})
if err != nil {
gp.logger.Error("failed to fetch pod metrics list", zap.Error(err))
} else {
gp.logger.Debug("pods found", zap.Any("length", len(podMetricsList.Items)))
for _, val := range podMetricsList.Items {
p, _ := resource.ParseQuantity("0m")
for _, container := range val.Containers {
p.Add(container.Usage["cpu"])
}
if value, ok := gp.podFSVCMap.Load(val.ObjectMeta.Name); ok {
if valArray, ok1 := value.([]interface{}); ok1 {
function, address := valArray[0], valArray[1]
gp.fsCache.SetCPUUtilizaton(function.(string), address.(string), p)
gp.logger.Info(fmt.Sprintf("updated function %s, address %s, cpuUsage %+v", function.(string), address.(string), p))
}
}
}
}
time.Sleep(30 * time.Second)
}
}
// choosePod picks a ready pod from the pool and relabels it, waiting if necessary.
// returns the key and pod API object.
func (gp *GenericPool) choosePod(newLabels map[string]string) (string, *apiv1.Pod, error) {
@@ -564,7 +603,6 @@ func (gp *GenericPool) getFuncSvc(ctx context.Context, fn *fv1.Function) (*fscac
gp.scheduleDeletePod(pod.ObjectMeta.Name)
return nil, err
}
gp.logger.Info("specialized pod", zap.String("pod", pod.ObjectMeta.Name), zap.Any("function", fn.ObjectMeta))
var svcHost string
@@ -623,6 +661,19 @@ func (gp *GenericPool) getFuncSvc(ctx context.Context, fn *fv1.Function) (*fscac
UID: pod.ObjectMeta.UID,
},
}
cpuUsage := resource.MustParse("0m")
for _, container := range pod.Spec.Containers {
val := *container.Resources.Limits.Cpu()
cpuUsage.Add(val)
}
// set cpuLimit to 85th percentage of the cpuUsage
cpuLimit, err := gp.getPercent(cpuUsage, 0.85)
if err != nil {
gp.logger.Error("failed to get 85 of CPU usage", zap.Error(err))
cpuLimit = cpuUsage
}
gp.logger.Debug("cpuLimit set to", zap.Any("cpulimit", cpuLimit))
m := fn.ObjectMeta // only cache necessary part
fsvc := &fscache.FuncSvc{
@@ -632,10 +683,12 @@ func (gp *GenericPool) getFuncSvc(ctx context.Context, fn *fv1.Function) (*fscac
Address: svcHost,
KubernetesObjects: kubeObjRefs,
Executor: fv1.ExecutorTypePoolmgr,
CPULimit: cpuLimit,
Ctime: time.Now(),
Atime: time.Now(),
}
gp.podFSVCMap.Store(pod.ObjectMeta.Name, []interface{}{crd.CacheKey(fsvc.Function), fsvc.Address})
gp.fsCache.AddFunc(*fsvc)
gp.fsCache.IncreaseColdStarts(fn.ObjectMeta.Name, string(fn.ObjectMeta.UID))
@@ -643,6 +696,12 @@ func (gp *GenericPool) getFuncSvc(ctx context.Context, fn *fv1.Function) (*fscac
return fsvc, nil
}
// getPercent returns x percent of the quantity i.e multiple it x/100
func (gp *GenericPool) getPercent(cpuUsage resource.Quantity, percentage float64) (resource.Quantity, error) {
val := int64(math.Ceil(float64(cpuUsage.MilliValue()) * percentage))
return resource.ParseQuantity(fmt.Sprintf("%dm", val))
}
// destroys the pool -- the deployment, replicaset and pods
func (gp *GenericPool) destroy() error {
close(gp.stopReadyPodControllerCh)
+10 -6
View File
@@ -36,6 +36,7 @@ import (
k8sInformers "k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
k8sCache "k8s.io/client-go/tools/cache"
metricsclient "k8s.io/metrics/pkg/client/clientset/versioned"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
"github.com/fission/fission/pkg/cache"
@@ -62,6 +63,7 @@ type (
pools map[string]*GenericPool
kubernetesClient *kubernetes.Clientset
metricsClient *metricsclient.Clientset
namespace string
fissionClient *crd.FissionClient
@@ -97,6 +99,7 @@ func MakeGenericPoolManager(
logger *zap.Logger,
fissionClient *crd.FissionClient,
kubernetesClient *kubernetes.Clientset,
metricsClient *metricsclient.Clientset,
functionNamespace string,
fetcherConfig *fetcherConfig.Config,
instanceID string) executortype.ExecutorType {
@@ -107,6 +110,7 @@ func MakeGenericPoolManager(
logger: gpmLogger,
pools: make(map[string]*GenericPool),
kubernetesClient: kubernetesClient,
metricsClient: metricsClient,
namespace: functionNamespace,
fissionClient: fissionClient,
functionEnv: cache.MakeCache(10*time.Second, 0),
@@ -172,7 +176,11 @@ func (gpm *GenericPoolManager) GetFuncSvc(ctx context.Context, fn *fv1.Function)
}
func (gpm *GenericPoolManager) GetFuncSvcFromCache(fn *fv1.Function) (*fscache.FuncSvc, error) {
return gpm.fsCache.GetFuncSvc(&fn.ObjectMeta)
return nil, nil
}
func (gpm *GenericPoolManager) GetFuncSvcFromPoolCache(fn *fv1.Function, requestsPerPod int) (*fscache.FuncSvc, int, error) {
return gpm.fsCache.GetFuncSvc(&fn.ObjectMeta, requestsPerPod)
}
func (gpm *GenericPoolManager) DeleteFuncSvcFromCache(fsvc *fscache.FuncSvc) {
@@ -183,10 +191,6 @@ func (gpm *GenericPoolManager) UnTapService(key string, svcHost string) {
gpm.fsCache.MarkAvailable(key, svcHost)
}
func (gpm *GenericPoolManager) GetTotalAvailable(fn *fv1.Function) int {
return gpm.fsCache.GetTotalAvailable(&fn.ObjectMeta)
}
func (gpm *GenericPoolManager) TapService(svcHost string) error {
err := gpm.fsCache.TouchByAddress(svcHost)
if err != nil {
@@ -457,7 +461,7 @@ func (gpm *GenericPoolManager) service() {
}
pool, err = MakeGenericPool(gpm.logger,
gpm.fissionClient, gpm.kubernetesClient, req.env, poolsize,
gpm.fissionClient, gpm.kubernetesClient, gpm.metricsClient, req.env, poolsize,
ns, gpm.namespace, gpm.fsCache, gpm.fetcherConfig, gpm.instanceID, gpm.enableIstio)
if err != nil {
req.responseChannel <- &response{error: err}
@@ -23,7 +23,6 @@ func (gp *GenericPool) startReadyPodController() {
options.FieldSelector = "status.phase=Running"
}
readyPodWatcher := cache.NewFilteredListWatchFromClient(gp.kubernetesClient.CoreV1().RESTClient(), "pods", gp.namespace, optionsModifier)
gp.readyPodQueue = workqueue.NewDelayingQueue()
gp.readyPodIndexer, gp.readyPodController = cache.NewIndexerInformer(readyPodWatcher, &apiv1.Pod{}, 0, cache.ResourceEventHandlerFuncs{
AddFunc: func(obj interface{}) {
+17 -12
View File
@@ -23,6 +23,7 @@ import (
"github.com/pkg/errors"
"go.uber.org/zap"
apiv1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
@@ -30,7 +31,7 @@ import (
"github.com/fission/fission/pkg/cache"
"github.com/fission/fission/pkg/crd"
ferror "github.com/fission/fission/pkg/error"
poolcache "github.com/fission/fission/pkg/newcache"
"github.com/fission/fission/pkg/poolcache"
)
type fscRequestType int
@@ -54,6 +55,7 @@ type (
Address string // Host:Port or IP:Port that the function's service can be reached at.
KubernetesObjects []apiv1.ObjectReference // Kubernetes Objects (within the function namespace)
Executor fv1.ExecutorType
CPULimit resource.Quantity
Ctime time.Time
Atime time.Time
@@ -147,8 +149,7 @@ func (fsc *FunctionServiceCache) service() {
fscs := fsc.connFunctionCache.ListAvailableValue()
funcObjects := make([]*FuncSvc, 0)
for _, funcSvc := range fscs {
fsvc := funcSvc.(*FuncSvc)
if time.Since(fsvc.Atime) > req.age {
if fsvc, ok := funcSvc.(*FuncSvc); ok && time.Since(fsvc.Atime) > req.age {
funcObjects = append(funcObjects, fsvc)
}
}
@@ -176,14 +177,14 @@ func (fsc *FunctionServiceCache) GetByFunction(m *metav1.ObjectMeta) (*FuncSvc,
return &fsvcCopy, nil
}
// GetFuncSvc gets a function service from pool cache using function key.
func (fsc *FunctionServiceCache) GetFuncSvc(m *metav1.ObjectMeta) (*FuncSvc, error) {
// GetFuncSvc gets a function service from pool cache using function key and returns number of active instances of function pod
func (fsc *FunctionServiceCache) GetFuncSvc(m *metav1.ObjectMeta, requestsPerPod int) (*FuncSvc, int, error) {
key := crd.CacheKey(m)
fsvcI, err := fsc.connFunctionCache.GetValue(key)
fsvcI, active, err := fsc.connFunctionCache.GetValue(key, requestsPerPod)
if err != nil {
fsc.logger.Info("Not found in Cache")
return nil, err
return nil, active, err
}
// update atime
@@ -191,7 +192,7 @@ func (fsc *FunctionServiceCache) GetFuncSvc(m *metav1.ObjectMeta) (*FuncSvc, err
fsvc.Atime = time.Now()
fsvcCopy := *fsvc
return &fsvcCopy, nil
return &fsvcCopy, active, nil
}
// GetByFunctionUID gets a function service from cache using function UUID.
@@ -218,7 +219,7 @@ func (fsc *FunctionServiceCache) GetByFunctionUID(uid types.UID) (*FuncSvc, erro
// AddFunc adds a function service to pool cache.
func (fsc *FunctionServiceCache) AddFunc(fsvc FuncSvc) {
fsc.connFunctionCache.SetValue(crd.CacheKey(fsvc.Function), fsvc.Address, &fsvc)
fsc.connFunctionCache.SetValue(crd.CacheKey(fsvc.Function), fsvc.Address, &fsvc, fsvc.CPULimit)
now := time.Now()
fsvc.Ctime = now
fsvc.Atime = now
@@ -226,9 +227,9 @@ func (fsc *FunctionServiceCache) AddFunc(fsvc FuncSvc) {
fsc.setFuncAlive(fsvc.Function.Name, string(fsvc.Function.UID), true)
}
// GetTotalAvailable returns the total number active function services.
func (fsc *FunctionServiceCache) GetTotalAvailable(m *metav1.ObjectMeta) int {
return fsc.connFunctionCache.GetTotalAvailable(crd.CacheKey(m))
// SetCPUUtilizaton updates/sets CPUutilization in the pool cache
func (fsc *FunctionServiceCache) SetCPUUtilizaton(key string, svcHost string, cpuUsage resource.Quantity) {
fsc.connFunctionCache.SetCPUUtilization(key, svcHost, cpuUsage)
}
// MarkAvailable marks the value at key [function][address] as available.
@@ -358,6 +359,10 @@ func (fsc *FunctionServiceCache) DeleteFunctionSvc(fsvc *FuncSvc) {
}
}
func (fsc *FunctionServiceCache) SetCPUUtilization(key string, svcHost string, cpuUsage resource.Quantity) {
fsc.connFunctionCache.SetCPUUtilization(key, svcHost, cpuUsage)
}
// DeleteOld deletes aged function service entries from cache.
func (fsc *FunctionServiceCache) DeleteOld(fsvc *FuncSvc, minAge time.Duration) (bool, error) {
if time.Since(fsvc.Atime) < minAge {
@@ -9,6 +9,7 @@ import (
"go.uber.org/zap"
"go.uber.org/zap/zapcore"
apiv1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/api/resource"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
fv1 "github.com/fission/fission/pkg/apis/core/v1"
@@ -171,10 +172,10 @@ func TestFunctionServiceNewCache(t *testing.T) {
},
Address: "xxx",
KubernetesObjects: objects,
CPULimit: resource.MustParse("5m"),
Ctime: now,
Atime: now,
}
fn := &fv1.Function{
ObjectMeta: metav1.ObjectMeta{
Name: "foo",
@@ -183,8 +184,10 @@ func TestFunctionServiceNewCache(t *testing.T) {
}
fsc.AddFunc(*fsvc)
active := fsc.GetTotalAvailable(fsvc.Function)
_, active, err := fsc.GetFuncSvc(fsvc.Function, 5)
if err != nil {
logger.Panic("received error while retrieving value from cache")
}
if active != 1 {
logger.Panic(fmt.Sprintln("active instances not matched expected 1, found ", active))
}
@@ -192,11 +195,7 @@ func TestFunctionServiceNewCache(t *testing.T) {
key := fmt.Sprintf("%v_%v", fn.ObjectMeta.UID, fn.ObjectMeta.ResourceVersion)
fsc.MarkAvailable(key, fsvc.Address)
if fsc.GetTotalAvailable(fsvc.Function) != 0 {
log.Panicln("active instances not matched")
}
_, err = fsc.GetFuncSvc(fsvc.Function)
_, _, err = fsc.GetFuncSvc(fsvc.Function, 5)
if err != nil {
logger.Panic("received error while retrieving value from cache")
}