Round Tripper of Fission Router: parameters be configurable (#713)
The Round Tripper parameters of timeout, keep alive time and Max retry times is configured in router system environment. And they are set to Round Tripper when router service initializing. This setup new nested structure `tsRoundTripperParams` to transfer them.
This commit is contained in:
@@ -175,6 +175,14 @@ spec:
|
|||||||
valueFrom:
|
valueFrom:
|
||||||
fieldRef:
|
fieldRef:
|
||||||
fieldPath: metadata.namespace
|
fieldPath: metadata.namespace
|
||||||
|
- name: ROUTER_ROUND_TRIP_TIMEOUT
|
||||||
|
value: {{ .Values.routerRoundTripTimeout | default "50ms" | quote }}
|
||||||
|
- name: ROUTER_ROUNDTRIP_TIMEOUT_EXPONENT
|
||||||
|
value: {{ .Values.routerRoundTripTimeoutExponent | default 2 | quote }}
|
||||||
|
- name: ROUTER_ROUND_TRIP_KEEP_ALIVE_TIME
|
||||||
|
value: {{ .Values.routerRoundTripKeepAliveTime | default "30s" | quote }}
|
||||||
|
- name: ROUTER_ROUND_TRIP_MAX_RETRIES
|
||||||
|
value: {{ .Values.routerRoundTripMaxRetries | default 10 | quote }}
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: "/router-healthz"
|
path: "/router-healthz"
|
||||||
|
|||||||
@@ -172,6 +172,14 @@ spec:
|
|||||||
valueFrom:
|
valueFrom:
|
||||||
fieldRef:
|
fieldRef:
|
||||||
fieldPath: metadata.namespace
|
fieldPath: metadata.namespace
|
||||||
|
- name: ROUTER_ROUND_TRIP_TIMEOUT
|
||||||
|
value: {{ .Values.routerRoundTripTimeout | default "50ms" | quote }}
|
||||||
|
- name: ROUTER_ROUNDTRIP_TIMEOUT_EXPONENT
|
||||||
|
value: {{ .Values.routerRoundTripTimeoutExponent | default 2 | quote }}
|
||||||
|
- name: ROUTER_ROUND_TRIP_KEEP_ALIVE_TIME
|
||||||
|
value: {{ .Values.routerRoundTripKeepAliveTime | default "30s" | quote }}
|
||||||
|
- name: ROUTER_ROUND_TRIP_MAX_RETRIES
|
||||||
|
value: {{ .Values.routerRoundTripMaxRetries | default 10 | quote }}
|
||||||
readinessProbe:
|
readinessProbe:
|
||||||
httpGet:
|
httpGet:
|
||||||
path: "/router-healthz"
|
path: "/router-healthz"
|
||||||
|
|||||||
+24
-17
@@ -33,18 +33,24 @@ import (
|
|||||||
executorClient "github.com/fission/fission/executor/client"
|
executorClient "github.com/fission/fission/executor/client"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type tsRoundTripperParams struct {
|
||||||
|
timeout time.Duration
|
||||||
|
timeoutExponent int
|
||||||
|
keepAlive time.Duration
|
||||||
|
maxRetries int
|
||||||
|
}
|
||||||
|
|
||||||
type functionHandler struct {
|
type functionHandler struct {
|
||||||
fmap *functionServiceMap
|
fmap *functionServiceMap
|
||||||
executor *executorClient.Client
|
executor *executorClient.Client
|
||||||
function *metav1.ObjectMeta
|
function *metav1.ObjectMeta
|
||||||
httpTrigger *crd.HTTPTrigger
|
httpTrigger *crd.HTTPTrigger
|
||||||
|
tsRoundTripperParams *tsRoundTripperParams
|
||||||
}
|
}
|
||||||
|
|
||||||
// A layer on top of http.DefaultTransport, with retries.
|
// A layer on top of http.DefaultTransport, with retries.
|
||||||
type RetryingRoundTripper struct {
|
type RetryingRoundTripper struct {
|
||||||
maxRetries int
|
funcHandler *functionHandler
|
||||||
initialTimeout time.Duration
|
|
||||||
funcHandler *functionHandler
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RoundTrip is a custom transport with retries for http requests that forwards the request to the right serviceUrl, obtained
|
// RoundTrip is a custom transport with retries for http requests that forwards the request to the right serviceUrl, obtained
|
||||||
@@ -92,7 +98,6 @@ func (roundTripper RetryingRoundTripper) RoundTrip(req *http.Request) (resp *htt
|
|||||||
}
|
}
|
||||||
|
|
||||||
// set the timeout for transport context
|
// set the timeout for transport context
|
||||||
timeout := roundTripper.initialTimeout
|
|
||||||
transport := http.DefaultTransport.(*http.Transport)
|
transport := http.DefaultTransport.(*http.Transport)
|
||||||
// Disables caching, Please refer to issue and specifically comment: https://github.com/fission/fission/issues/723#issuecomment-398781995
|
// Disables caching, Please refer to issue and specifically comment: https://github.com/fission/fission/issues/723#issuecomment-398781995
|
||||||
transport.DisableKeepAlives = true
|
transport.DisableKeepAlives = true
|
||||||
@@ -104,7 +109,9 @@ func (roundTripper RetryingRoundTripper) RoundTrip(req *http.Request) (resp *htt
|
|||||||
needExecutor = true
|
needExecutor = true
|
||||||
}
|
}
|
||||||
|
|
||||||
for i := 0; i < roundTripper.maxRetries-1; i++ {
|
executingTimeout := roundTripper.funcHandler.tsRoundTripperParams.timeout
|
||||||
|
|
||||||
|
for i := 0; i < roundTripper.funcHandler.tsRoundTripperParams.maxRetries-1; i++ {
|
||||||
if needExecutor {
|
if needExecutor {
|
||||||
log.Printf("Calling getServiceForFunction for function: %s", roundTripper.funcHandler.function.Name)
|
log.Printf("Calling getServiceForFunction for function: %s", roundTripper.funcHandler.function.Name)
|
||||||
|
|
||||||
@@ -149,8 +156,8 @@ func (roundTripper RetryingRoundTripper) RoundTrip(req *http.Request) (resp *htt
|
|||||||
|
|
||||||
// over-riding default settings.
|
// over-riding default settings.
|
||||||
transport.DialContext = (&net.Dialer{
|
transport.DialContext = (&net.Dialer{
|
||||||
Timeout: timeout,
|
Timeout: executingTimeout,
|
||||||
KeepAlive: 30 * time.Second,
|
KeepAlive: roundTripper.funcHandler.tsRoundTripperParams.keepAlive,
|
||||||
}).DialContext
|
}).DialContext
|
||||||
|
|
||||||
overhead := time.Since(startTime)
|
overhead := time.Since(startTime)
|
||||||
@@ -183,9 +190,11 @@ func (roundTripper RetryingRoundTripper) RoundTrip(req *http.Request) (resp *htt
|
|||||||
// just retry after backing off for timeout period.
|
// just retry after backing off for timeout period.
|
||||||
if serviceUrlFromExecutor {
|
if serviceUrlFromExecutor {
|
||||||
log.Printf("request to %s errored out. backing off for %v before retrying",
|
log.Printf("request to %s errored out. backing off for %v before retrying",
|
||||||
req.URL.Host, timeout)
|
req.URL.Host, executingTimeout)
|
||||||
timeout *= time.Duration(2)
|
|
||||||
time.Sleep(timeout)
|
executingTimeout = executingTimeout * time.Duration(roundTripper.funcHandler.tsRoundTripperParams.timeoutExponent)
|
||||||
|
time.Sleep(executingTimeout)
|
||||||
|
|
||||||
needExecutor = false
|
needExecutor = false
|
||||||
continue
|
continue
|
||||||
} else {
|
} else {
|
||||||
@@ -231,9 +240,7 @@ func (fh *functionHandler) handler(responseWriter http.ResponseWriter, request *
|
|||||||
proxy := &httputil.ReverseProxy{
|
proxy := &httputil.ReverseProxy{
|
||||||
Director: director,
|
Director: director,
|
||||||
Transport: &RetryingRoundTripper{
|
Transport: &RetryingRoundTripper{
|
||||||
initialTimeout: 50 * time.Millisecond,
|
funcHandler: fh,
|
||||||
maxRetries: 10,
|
|
||||||
funcHandler: fh,
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
"net/http/httptest"
|
"net/http/httptest"
|
||||||
"net/url"
|
"net/url"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
)
|
)
|
||||||
@@ -56,6 +57,12 @@ func TestFunctionProxying(t *testing.T) {
|
|||||||
|
|
||||||
fh := &functionHandler{fmap: fmap,
|
fh := &functionHandler{fmap: fmap,
|
||||||
function: fn,
|
function: fn,
|
||||||
|
tsRoundTripperParams: &tsRoundTripperParams{
|
||||||
|
timeout: 50 * time.Millisecond,
|
||||||
|
timeoutExponent: 2,
|
||||||
|
keepAlive: 30 * time.Second,
|
||||||
|
maxRetries: 10,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
functionHandlerServer := httptest.NewServer(http.HandlerFunc(fh.handler))
|
functionHandlerServer := httptest.NewServer(http.HandlerFunc(fh.handler))
|
||||||
fhURL := functionHandlerServer.URL
|
fhURL := functionHandlerServer.URL
|
||||||
|
|||||||
+19
-14
@@ -49,17 +49,20 @@ type HTTPTriggerSet struct {
|
|||||||
functions []crd.Function
|
functions []crd.Function
|
||||||
funcStore k8sCache.Store
|
funcStore k8sCache.Store
|
||||||
funcController k8sCache.Controller
|
funcController k8sCache.Controller
|
||||||
|
|
||||||
|
tsRoundTripperParams *tsRoundTripperParams
|
||||||
}
|
}
|
||||||
|
|
||||||
func makeHTTPTriggerSet(fmap *functionServiceMap, fissionClient *crd.FissionClient,
|
func makeHTTPTriggerSet(fmap *functionServiceMap, fissionClient *crd.FissionClient,
|
||||||
kubeClient *kubernetes.Clientset, executor *executorClient.Client, crdClient *rest.RESTClient) (*HTTPTriggerSet, k8sCache.Store, k8sCache.Store) {
|
kubeClient *kubernetes.Clientset, executor *executorClient.Client, crdClient *rest.RESTClient, params *tsRoundTripperParams) (*HTTPTriggerSet, k8sCache.Store, k8sCache.Store) {
|
||||||
httpTriggerSet := &HTTPTriggerSet{
|
httpTriggerSet := &HTTPTriggerSet{
|
||||||
functionServiceMap: fmap,
|
functionServiceMap: fmap,
|
||||||
triggers: []crd.HTTPTrigger{},
|
triggers: []crd.HTTPTrigger{},
|
||||||
fissionClient: fissionClient,
|
fissionClient: fissionClient,
|
||||||
kubeClient: kubeClient,
|
kubeClient: kubeClient,
|
||||||
executor: executor,
|
executor: executor,
|
||||||
crdClient: crdClient,
|
crdClient: crdClient,
|
||||||
|
tsRoundTripperParams: params,
|
||||||
}
|
}
|
||||||
var tStore, fnStore k8sCache.Store
|
var tStore, fnStore k8sCache.Store
|
||||||
var tController, fnController k8sCache.Controller
|
var tController, fnController k8sCache.Controller
|
||||||
@@ -121,10 +124,11 @@ func (ts *HTTPTriggerSet) getRouter() *mux.Router {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fh := &functionHandler{
|
fh := &functionHandler{
|
||||||
fmap: ts.functionServiceMap,
|
fmap: ts.functionServiceMap,
|
||||||
function: rr.functionMetadata,
|
function: rr.functionMetadata,
|
||||||
executor: ts.executor,
|
executor: ts.executor,
|
||||||
httpTrigger: &trigger,
|
httpTrigger: &trigger,
|
||||||
|
tsRoundTripperParams: ts.tsRoundTripperParams,
|
||||||
}
|
}
|
||||||
|
|
||||||
ht := muxRouter.HandleFunc(trigger.Spec.RelativeURL, fh.handler)
|
ht := muxRouter.HandleFunc(trigger.Spec.RelativeURL, fh.handler)
|
||||||
@@ -152,9 +156,10 @@ func (ts *HTTPTriggerSet) getRouter() *mux.Router {
|
|||||||
for _, function := range ts.functions {
|
for _, function := range ts.functions {
|
||||||
m := function.Metadata
|
m := function.Metadata
|
||||||
fh := &functionHandler{
|
fh := &functionHandler{
|
||||||
fmap: ts.functionServiceMap,
|
fmap: ts.functionServiceMap,
|
||||||
function: &m,
|
function: &m,
|
||||||
executor: ts.executor,
|
executor: ts.executor,
|
||||||
|
tsRoundTripperParams: ts.tsRoundTripperParams,
|
||||||
}
|
}
|
||||||
muxRouter.HandleFunc(fission.UrlForFunction(function.Metadata.Name, function.Metadata.Namespace), fh.handler)
|
muxRouter.HandleFunc(fission.UrlForFunction(function.Metadata.Name, function.Metadata.Namespace), fh.handler)
|
||||||
}
|
}
|
||||||
|
|||||||
+30
-1
@@ -44,6 +44,8 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"strconv"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
@@ -97,7 +99,34 @@ func Start(port int, executorUrl string) {
|
|||||||
restClient := fissionClient.GetCrdClient()
|
restClient := fissionClient.GetCrdClient()
|
||||||
|
|
||||||
executor := executorClient.MakeClient(executorUrl)
|
executor := executorClient.MakeClient(executorUrl)
|
||||||
triggers, _, fnStore := makeHTTPTriggerSet(fmap, fissionClient, kubeClient, executor, restClient)
|
|
||||||
|
timeout, err := time.ParseDuration(os.Getenv("ROUTER_ROUND_TRIP_TIMEOUT"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to parse timeout: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
timeoutExponent, err := strconv.Atoi(os.Getenv("ROUTER_ROUNDTRIP_TIMEOUT_EXPONENT"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to parse timeout exponent: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
keepAlive, err := time.ParseDuration(os.Getenv("ROUTER_ROUND_TRIP_KEEP_ALIVE_TIME"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to parse keep alive time: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
maxRetries, err := strconv.Atoi(os.Getenv("ROUTER_ROUND_TRIP_MAX_RETRIES"))
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to parse max retry times: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
triggers, _, fnStore := makeHTTPTriggerSet(fmap, fissionClient, kubeClient, executor, restClient,
|
||||||
|
&tsRoundTripperParams{
|
||||||
|
timeout: timeout,
|
||||||
|
timeoutExponent: timeoutExponent,
|
||||||
|
keepAlive: keepAlive,
|
||||||
|
maxRetries: maxRetries,
|
||||||
|
})
|
||||||
resolver := makeFunctionReferenceResolver(fnStore)
|
resolver := makeFunctionReferenceResolver(fnStore)
|
||||||
|
|
||||||
go serveMetric()
|
go serveMetric()
|
||||||
|
|||||||
@@ -59,7 +59,13 @@ func TestRouter(t *testing.T) {
|
|||||||
frr.refCache.Set(nfr, rr)
|
frr.refCache.Set(nfr, rr)
|
||||||
|
|
||||||
// HTTP trigger set with a trigger for this function
|
// HTTP trigger set with a trigger for this function
|
||||||
triggers, _, _ := makeHTTPTriggerSet(fmap, nil, nil, nil, nil)
|
triggers, _, _ := makeHTTPTriggerSet(fmap, nil, nil, nil, nil,
|
||||||
|
&tsRoundTripperParams{
|
||||||
|
timeout: 50 * time.Millisecond,
|
||||||
|
timeoutExponent: 2,
|
||||||
|
keepAlive: 30 * time.Second,
|
||||||
|
maxRetries: 10,
|
||||||
|
})
|
||||||
triggerUrl := "/foo"
|
triggerUrl := "/foo"
|
||||||
triggers.triggers = append(triggers.triggers,
|
triggers.triggers = append(triggers.triggers,
|
||||||
crd.HTTPTrigger{
|
crd.HTTPTrigger{
|
||||||
|
|||||||
Reference in New Issue
Block a user