mirror of
https://github.com/openfaas/faas.git
synced 2025-06-09 00:36:46 +00:00
Existing code has been used for scaling up and querying replicas. This meant the new code was deleted and there is less duplication now. The cache store a whole query response rather than just the available replica count and the tests were updated. This has been tested with Docker swarm and the image: openfaas/gateway:scale-17-07-2018 This feature now needs the env-var of scale_from_zero to be enabled in order to turn on the scaling behaviour. Signed-off-by: Alex Ellis (VMware) <alexellis2@gmail.com>
91 lines
2.3 KiB
Go
91 lines
2.3 KiB
Go
// Copyright (c) OpenFaaS Project. All rights reserved.
|
|
// Licensed under the MIT license. See LICENSE file in the project root for full license information.
|
|
|
|
package handlers
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"net/http"
|
|
"time"
|
|
)
|
|
|
|
// ScalingConfig for scaling behaviours
|
|
type ScalingConfig struct {
|
|
MaxPollCount uint
|
|
FunctionPollInterval time.Duration
|
|
CacheExpiry time.Duration
|
|
ServiceQuery ServiceQuery
|
|
}
|
|
|
|
// MakeScalingHandler creates handler which can scale a function from
|
|
// zero to 1 replica(s).
|
|
func MakeScalingHandler(next http.HandlerFunc, upstream http.HandlerFunc, config ScalingConfig) http.HandlerFunc {
|
|
cache := FunctionCache{
|
|
Cache: make(map[string]*FunctionMeta),
|
|
Expiry: config.CacheExpiry,
|
|
}
|
|
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
functionName := getServiceName(r.URL.String())
|
|
|
|
if serviceQueryResponse, hit := cache.Get(functionName); hit && serviceQueryResponse.AvailableReplicas > 0 {
|
|
next.ServeHTTP(w, r)
|
|
return
|
|
}
|
|
|
|
queryResponse, err := config.ServiceQuery.GetReplicas(functionName)
|
|
cache.Set(functionName, queryResponse)
|
|
|
|
if err != nil {
|
|
var errStr string
|
|
errStr = fmt.Sprintf("error finding function %s: %s", functionName, err.Error())
|
|
|
|
log.Printf(errStr)
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
w.Write([]byte(errStr))
|
|
return
|
|
}
|
|
|
|
if queryResponse.AvailableReplicas == 0 {
|
|
minReplicas := uint64(1)
|
|
if queryResponse.MinReplicas > 0 {
|
|
minReplicas = queryResponse.MinReplicas
|
|
}
|
|
|
|
err := config.ServiceQuery.SetReplicas(functionName, minReplicas)
|
|
if err != nil {
|
|
errStr := fmt.Errorf("unable to scale function [%s], err: %s", functionName, err)
|
|
log.Printf(errStr.Error())
|
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
w.Write([]byte(errStr.Error()))
|
|
return
|
|
}
|
|
|
|
for i := 0; i < int(config.MaxPollCount); i++ {
|
|
queryResponse, err := config.ServiceQuery.GetReplicas(functionName)
|
|
cache.Set(functionName, queryResponse)
|
|
|
|
if err != nil {
|
|
errStr := fmt.Sprintf("error: %s", err.Error())
|
|
log.Printf(errStr)
|
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
w.Write([]byte(errStr))
|
|
return
|
|
}
|
|
|
|
if queryResponse.AvailableReplicas > 0 {
|
|
break
|
|
}
|
|
|
|
time.Sleep(config.FunctionPollInterval)
|
|
}
|
|
}
|
|
|
|
next.ServeHTTP(w, r)
|
|
}
|
|
}
|