fiddlecli - Break out fiddle retries into its own library.
Bug: skia:8582
Change-Id: I91d009c97dd796e06028c55f56674a139ddcf42e
Reviewed-on: https://skia-review.googlesource.com/c/177909
Reviewed-by: Ravi Mistry <rmistry@google.com>
Commit-Queue: Ravi Mistry <rmistry@google.com>
Auto-Submit: Joe Gregorio <jcgregorio@google.com>
diff --git a/fiddlek/go/client/client.go b/fiddlek/go/client/client.go
new file mode 100644
index 0000000..00bf42a
--- /dev/null
+++ b/fiddlek/go/client/client.go
@@ -0,0 +1,75 @@
+package client
+
+import (
+ "bytes"
+ "encoding/json"
+ "fmt"
+ "net/http"
+ "time"
+
+ "go.skia.org/infra/fiddlek/go/types"
+ "go.skia.org/infra/go/httputils"
+ "go.skia.org/infra/go/sklog"
+ "go.skia.org/infra/go/util"
+)
+
+const (
+ RETRIES = 10
+)
+
+// singleRequest does a single request to run a fiddle
+//
+// c - HTTP client.
+// body - The body to send to the fiddle /_/run endpoint.
+// domain - The scheme and domain name to make requests to, e.g. "https://fiddle.skia.org".
+// sleep - The duration to sleep if the request fails.
+// failFast - If true then fail fatally.
+func singleRequest(c *http.Client, body []byte, domain string, sleep time.Duration, failFast bool) (*types.RunResults, bool) {
+ resp, err := c.Post(domain+"/_/run", "application/json", bytes.NewReader(body))
+ if err != nil {
+ sklog.Infof("Send error: %s", err)
+ time.Sleep(sleep)
+ return nil, false
+ }
+ defer util.Close(resp.Body)
+ if resp.StatusCode != 200 {
+ if failFast {
+ sklog.Fatalf("Send failed, with fail_fast set: %s", resp.Status)
+ }
+ sklog.Infof("Send failed: %s", resp.Status)
+ time.Sleep(sleep)
+ return nil, false
+ }
+ var runResults types.RunResults
+ if err := json.NewDecoder(resp.Body).Decode(&runResults); err != nil {
+ sklog.Infof("Malformed response: %s", err)
+ time.Sleep(sleep)
+ return nil, false
+ }
+ return &runResults, true
+}
+
+// Do runs a single fiddle contained in 'body'.
+//
+// failFast - If true then fail fatally.
+// domain - The scheme and domain name to make requests to, e.g. "https://fiddle.skia.org".
+// validator - A function that does extra validation on the fiddle run results. Return true if the
+// response is valid.
+func Do(body []byte, failFast bool, domain string, validator func(*types.RunResults) bool) (*types.RunResults, bool) {
+ c := httputils.NewTimeoutClient()
+ success := false
+ sleep := time.Second
+ var runResults *types.RunResults
+ for tries := 0; tries < RETRIES; tries++ {
+ // POST to fiddle.
+ runResults, success = singleRequest(c, body, domain, sleep, failFast)
+ if success {
+ if validator(runResults) {
+ return runResults, success
+ }
+ }
+ sleep *= 2
+ fmt.Print("x")
+ }
+ return nil, false
+}
diff --git a/fiddlek/go/fiddlecli/main.go b/fiddlek/go/fiddlecli/main.go
index 1c6a600..b25d0b7 100644
--- a/fiddlek/go/fiddlecli/main.go
+++ b/fiddlek/go/fiddlecli/main.go
@@ -5,30 +5,24 @@
package main
import (
- "bytes"
"encoding/json"
"flag"
"fmt"
"io/ioutil"
"log"
- "net/http"
"os"
"sync"
- "time"
+ "go.skia.org/infra/fiddlek/go/client"
"go.skia.org/infra/fiddlek/go/types"
"go.skia.org/infra/go/common"
- "go.skia.org/infra/go/httputils"
"go.skia.org/infra/go/sklog"
- "go.skia.org/infra/go/util"
"golang.org/x/sync/errgroup"
)
const (
- RETRIES = 10
-
// VERSION of the application. Update for major and minor changes to functionality.
- VERSION = "1.0"
+ VERSION = "1.1"
)
// flags
@@ -49,33 +43,6 @@
req *types.FiddleContext
}
-// singleRequest does a single request to fiddle.skia.org.
-func singleRequest(c *http.Client, body []byte, domain string) (*types.RunResults, bool) {
- resp, err := c.Post(domain+"/_/run", "application/json", bytes.NewReader(body))
- sleep := time.Second
- if err != nil {
- sklog.Infof("Send error: %s", err)
- time.Sleep(sleep)
- return nil, false
- }
- defer util.Close(resp.Body)
- if resp.StatusCode != 200 {
- if *failFast {
- sklog.Fatalf("Send failed, with fail_fast set: %s", resp.Status)
- }
- sklog.Infof("Send failed: %s", resp.Status)
- time.Sleep(sleep)
- return nil, false
- }
- var runResults types.RunResults
- if err := json.NewDecoder(resp.Body).Decode(&runResults); err != nil {
- sklog.Infof("Malformed response: %s", err)
- time.Sleep(sleep)
- return nil, false
- }
- return &runResults, true
-}
-
func main() {
// Check flags.
common.Init()
@@ -134,30 +101,20 @@
mutex.Unlock()
continue
}
- success := false
- var runResults *types.RunResults
- for tries := 0; tries < RETRIES; tries++ {
- c := httputils.NewTimeoutClient()
- // POST to fiddle.
- b, err = json.Marshal(req.req)
- if err != nil {
- sklog.Errorf("Failed to encode an individual request: %s", err)
- break
- }
- runResults, success = singleRequest(c, b, *domain)
- if success {
- if fiddleHash != runResults.FiddleHash {
- sklog.Warningf("Got mismatched hashes for %s: Want %q != Got %q", req.id, fiddleHash, runResults.FiddleHash)
- } else {
- break
- }
- } else {
- sklog.Warningf("Send failed for: %s", req.id)
- }
- fmt.Print("x")
+ b, err = json.Marshal(req.req)
+ if err != nil {
+ sklog.Errorf("Failed to encode an individual request: %s", err)
+ continue
}
+ runResults, success := client.Do(b, *failFast, *domain, func(runResults *types.RunResults) bool {
+ if fiddleHash != runResults.FiddleHash {
+ sklog.Warningf("Got mismatched hashes for %s: Want %q != Got %q", req.id, fiddleHash, runResults.FiddleHash)
+ return false
+ }
+ return true
+ })
if !success {
- sklog.Errorf("Failed to make request after %d tries", RETRIES)
+ sklog.Errorf("Failed to make request after retries")
continue
}
diff --git a/named-fiddles/go/named-fiddles/main.go b/named-fiddles/go/named-fiddles/main.go
index ae1271a..c8505a3 100644
--- a/named-fiddles/go/named-fiddles/main.go
+++ b/named-fiddles/go/named-fiddles/main.go
@@ -16,6 +16,7 @@
"github.com/gorilla/csrf"
"github.com/gorilla/mux"
"github.com/unrolled/secure"
+ "go.skia.org/infra/fiddlek/go/client"
"go.skia.org/infra/fiddlek/go/store"
"go.skia.org/infra/fiddlek/go/types"
"go.skia.org/infra/go/allowed"
@@ -41,11 +42,6 @@
resourcesDir = flag.String("resources_dir", "", "The directory to find templates, JS, and CSS files. If blank the current directory will be used.")
)
-const (
- // NUM_RETRIES is the number of time to try to run a fiddle before giving up.
- NUM_RETRIES = 5
-)
-
// Server is the state of the server.
type Server struct {
store *store.Store
@@ -103,26 +99,15 @@
}
// Then re-run it.
- var resp *http.Response
- for i := 0; i < NUM_RETRIES; i++ {
- resp, err = c.Post("https://fiddle.skia.org/_/run", "application/json", getResp.Body)
- if err != nil || resp.StatusCode != 200 {
- status := ""
- if resp != nil {
- status = resp.Status
- }
- sklog.Errorf("Failed to run %q: %s %s", n.Name, status, err)
- continue
- }
- break
- }
- if err != nil || resp.StatusCode != 200 {
- srv.errorsInRun.Inc(1)
+ b, err := ioutil.ReadAll(getResp.Body)
+ if err != nil {
+ sklog.Warningf("Failed to read fiddle: %s", err)
return true
}
- var runResults types.RunResults
- if err := json.NewDecoder(resp.Body).Decode(&runResults); err != nil {
- sklog.Errorf("Failed to decode run results: %s", err)
+ runResults, success := client.Do(b, false, "https://fiddle.skia.org", func(*types.RunResults) bool {
+ return true
+ })
+ if success {
srv.errorsInRun.Inc(1)
return true
}