Join GitHub today
GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.
Sign upUnchecked exceptions can't be captured from a ServerInterceptor #1552
Comments
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ejona86
Mar 15, 2016
Member
FYI, failure rate statistics are going to be a native feature.
Yes, close() is not called, because 1) it is impossible to call from a threading standpoint and 2) it would have to be a feature of the stub which means if an interceptor threw an exception close() still wouldn't be called.
Your best option is to override onHalfClose (and preferably the other listener methods, too) to catch and notice the exception. Note that startCall would throw instead in the case of client-streaming and bidi calls. Basically you should catch exceptions from all the listener methods and startCall.
|
FYI, failure rate statistics are going to be a native feature. Yes, Your best option is to override onHalfClose (and preferably the other listener methods, too) to catch and notice the exception. Note that startCall would throw instead in the case of client-streaming and bidi calls. Basically you should catch exceptions from all the listener methods and startCall. |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
zackangelo
commented
Mar 16, 2016
|
Thanks Eric! The option you suggested in the meantime seems to work great. |
zackangelo
closed this
Mar 16, 2016
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
zackangelo
May 13, 2016
@ejona86 hate to resurrect an old issue... we're trying to similarly capture exceptions, but now we'd like to add a header or trailer with the error details in the Throwable.
It's straightforward if the error occurs asynchronously, but if it's in the calling thread the error is thrown in onHalfClose, by which point it seems too late to modify the Metadata in the response?
zackangelo
commented
May 13, 2016
|
@ejona86 hate to resurrect an old issue... we're trying to similarly capture exceptions, but now we'd like to add a header or trailer with the error details in the Throwable. It's straightforward if the error occurs asynchronously, but if it's in the calling thread the error is thrown in |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ejona86
May 13, 2016
Member
@zackangelo, I don't follow, onHalfClose is called before ServerCall.close() has been called. You want to send headers instead?
|
@zackangelo, I don't follow, |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
zackangelo
May 13, 2016
@ejona86 Maybe I'm missing something, but if I modify the Metadata from onHalfClose, those trailers don't seem to be making it in the response.
zackangelo
commented
May 13, 2016
|
@ejona86 Maybe I'm missing something, but if I modify the |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ejona86
May 13, 2016
Member
"the Metadata" Where did you get that instance? It might be useful to see a small code snippet (or pseudo code)
|
" |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
zackangelo
commented
May 13, 2016
|
It's the |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ejona86
May 14, 2016
Member
The Metadata passed to interceptCall() is incoming from the client. Changing it will never impact the response. Instead, you need to deal with the Metadata passed in sendHeaders() or 'close()`.
|
The Metadata passed to |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
zackangelo
May 16, 2016
@ejona86 apologies, we've been grasping at straws a bit trying to get it to work, this was one of our more desperate iterations :)
sendHeaders doesn't appear to be called at all, is there anything additional I need to do to make the interceptor aware that I want to send headers? Also, would sendHeaders be invoked after the exception occurs in the method call? Thanks for your help.
zackangelo
commented
May 16, 2016
|
@ejona86 apologies, we've been grasping at straws a bit trying to get it to work, this was one of our more desperate iterations :)
|
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ejona86
May 16, 2016
Member
Try something like this. Note that it assumes when an exception occurs that the application will not use ServerCall any more (since the object is not thread-safe). For many applications that's a reasonable assumption.
@Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
MethodDescriptor<ReqT, RespT> method,
final ServerCall<RespT> call,
final Metadata requestHeaders,
ServerCallHandler<ReqT, RespT> next) {
ServerCall.Listener<ReqT> listener;
try {
listener = next.startCall(method, call, requestHeaders);
} catch (RuntimeException ex) {
handleException(call, ex);
throw ex;
}
return new SimpleForwardingServerCallListener<ReqT>(listener) {
// No point in overriding onCancel and onComplete; it's already too late
@Override public void onHalfClose() {
try {
super.onHalfClose();
} catch (RuntimeException ex) {
handleException(call, ex);
throw ex;
}
}
@Override public void onReady() {
try {
super.onReady();
} catch (RuntimeException ex) {
handleException(call, ex);
throw ex;
}
}
};
private void handleThrowable(ServerCall<RespT> call, Throwable t) {
call.close(Status.fromThrowable(ex), yourCustomLogic(ex));
}
}|
Try something like this. Note that it assumes when an exception occurs that the application will not use ServerCall any more (since the object is not thread-safe). For many applications that's a reasonable assumption. @Override
public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(
MethodDescriptor<ReqT, RespT> method,
final ServerCall<RespT> call,
final Metadata requestHeaders,
ServerCallHandler<ReqT, RespT> next) {
ServerCall.Listener<ReqT> listener;
try {
listener = next.startCall(method, call, requestHeaders);
} catch (RuntimeException ex) {
handleException(call, ex);
throw ex;
}
return new SimpleForwardingServerCallListener<ReqT>(listener) {
// No point in overriding onCancel and onComplete; it's already too late
@Override public void onHalfClose() {
try {
super.onHalfClose();
} catch (RuntimeException ex) {
handleException(call, ex);
throw ex;
}
}
@Override public void onReady() {
try {
super.onReady();
} catch (RuntimeException ex) {
handleException(call, ex);
throw ex;
}
}
};
private void handleThrowable(ServerCall<RespT> call, Throwable t) {
call.close(Status.fromThrowable(ex), yourCustomLogic(ex));
}
} |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
zackangelo
May 16, 2016
Some additional clarification after I ran some more tests, it looks like sendHeaders isn't invoked at all if the method results in a failure in any way (async or in calling thread).
zackangelo
commented
May 16, 2016
|
Some additional clarification after I ran some more tests, it looks like |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
zackangelo
May 16, 2016
@ejona86 closing the call in the exception handlers seems to be working!
Am I altering the call flow in any meaningful way that I should be aware of? Why isn't .close(...) called by default when an exception occurs in .onHalfClose()?
zackangelo
commented
May 16, 2016
|
@ejona86 closing the call in the exception handlers seems to be working! Am I altering the call flow in any meaningful way that I should be aware of? Why isn't |
This comment has been minimized.
Show comment
Hide comment
This comment has been minimized.
ejona86
May 16, 2016
Member
Why isn't .close(...) called by default when an exception occurs in .onHalfClose()?
Because close() is "outside" of the runtime; it can only be called from the application, and threading prevents us from calling it as part of the stub. And even then it wouldn't change what happens when an interceptor throws an exception.
close() is called within the grpc library, but that doesn't invoke any interceptors because it happens within the Channel itself. Normally the exception is just logged and onCancelled() called.
Because close() is "outside" of the runtime; it can only be called from the application, and threading prevents us from calling it as part of the stub. And even then it wouldn't change what happens when an interceptor throws an exception. close() is called within the grpc library, but that doesn't invoke any interceptors because it happens within the Channel itself. Normally the exception is just logged and onCancelled() called. |
zackangelo commentedMar 15, 2016
I'm attempting to add instrumentation to our gRPC service implementations using a
ServerInterceptor, namely failure rates on a per-method basis. To do this, I'm using aSimpleForwardingServerCall, overriding theclosemethod and then checking the status to see if the call succeeded.When an unchecked exception is thrown from a service implementation:
and given an
interceptCallmethod that looks something like this:the
closemethod is never called, so there isn't an opportunity to log the failure.The exception seems to bubble up to the Executor instead:
I've also tried returning a
ForwardingServerCallListenerfrominterceptCalland theonCompletecallback is invoked, but it doesn't have enough information for me to determine if the call was a failure.Is there another API I can take a look at that will allow me to capture these failures?