ardanlabs / service

Starter-kit for writing services in Go using Kubernetes.

Home Page:https://www.ardanlabs.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Web errors middleware

Delicious-Bacon opened this issue · comments

I am not an expert, but something caught my eyes.

The web errors middleware will propagate the response error to the outer-most layer and potentially cause the unwanted shutdown.




Why I think it might cause the unwanted shutdown:
a.SignalShutdown()

If I am correct, that is the outer-most layer (the app's Handle).
Since it initiates the shutdown on any err != nil, it might shutdown the app with these Respond errors:





This might be the legacy of issue #168 where the Respond could have returned a shutdownError.

This is coded on purpose and explained in the class.

The idea is if the error middleware propegates any error, it wants the system to shutdown. One of the rules for error handling is the error stops with the code handling the error. In this case, the error is not stopping.

The error middleware could be coded to do more checks to validate a shutdown should happen. That for now is beyond the scope of this MVP.

I get what you mean with the error propagation, and I love that idea.

What I meant to point out was that the error handler middleware could have handled the respond's error (log it), and only propagate the error if it's the IsShutdown. Respond in this case wanted to write the error to the user, but what if the connection already closed (ResponseWriter.Write() returns that kind of an error), is it worth the shutdown on our end?

Something like this:

// Respond with the error back to the client.
if rErr := web.Respond(ctx, w, er, status); rErr != nil {
    // Log the error.
    // I would add this in any case, since we don't know what caused
    // the propagation if the Respond caused it.
    // Just like logging the original received err on line #35.
    log.Errorw("ERROR", "traceid", v.TraceID, "message", rErr)

    // Propagate only if response error must cause shutdown.
    if ok := web.IsShutdown(rErr); ok {
        return rErr
    }
}

// If we receive the shutdown err we need to return it
// back to the base handler to shut down the service.
if ok := web.IsShutdown(err); ok {
    return err
}

Again, this would mean the Respond would have to decide when to return the NewShutdownError.

This stackoverflow answer states some of the "Reasons why ResponseWriter.Write() may return a non-nil error".

The json.Marshal() might also return an error in the Respond.

In your opinion, which of these errors would demand a shutdown and why?

I am a rookie and would love to know your whys behind your decisions in a case like this.

You are asking great questions. Engineering is about making choices with well defined costs. The code I'm providing is using a philosophy that says, any error returned by the error middleware indicates a program wide integrity error and we need to restart.

You may want to change this and make it more specific. Whatever you choose is correct for your service because you are thinking about it and understand the choice.

Thank you, Bill, your answer has taught me more than what I asked for. I asked for the fish, and you've taught me how to fish. I am grateful for that.