mirror of
https://github.com/fnproject/fn.git
synced 2022-10-28 21:29:17 +03:00
fn: I/O related improvements (#809)
*) I/O protocol parse issues should shutdown the container as the container goes to inconsistent state between calls. (eg. next call may receive previous calls left overs.) *) Move ghost read/write code into io_utils in common. *) Clean unused error from docker Wait() *) We can catch one case in JSON, if there's remaining unparsed data in decoder buffer, we can shut the container *) stdout/stderr when container is not handling a request are now blocked if freezer is also enabled. *) if a fatal err is set for slot, we do not requeue it and proceed to shutdown *) added a test function for a few cases with freezer strict behavior
This commit is contained in:
@@ -54,6 +54,12 @@ type AppRequest struct {
|
||||
TrailerRepeat int `json:"trailerRepeat,omitempty"`
|
||||
// corrupt http or json
|
||||
InvalidResponse bool `json:"invalidResponse,omitempty"`
|
||||
// if specified we 'sleep' the specified msecs *after* processing request
|
||||
PostSleepTime int `json:"postSleepTime,omitempty"`
|
||||
// spit this out in stdout after processing each request
|
||||
PostOutGarbage string `json:"postOutGarbage,omitempty"`
|
||||
// spit this out in stderr after processing each request
|
||||
PostErrGarbage string `json:"postErrGarbage,omitempty"`
|
||||
// TODO: simulate slow read/slow write
|
||||
// TODO: simulate partial IO write/read
|
||||
// TODO: simulate high cpu usage (async and sync)
|
||||
@@ -101,6 +107,10 @@ func AppHandler(ctx context.Context, in io.Reader, out io.Writer) {
|
||||
var outto fdkresponse
|
||||
outto.Writer = out
|
||||
finalizeRequest(&outto, req, resp)
|
||||
err := postProcessRequest(req, out)
|
||||
if err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
}
|
||||
|
||||
func finalizeRequest(out *fdkresponse, req *AppRequest, resp *AppResponse) {
|
||||
@@ -222,6 +232,37 @@ func processRequest(ctx context.Context, in io.Reader) (*AppRequest, *AppRespons
|
||||
return &request, &resp
|
||||
}
|
||||
|
||||
func postProcessRequest(request *AppRequest, out io.Writer) error {
|
||||
if request == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
if request.PostSleepTime > 0 {
|
||||
if request.IsDebug {
|
||||
log.Printf("PostProcess Sleeping %d", request.PostSleepTime)
|
||||
}
|
||||
time.Sleep(time.Duration(request.PostSleepTime) * time.Millisecond)
|
||||
}
|
||||
|
||||
if request.PostOutGarbage != "" {
|
||||
if request.IsDebug {
|
||||
log.Printf("PostProcess PostOutGarbage %s", request.PostOutGarbage)
|
||||
}
|
||||
|
||||
_, err := io.WriteString(out, request.PostOutGarbage)
|
||||
if err != nil {
|
||||
log.Printf("PostOutGarbage write string error %v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if request.PostErrGarbage != "" {
|
||||
log.Printf("PostProcess PostErrGarbage %s", request.PostErrGarbage)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func main() {
|
||||
if os.Getenv("ENABLE_HEADER") != "" {
|
||||
log.Printf("Container starting")
|
||||
@@ -287,6 +328,7 @@ func testDoJSONOnce(ctx context.Context, in io.Reader, out io.Writer, buf *bytes
|
||||
resp.Header = hdr
|
||||
|
||||
var jsonRequest fdkutils.JsonIn
|
||||
var appRequest *AppRequest
|
||||
err := json.NewDecoder(in).Decode(&jsonRequest)
|
||||
if err != nil {
|
||||
// stdin now closed
|
||||
@@ -295,7 +337,11 @@ func testDoJSONOnce(ctx context.Context, in io.Reader, out io.Writer, buf *bytes
|
||||
return err
|
||||
}
|
||||
resp.Status = http.StatusInternalServerError
|
||||
io.WriteString(resp, fmt.Sprintf(`{"error": %v}`, err.Error()))
|
||||
_, err = io.WriteString(resp, fmt.Sprintf(`{"error": %v}`, err.Error()))
|
||||
if err != nil {
|
||||
log.Printf("json write string error %v", err)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
fdkutils.SetHeaders(ctx, jsonRequest.Protocol.Headers)
|
||||
ctx, cancel := fdkutils.CtxWithDeadline(ctx, jsonRequest.Deadline)
|
||||
@@ -308,6 +354,7 @@ func testDoJSONOnce(ctx context.Context, in io.Reader, out io.Writer, buf *bytes
|
||||
io.Copy(out, strings.NewReader(InvalidResponseStr))
|
||||
}
|
||||
|
||||
appRequest = appReq
|
||||
}
|
||||
|
||||
jsonResponse := getJSONResp(buf, &resp, &jsonRequest)
|
||||
@@ -324,7 +371,7 @@ func testDoJSONOnce(ctx context.Context, in io.Reader, out io.Writer, buf *bytes
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return postProcessRequest(appRequest, out)
|
||||
}
|
||||
|
||||
// since we need to test little jason's content type since he's special. but we
|
||||
@@ -355,6 +402,7 @@ func testDoHTTPOnce(ctx context.Context, in io.Reader, out io.Writer, buf *bytes
|
||||
resp.Status = 200
|
||||
resp.Header = hdr
|
||||
|
||||
var appRequest *AppRequest
|
||||
req, err := http.ReadRequest(bufio.NewReader(in))
|
||||
if err != nil {
|
||||
// stdin now closed
|
||||
@@ -364,7 +412,11 @@ func testDoHTTPOnce(ctx context.Context, in io.Reader, out io.Writer, buf *bytes
|
||||
}
|
||||
// TODO it would be nice if we could let the user format this response to their preferred style..
|
||||
resp.Status = http.StatusInternalServerError
|
||||
io.WriteString(resp, err.Error())
|
||||
_, err = io.WriteString(resp, err.Error())
|
||||
if err != nil {
|
||||
log.Printf("http write string error %v", err)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
fnDeadline := fdkutils.Context(ctx).Header.Get("FN_DEADLINE")
|
||||
ctx, cancel := fdkutils.CtxWithDeadline(ctx, fnDeadline)
|
||||
@@ -378,6 +430,7 @@ func testDoHTTPOnce(ctx context.Context, in io.Reader, out io.Writer, buf *bytes
|
||||
io.Copy(out, strings.NewReader(InvalidResponseStr))
|
||||
}
|
||||
|
||||
appRequest = appReq
|
||||
}
|
||||
|
||||
hResp := fdkutils.GetHTTPResp(buf, &resp.Response, req)
|
||||
@@ -388,7 +441,7 @@ func testDoHTTPOnce(ctx context.Context, in io.Reader, out io.Writer, buf *bytes
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
return postProcessRequest(appRequest, out)
|
||||
}
|
||||
|
||||
func getChunk(size int) []byte {
|
||||
|
||||
Reference in New Issue
Block a user