Skip to content

Commit

Permalink
Update retry proxy to include a recursive constructor
Browse files Browse the repository at this point in the history
  • Loading branch information
nstogner committed Jan 18, 2024
1 parent 363aaa0 commit e0c3dbc
Show file tree
Hide file tree
Showing 2 changed files with 50 additions and 28 deletions.
6 changes: 5 additions & 1 deletion hack/failonceserver/main.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package main

import (
"io"
"net/http"
"os"
"sync"
)

Expand All @@ -10,7 +12,9 @@ func main() {
var mtx sync.RWMutex
paths := map[string]bool{}

http.ListenAndServe(":8080", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
http.ListenAndServe(":8082", http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
io.Copy(os.Stdout, r.Body)

mtx.RLock()
shouldSucceed := paths[r.URL.Path]
mtx.RUnlock()
Expand Down
72 changes: 45 additions & 27 deletions hack/retryproxy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,32 +18,9 @@ func main() {
}
r.Body.Close()

// go run ./hack/failserver
first := newReverseProxy("http://localhost:8081")

first.ModifyResponse = func(r *http.Response) error {
if r.StatusCode == http.StatusServiceUnavailable {
// Returning an error will trigger the ErrorHandler.
return errRetry
}
return nil
}

first.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
if err == errRetry {
log.Println("retrying")

// Simulate calling the next backend.
// go run ./hack/successserver
next := newReverseProxy("http://localhost:8082")
next.ServeHTTP(w, newReq(r, body))
return
}
}

log.Println("serving")
first.ServeHTTP(w, newReq(r, body))
backend(r, body, 0).ServeHTTP(w, newReq(r, body))
}))

}

var errRetry = errors.New("retry")
Expand All @@ -54,8 +31,49 @@ func newReq(r *http.Request, body []byte) *http.Request {
return clone
}

func newReverseProxy(addr string) *httputil.ReverseProxy {
u, err := url.Parse(addr)
type backends struct {
attempt int
requestBody []byte
}

func backend(r *http.Request, body []byte, attempt int) http.Handler {
// go run ./hack/failserver
first := newReverseProxy(getEndpoint(attempt))

first.ModifyResponse = func(r *http.Response) error {
if r.StatusCode == http.StatusServiceUnavailable {
// Returning an error will trigger the ErrorHandler.
return errRetry
}
return nil
}

first.ErrorHandler = func(w http.ResponseWriter, r *http.Request, err error) {
if err == errRetry {
log.Println("retrying")

// Simulate calling the next backend.
// go run ./hack/successserver
backend(r, body, attempt+1).ServeHTTP(w, newReq(r, body))
return
}
}

log.Println("serving")
return first
}

func getEndpoint(attempt int) string {
switch attempt {
case 0:
return "http://localhost:8081"
default:
return "http://localhost:8082"
}
}

func newReverseProxy(host string) *httputil.ReverseProxy {
u, err := url.Parse(host)
if err != nil {
panic(err)
}
Expand Down

0 comments on commit e0c3dbc

Please sign in to comment.