Add APIErrorWrapper so that underlying errors can be logged (#1246)

This commit is contained in:
Owen Strain
2018-09-28 17:26:54 -07:00
committed by GitHub
parent 0dd24932f2
commit 21f77f837e
4 changed files with 48 additions and 10 deletions

View File

@@ -194,3 +194,26 @@ type ErrorWrapper struct {
func (m *ErrorWrapper) Validate() error { func (m *ErrorWrapper) Validate() error {
return nil return nil
} }
// APIErrorWrapper wraps an error with an APIError such that the APIError
// governs the HTTP response but the root error remains accessible.
type APIErrorWrapper interface {
APIError
RootError() error
}
type apiErrorWrapper struct {
APIError
root error
}
func (w apiErrorWrapper) RootError() error {
return w.root
}
func NewAPIErrorWrapper(apiErr APIError, rootErr error) APIErrorWrapper {
return &apiErrorWrapper{
APIError: apiErr,
root: rootErr,
}
}

View File

@@ -34,12 +34,10 @@ func (p *chPlacer) PlaceCall(rp RunnerPool, ctx context.Context, call RunnerCall
key := call.Model().FnID key := call.Model().FnID
sum64 := siphash.Hash(0, 0x4c617279426f6174, []byte(key)) sum64 := siphash.Hash(0, 0x4c617279426f6174, []byte(key))
var runnerPoolErr error
for { for {
runners, err := rp.Runners(call) var runners []Runner
if err != nil { runners, runnerPoolErr = rp.Runners(call)
state.HandleFindRunnersFailure(err)
return err
}
i := int(jumpConsistentHash(sum64, int32(len(runners)))) i := int(jumpConsistentHash(sum64, int32(len(runners))))
for j := 0; j < len(runners) && !state.IsDone(); j++ { for j := 0; j < len(runners) && !state.IsDone(); j++ {
@@ -59,6 +57,14 @@ func (p *chPlacer) PlaceCall(rp RunnerPool, ctx context.Context, call RunnerCall
} }
} }
if runnerPoolErr != nil {
// If we haven't been able to place the function and we got an error
// from the runner pool, return that error (since we don't have
// enough runners to handle the current load and the runner pool is
// having trouble).
state.HandleFindRunnersFailure(runnerPoolErr)
return runnerPoolErr
}
return models.ErrCallTimeoutServerBusy return models.ErrCallTimeoutServerBusy
} }

View File

@@ -28,12 +28,10 @@ func (sp *naivePlacer) PlaceCall(rp RunnerPool, ctx context.Context, call Runner
state := NewPlacerTracker(ctx, &sp.cfg) state := NewPlacerTracker(ctx, &sp.cfg)
defer state.HandleDone() defer state.HandleDone()
var runnerPoolErr error
for { for {
runners, err := rp.Runners(call) var runners []Runner
if err != nil { runners, runnerPoolErr = rp.Runners(call)
state.HandleFindRunnersFailure(err)
return err
}
for j := 0; j < len(runners) && !state.IsDone(); j++ { for j := 0; j < len(runners) && !state.IsDone(); j++ {
@@ -51,5 +49,13 @@ func (sp *naivePlacer) PlaceCall(rp RunnerPool, ctx context.Context, call Runner
} }
} }
if runnerPoolErr != nil {
// If we haven't been able to place the function and we got an error
// from the runner pool, return that error (since we don't have
// enough runners to handle the current load and the runner pool is
// having trouble).
state.HandleFindRunnersFailure(runnerPoolErr)
return runnerPoolErr
}
return models.ErrCallTimeoutServerBusy return models.ErrCallTimeoutServerBusy
} }

View File

@@ -27,6 +27,9 @@ func handleErrorResponse(c *gin.Context, err error) {
// HandleErrorResponse used to handle response errors in the same way. // HandleErrorResponse used to handle response errors in the same way.
func HandleErrorResponse(ctx context.Context, w http.ResponseWriter, err error) { func HandleErrorResponse(ctx context.Context, w http.ResponseWriter, err error) {
log := common.Logger(ctx) log := common.Logger(ctx)
if w, ok := err.(models.APIErrorWrapper); ok {
log = log.WithField("root_error", w.RootError())
}
if ctx.Err() == context.Canceled { if ctx.Err() == context.Canceled {
log.Info("client context cancelled") log.Info("client context cancelled")