-
Notifications
You must be signed in to change notification settings - Fork 327
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Get panic cause as error in Error hooks #160
Conversation
func AddImport(fset *token.FileSet, f *ast.File, ipath string) (added bool) { | ||
return AddNamedImport(fset, f, "", ipath) | ||
func AddImport(fset *token.FileSet, f *ast.File, path string) (added bool) { | ||
return AddNamedImport(fset, f, "", path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry, all of this appeared when I first ran make test_core
.
I wonder if I can git reset
this, or if we should keep this diff around to keep tools up to date. I tried to mitigate some of this in another PR: #159 but that didn't update the tools. I'm not sure I understand what is going on here.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to rethink our build tooling in general, maybe moving to doing everything in Docker. I'll just accept these changes for now.
Fixes #163 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks basically good - I agree with the goal here.
internal/twirptest/service.twirp.go
Outdated
// The panic is not intercepted and should be handled in middleware to avoid empty responses. | ||
func handlePanics(ctx context.Context, resp http.ResponseWriter, hooks *twirp.ServerHooks) { | ||
if r := recover(); r != nil { | ||
err := errFromPanic(r) // allow to inspect error on Error hooks |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
These comments are overflowing way off to the right side. Could we get them to stay under ~100 characters, either by moving them above the lines they describe or by not vertically aligning them?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
They seem to auto-align when generating code. I didn't realize that was happening. Fixing ...
internal/twirptest/service_test.go
Outdated
@@ -802,7 +803,7 @@ func TestPanickyApplication(t *testing.T) { | |||
h := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { | |||
defer func() { | |||
if r := recover(); r == nil { | |||
t.Error("http server never panicked") | |||
t.Error("http server never panicked") // also make sure it did panic |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think this comment is useful.
internal/twirptest/service_test.go
Outdated
errHookCalled = true | ||
// The error should have a .Cause containing the panic value for inspection | ||
err := pkgerrors.Cause(twerr) | ||
if err.Error() != "This Is Fine Meme" { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Rather than testing the error string, you should be able to test whether err == panicValue
directly.
internal/twirptest/service_test.go
Outdated
server := httptest.NewServer(h) | ||
defer server.Close() | ||
|
||
client := NewHaberdasherJSONClient(server.URL, http.DefaultClient) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would be good to test both JSON and Protobuf code paths.
internal/twirptest/service.twirp.go
Outdated
_ = writeErr | ||
} | ||
|
||
callResponseSent(ctx, hooks) | ||
callResponseSent(ctx, hooks) // ResponseSent hook |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this comment
internal/twirptest/service.twirp.go
Outdated
// hook, or just silently ignore the error. | ||
// | ||
// Logging is unacceptable because we don't have a user-controlled | ||
// Most likely the connection is broken. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer the old comment that was here, could you revert this change?
internal/twirptest/service.twirp.go
Outdated
@@ -381,32 +365,23 @@ func writeError(ctx context.Context, resp http.ResponseWriter, err error, hooks | |||
|
|||
statusCode := twirp.ServerHTTPStatusFromErrorCode(twerr.Code()) | |||
ctx = ctxsetters.WithStatusCode(ctx, statusCode) | |||
ctx = callError(ctx, hooks, twerr) | |||
ctx = callError(ctx, hooks, twerr) // Error hook |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove this comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it make sense to rename callError
to callErrorHook
? and callResponseSent
to callResponseSentHook
? etc. No big deal, I just found "callError" to be a little misleading.
internal/twirptest/service.twirp.go
Outdated
func (e *wrappedError) Cause() error { return e.cause } | ||
func (e *wrappedError) Error() string { return e.prefix + ": " + e.cause.Error() } | ||
|
||
// handlePanics makes sure that panics during rpc methods respond with Twirp Interna |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: Internal
internal/twirptest/service.twirp.go
Outdated
|
||
// handlePanics makes sure that panics during rpc methods respond with Twirp Interna | ||
// error responses (status 500) and trigger hooks with the panic wrapped as an error. | ||
// The panic is not intercepted and should be handled in middleware to avoid empty responses. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd phrase this differently. The panic is definitely intercepted, we just re-raise it.
Empty responses are kind of a separate issue that we should be able to deal with by flushing correctly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I'll phrase it differently to be more clear. I found the empty response issue while working on this, it was not as clear to me before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For reference, the empty responses issue is tracked here #163
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One minor bug in a test, but LGTM other than that.
if err == nil { | ||
t.Fatalf("%s client: err was expected for panicking handler, found nil", name) | ||
} | ||
if !errHookCalled { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need to reset this variable to false
after the first loop iteration
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(fixed it myself)
func AddImport(fset *token.FileSet, f *ast.File, ipath string) (added bool) { | ||
return AddNamedImport(fset, f, "", ipath) | ||
func AddImport(fset *token.FileSet, f *ast.File, path string) (added bool) { | ||
return AddNamedImport(fset, f, "", path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we need to rethink our build tooling in general, maybe moving to doing everything in Docker. I'll just accept these changes for now.
if err == nil { | ||
t.Fatalf("%s client: err was expected for panicking handler, found nil", name) | ||
} | ||
if !errHookCalled { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(fixed it myself)
Currently, service method handlers make sure that panics still call Error hooks. However, the
twirp.Error
passed to the error hook has no information about the panic, it is simply anInternal
error with Msg: "Internal service panic".This PR adds a
Cause
to the error passed to the Error hooks, so it can be unwrapped withpkg/errors.Cause
. The resulting error response is the same, with Msg: "Internal service panic", the information about the panic is only available in the server through accessing the cause.In addition, I made a little bit of refactor to simplify and explain the code that handles panics.