-
Notifications
You must be signed in to change notification settings - Fork 0
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
Release error chaining and formalise custom errors #1
Conversation
In doing this, I discovered that our Maybe this impacts GRPC error serialisation. Furthermore I'm playing around with error chaining types to see if it's possible to have type-guided error chains which will help for debugging. |
This will require |
This has made the |
One of the important functions would be a static This would follow our Note that when using
Thus producing a very "structured" JSON version of the exception. Unlike our current Since we may expect to serialise exceptions over the network, we would want something to do this. However there's a little challenge here. Because the This is discussed in this comment MatrixAI/Polykey#304 (comment) |
It was explained that GRPC metadata doesn't have "nested" data. However all the fields are "multivalues". Thus it is possible to do:
Deserialising from this would not be using the However an alternative is to avoid relying on the metadata format, and directly set the stringified JSON in just one property. Which gives us some flexibility at the cost of some lower transparency in the GRPC metadata (any reaction to errors, has to involve potentially parsing the JSON first). The During serialisation, we can produce a structured "{ type, data }" format that is used by js-id, so that we have a similar kind of "JSON encoded object" format where the Our GRPC metadata properties can mirror some of the important data from these exception objects. But there should be an The current GRPC properties we are using is:
We know that GRPC also sets additional properties whenever a
When we are throwing our application exceptions, we are using the Suppose all 3 metadata properties was reduced to just:
On the other side, we acquire the
Now the It has to take the In In this case, This is what we currently do in
This only works because Let me prototype a static function that gets inherited and uses the internal class name. We may be able to work something out, if we can expect the same class wrapper at the root of the exception structure. Any types that are not valid exceptions, would then need to be converted to a "base" exception that gets used. We already do something like this in
That acts as the base during recursive traversal of the JSON structure. |
Because causes can be arbitrary, this creates a form of open-extensibility for the cause chain, which means that encoding and decoding to and from JSON has to deal with arbitrary data types. To deal with this, I suspect a combination of JSON's replacer and reviver mechanisms have to be used to work against a select set of types. In this library alone, the only types we are aware of are During encoding, instances of We can at least resolve this issue by dealing with this in our It also seems that we may provide Alternatively the Seems like it could be limited to just instances of So at the end of the day, the user must supply the appropriate reviver or replacer. This would be case with PK. |
Additional requirement coming from MatrixAI/Polykey#321 (comment)
Consider when we make a function call to a particular domain like One way to differentiate this is to augment the exception with additional details in the This means This new exception can then have in its It may not actually be necessary to reconstruct all exception objects in the This can be addressed by have a base exception class indicating |
Additionally we should also differentiate client to agent calls, and agent to agent calls, so a single import { AbstractError } from '@matrixai/errors';
import sysexits from './utils/sysexits';
// exitCode is not part of `AbstractError` since it is specific to how PK uses it
class ErrorPolykey extends AbstractError {
static description = 'Polykey error';
exitCode: number = sysexits.GENERAL;
}
// here is our new wrappers intended to be used by `grpcUtils.toError` when receiving error over GRPC call
// Client to Agent calls and Agent to Agent Calls
// use the nodeId property to differentiate between own agent and foreign agent
class ErrorPolykeyRemote extends ErrorPolykey {
static description = 'Remote error from RPC call';
exitCode = sysexits.UNAVAILABLE;
nodeId: NodeId;
nodeAddress: NodeAddress;
}
// the exit code for `ErrorPolykeyRemote` may actually depend on what it is wrapping though |
The This should be done for client to agent and agent to agent. We now have output format options in That would mean one cannot just use Alternatively the Important details like |
As an example rather than You do:
That ensures that the exception being stringified is already being filtered, in this case the |
It turns out that as soon as there's a |
I just discovered that JS It's also available https://stackoverflow.com/questions/22303633/set-error-cause-in-javascript-node-js Node.js (16.9+). We aren't on that version just yet. This is great, the design basically matches the exact API I have. And this should also mean that we can now expect a causation chain even for normal |
For now I can't use it mainly due to:
|
Going to put this here for later, since I want to try out error integration first.
I'm not sure if Until we have figured out a good pattern for this. I suspect the The |
Also test details...
|
Description
Issues Fixed
Tasks
AbstractError
as the global class to be inherited fromcause
property that allows one to determine an "exception chain"timestamp: Date
property that is weakly monotonic.[ ] 4. Figure out proper serialisation and deserialisation especially in the causation chain.toJSON
method to not actually useJSON.stringify
, it should be returning the POJO that will be used byJSON
Final checklist