Javadoc
Converts an internal exception thrown by Conductor into an StatusException
that uses modern "Status" metadata for GRPC.
Note that this is trickier than it ought to be because the GRPC APIs have
not been upgraded yet. Here's a quick breakdown of how this works in practice:
Reporting a "status" result back to a client with GRPC is pretty straightforward.
GRPC implementations simply serialize the status into several HTTP/2 trailer headers that
are sent back to the client before shutting down the HTTP/2 stream.
- 'grpc-status', which is a string representation of a
com.google.rpc.Code- 'grpc-message', which is the description of the returned status
- 'grpc-status-details-bin' (optional), which is an arbitrary payload with a serialized
ProtoBuf object, containing an accurate description of the error in case the status is not
successful.
By convention, Google provides a default set of ProtoBuf messages for the most common
error cases. Here, we'll be using
DebugInfo, as we're reporting an internal
Java exception which we couldn't properly handle.
Now, how do we go about sending all those headers _and_ the
DebugInfo payload
using the Java GRPC API?
The only way we can return an error with the Java API is by passing an instance of
io.grpc.StatusException or
io.grpc.StatusRuntimeException to
StreamObserver#onError(Throwable). The easiest way to create either of these
exceptions is by using the
Status class and one of its predefined code
identifiers (in this case,
Status#INTERNAL because we're reporting an internal
exception). The
Status class has setters to set its most relevant attributes,
namely those that will be automatically serialized into the 'grpc-status' and 'grpc-message'
trailers in the response. There is, however, no setter to pass an arbitrary ProtoBuf message
to be serialized into a `grpc-status-details-bin` trailer. This feature exists in the other
language implementations but it hasn't been brought to Java yet.
Fortunately,
Status#asException(Metadata) exists, allowing us to pass any amount
of arbitrary trailers before we close the response. So we're using this API to manually
craft the 'grpc-status-detail-bin' trailer, in the same way that the GRPC server implementations
for Go and C++ craft and serialize the header. This will allow us to access the metadata
cleanly from Go and C++ clients by using the 'details' method which _has_ been implemented
in those two clients.