Bug #7492

Updated by Tom Clegg over 4 years ago

Keepproxy (which uses keepclient) is failing requests because one of the upstream servers returned "read tcp use of closed network connection". This is being returned to the client as a 404, but actually should be a 502 (Bad Gateway) which would trigger retry logic on the client.

h3. Implementation

* create an Error interface (similar to https://golang.org/pkg/net/#Error)
** <pre><code>type Error struct {
Temporary() bool // Is the error temporary?
* create a multipleResponseError type that implements Error
** <pre><code>type multipleResponseError struct {
isTemp bool
func (e *multipleResponseError) Temporary() bool {
return e.isTemp
* create a NotFoundError type that implements Error
** <pre><code>type NotFoundError struct {
* Change BlockNotFound to a NotFoundError
** <pre><code>var BlockNotFound = &NotFoundError{multipleResponseError{
error: errors.New("Block not found"),
isTemp: false,
* in Get(), count how many responses are http.StatusNotFound
* when returning from Get() after all attempts have failed, make a NotFoundError or a multipleResponseError:
** <pre><code>
if count404 == len(serversToTry) {
err = BlockNotFound
} else {
err = &multipleResponseError{
error: fmt.Errorf("%s %s failed: %v", method, locator, errs),
isTemp: len(serversToTry) > 0,

(*Defer:* add a way for clients to see a slice of all errors encountered, or at least the last error from each server. For now, that information is only available as a string, via the usual Error() method.)

* Do a type select on the error returned from keepclient.Get() to determine the appropriate HTTP response
** <pre><code>
switch err := err.(type) {
case keepclient.NotFoundError:
// respond 404
case keepclient.Error:
if err.Temporary() {
// respond 502
} else {
// respond 422
// respond 500
* In all cases, return err.Error() in the response body.