Project

General

Profile

Actions

Bug #7492

closed

[keepproxy] Report upstream server errors as 502 Bad Gateway instead of 404

Added by Peter Amstutz over 8 years ago. Updated over 8 years ago.

Status:
Resolved
Priority:
Normal
Assigned To:
Radhika Chippada
Category:
-
Target version:
Story points:
1.0

Description

Keepproxy (which uses keepclient) is failing requests because one of the upstream servers returned "read tcp 10.26.0.7:25107: 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.

Requirements

If an error occurs in (*keepclient.KeepClient)Get() then keepproxy's http response status must be:
  • 404 if every keepstore service returned 404
  • 422 if every keepstore service returned a non-retryable error (but some didn't return 404)
  • 502 if any keepstore service had still returned a retryable error when tries_remaining ran out

Also, the list of errors received from the upstream keepstore services should be propagated to keepproxy's client in the response body. (Currently this information is logged by the SDK, so it shows up in keepproxy's log file but it is not available to the originator of the request.)

Implementation

We need to update (*keepclient.KeepClient)Get() to make it possible for keepproxy to distinguish between the above outcomes.

keepclient:
  • create an Error interface (similar to https://golang.org/pkg/net/#Error)
    • type Error struct {
          error
          Temporary() bool // Is the error temporary?
      }
  • create a multipleResponseError type that implements Error
    • type multipleResponseError struct {
          error
          isTemp bool
      }
      func (e *multipleResponseError) Temporary() bool {
          return e.isTemp
      }
      
  • create a NotFoundError type that implements Error
    • type NotFoundError struct {
          multipleResponseError
      }
      
  • Change BlockNotFound to a NotFoundError
    • 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:
    • 
      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.)

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

Subtasks 1 (0 open1 closed)

Task #7557: Review branch: 7492-keepproxy-upstream-errorsResolvedRadhika Chippada10/14/2015Actions

Related issues

Related to Arvados - Bug #7491: [SDK] Go keepclient should retry on network errorsResolvedPeter Amstutz10/08/2015Actions
Actions

Also available in: Atom PDF