mirror of
https://github.com/openfaas/faas.git
synced 2025-06-09 16:56:47 +00:00
During some exploratory testing, I ran into an issue where the gateway would attempt to scale a deployment from zero replicas to min, despite there already being min replicas. Why? The scaling logic was looking for Available replicas when it should have looked for Desired replicas. So when a deployment had zero ready replicas due to readiness checks failing, the gateway was attempting to scale from zero to min. This logic has been corrected and separated from the a holding pattern where the gateway waits for a ready replica. Tested with KinD and an edited function which had a readiness probe, which was failing and no ready replicas. As desired, the gateway did not scale to min. However, when setting desired replicas to zero, the gateway did scale up as expected. This change also modifies all print statements for "seconds" and makes them use 4 decimal places instead of the default which was a longer, more verbose string for the logs. Signed-off-by: Alex Ellis (OpenFaaS Ltd) <alexellis2@gmail.com>
55 lines
1.6 KiB
Go
55 lines
1.6 KiB
Go
// Copyright (c) OpenFaaS Author(s). 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"
|
|
|
|
"github.com/openfaas/faas/gateway/pkg/middleware"
|
|
"github.com/openfaas/faas/gateway/scaling"
|
|
)
|
|
|
|
// MakeScalingHandler creates handler which can scale a function from
|
|
// zero to N replica(s). After scaling the next http.HandlerFunc will
|
|
// be called. If the function is not ready after the configured
|
|
// amount of attempts / queries then next will not be invoked and a status
|
|
// will be returned to the client.
|
|
func MakeScalingHandler(next http.HandlerFunc, scaler scaling.FunctionScaler, config scaling.ScalingConfig, defaultNamespace string) http.HandlerFunc {
|
|
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
functionName, namespace := middleware.GetNamespace(defaultNamespace, middleware.GetServiceName(r.URL.String()))
|
|
|
|
res := scaler.Scale(functionName, namespace)
|
|
|
|
if !res.Found {
|
|
errStr := fmt.Sprintf("error finding function %s.%s: %s", functionName, namespace, res.Error.Error())
|
|
log.Printf("Scaling: %s\n", errStr)
|
|
|
|
w.WriteHeader(http.StatusNotFound)
|
|
w.Write([]byte(errStr))
|
|
return
|
|
}
|
|
|
|
if res.Error != nil {
|
|
errStr := fmt.Sprintf("error finding function %s.%s: %s", functionName, namespace, res.Error.Error())
|
|
log.Printf("Scaling: %s\n", errStr)
|
|
|
|
w.WriteHeader(http.StatusInternalServerError)
|
|
w.Write([]byte(errStr))
|
|
return
|
|
}
|
|
|
|
if res.Available {
|
|
next.ServeHTTP(w, r)
|
|
return
|
|
}
|
|
|
|
log.Printf("[Scale] function=%s.%s 0=>N timed-out after %.4fs\n",
|
|
functionName, namespace, res.Duration.Seconds())
|
|
}
|
|
}
|