internal/relui: record resume errors on workflows

When a workflow fails to resume from an error, record the error on the
workflow and mark it as finished. This typically happens when resuming a
task for an un-resumable workflow, either because the definition changed
or is missing.

With this change, the retryTaskHandler can simply redirect, as the user
will see the error on the workflow itself.

Change-Id: I934dc8b24983716820a3b19160052b173d3b519e
Reviewed-on: https://go-review.googlesource.com/c/build/+/412134
Run-TryBot: Alex Rakoczy <alex@golang.org>
Reviewed-by: Dmitri Shuralyov <dmitshur@google.com>
Reviewed-by: Dmitri Shuralyov <dmitshur@golang.org>
Reviewed-by: Heschi Kreinick <heschi@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
diff --git a/internal/relui/web.go b/internal/relui/web.go
index 6b6a6b6..c6acad4 100644
--- a/internal/relui/web.go
+++ b/internal/relui/web.go
@@ -273,8 +273,6 @@
 	}
 	if err := s.w.Resume(r.Context(), id); err != nil {
 		log.Printf("s.w.Resume(_, %q): %v", id, err)
-		http.Error(w, http.StatusText(http.StatusInternalServerError), http.StatusInternalServerError)
-		return
 	}
 	http.Redirect(w, r, s.BaseLink("/"), http.StatusSeeOther)
 }
diff --git a/internal/relui/worker.go b/internal/relui/worker.go
index e8f77a3..4a82902 100644
--- a/internal/relui/worker.go
+++ b/internal/relui/worker.go
@@ -180,11 +180,15 @@
 	}
 	d := w.dh.Definition(wf.Name.String)
 	if d == nil {
-		return fmt.Errorf("no workflow named %q", wf.Name.String)
+		err := fmt.Errorf("no workflow named %q", wf.Name.String)
+		w.l.WorkflowFinished(ctx, wf.ID, nil, err)
+		return err
 	}
 	state := &workflow.WorkflowState{ID: wf.ID}
 	if err := json.Unmarshal([]byte(wf.Params.String), &state.Params); err != nil {
-		return fmt.Errorf("unmarshalling params for %q: %w", id, err)
+		err := fmt.Errorf("unmarshalling params for %q: %w", id, err)
+		w.l.WorkflowFinished(ctx, wf.ID, nil, err)
+		return err
 	}
 	taskStates := make(map[string]*workflow.TaskState)
 	for _, t := range tasks {
@@ -199,6 +203,7 @@
 	}
 	res, err := workflow.Resume(d, state, taskStates)
 	if err != nil {
+		w.l.WorkflowFinished(ctx, wf.ID, nil, err)
 		return err
 	}
 	return w.run(res)