From badcf7863c3153dce402c3b21819e7359652e3c6 Mon Sep 17 00:00:00 2001 From: Alex Ellis Date: Tue, 28 Mar 2017 15:06:48 +0100 Subject: [PATCH 1/2] Add function store idea --- ROADMAP.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/ROADMAP.md b/ROADMAP.md index dd17d561..26c4d8ae 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -37,11 +37,14 @@ This binary fwatchdog acts as a watchdog for your function. Features: ## 2. Future items * Asynchronous / long-running tasks -* Built-in TLS termination or guide for termination through NGinx etc -* Deeper tests coverage and integration tests +* Function store - list of useful predefined functions +* Guide for termination through NGinx or built-in TLS termination +* Guide for basic authentication over HTTPs (set up externally through NGinx etc) * Documentation about Alexa sample function * Supporting request parameters +* Deeper tests coverage and integration tests + ## 3. Development and Contributing If you would like to consume the project with your own functions then you can use the public images and the supplied `docker stack` file as a template (docker-compose.yml) From c2eb41ee4f1ffba64193e585ecadffbee8e1e119 Mon Sep 17 00:00:00 2001 From: Alex Ellis Date: Tue, 28 Mar 2017 19:05:33 +0100 Subject: [PATCH 2/2] Fix buffer dead-lock in Watchdog (#33) * Go sync group to handle blocking on buffered-pipes --- watchdog/main.go | 86 +++++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 33 deletions(-) diff --git a/watchdog/main.go b/watchdog/main.go index a2c0598a..da69c2fb 100644 --- a/watchdog/main.go +++ b/watchdog/main.go @@ -8,6 +8,7 @@ import ( "os" "os/exec" "strings" + "sync" "time" ) @@ -20,42 +21,61 @@ func (OsEnv) Getenv(key string) string { return os.Getenv(key) } +func pipeRequest(config *WatchdogConfig, w http.ResponseWriter, r *http.Request) { + parts := strings.Split(config.faasProcess, " ") + + targetCmd := exec.Command(parts[0], parts[1:]...) + writer, _ := targetCmd.StdinPipe() + + var out []byte + var err error + var res []byte + + var wg sync.WaitGroup + wg.Add(2) + + res, _ = ioutil.ReadAll(r.Body) + defer r.Body.Close() + + go func() { + defer wg.Done() + writer.Write(res) + writer.Close() + }() + + go func() { + defer wg.Done() + out, err = targetCmd.CombinedOutput() + }() + + wg.Wait() + + if err != nil { + if config.writeDebug == true { + log.Println(targetCmd, err) + } + + w.WriteHeader(500) + response := bytes.NewBufferString(err.Error()) + w.Write(response.Bytes()) + return + } + if config.writeDebug == true { + os.Stdout.Write(out) + } + + // Match header for strict services + if r.Header.Get("Content-Type") == "application/json" { + w.Header().Set("Content-Type", "application/json") + } + w.WriteHeader(200) + w.Write(out) +} + func makeRequestHandler(config *WatchdogConfig) func(http.ResponseWriter, *http.Request) { return func(w http.ResponseWriter, r *http.Request) { if r.Method == "POST" { - parts := strings.Split(config.faasProcess, " ") - - targetCmd := exec.Command(parts[0], parts[1:]...) - writer, _ := targetCmd.StdinPipe() - - res, _ := ioutil.ReadAll(r.Body) - defer r.Body.Close() - - writer.Write(res) - writer.Close() - - out, err := targetCmd.CombinedOutput() - - if err != nil { - if config.writeDebug == true { - log.Println(targetCmd, err) - } - - w.WriteHeader(500) - response := bytes.NewBufferString(err.Error()) - w.Write(response.Bytes()) - return - } - if config.writeDebug == true { - os.Stdout.Write(out) - } - - // Match header for strict services - if r.Header.Get("Content-Type") == "application/json" { - w.Header().Set("Content-Type", "application/json") - } - w.WriteHeader(200) - w.Write(out) + pipeRequest(config, w, r) } else { w.WriteHeader(http.StatusMethodNotAllowed) }