Go Http Handler is restarting itself during the execution of a command (cmd.Command)
Solution 1:
There's a couple of things of note:
- capturing
stdout
andstderr
seems brittle (error handling from goroutine will not propagate properly) - long running executable may cause request timeout issues
to capture stdout
and stderr
- I'd suggest using something like exec.Cmd.CombinedOutput e.g.
cmd := exec.CommandContext(ctx, "flutter", "build", "appbundle") // see below for ctx details
var sout, serr bytes.Buffer
c.Stdout = &sout
c.Stderr = &serr
err := c.Run()
if err != nil { /* ... */ }
outBody, errBody := string(sout.Bytes()), string(serr.Bytes())
so no need for tricky wait-groups or complex error handling between goroutines.
You need to handle the case where web-requests may take too long. If a request is canceled (by the client or the server) - you need a mechanism in place to cancel the request's sub-tasks (e.g. you externally executed process)
When running any webservice always ensure to leverage context.Context
for the lifetime of a request - especially when running any potentially blocking operations (as you are with exec.Command
).
So first, from your handler, grab the request's context.Context
, and pass this along to any potentially blocking calls:
func (h *HttpServer) GenerateMobileApp(w http.ResponseWriter, r *http.Request) {
...
ctx := r.Context() // context.Context for the lifetime of the request
...
go func() {
apkGeneratedPath, err := h.mobileAPP.GenerateAPK(ctx, project.Id) // <- add ctx
}
}
and update your APK generator signature like so:
func (app *MobileAPP) GenerateAPK(ctx context.Context, projectID string) (string, error)
and to use ctx
when executing an external tool:
//cmd := exec.Command("flutter", "build", "appbundle")
cmd := exec.CommandContext(ctx, "flutter", "build", "appbundle")
with this in place, if the web request is canceled (times out - based on web server settings; or the client disconnects) the process will be terminated.
You can even have special clean-up logic in place for this occurrence, by checking the error from exec.CommandContext
for either context.Canceled
(client disconnected) or context.DeadlineExceeded
(request timed-out).