puppet
puppet copied to clipboard
[RFC] We need a better error system
Is your feature request related to a problem? Please describe. Recently we observed more and more limitation pushed out by WeChat. In some cases, connection to WeChat server got kicked out. It would be better that we emit these cases as errors so developers could handle them properly.
Currently all the error messages emitted is an Error instance, only one message on it, so it is really hard to set a solid error type for the error. So here is this issue, I would like to bring this issue up and talk about the design for WechatyError or something else :P
Describe the solution you'd like
We could have a parent error type as WechatyError, then PuppetError extends the parent, then each puppet has its own error class.
How about this design:
class WechatyError extends Error {
public readonly type: WechatyErrorType
public readonly message: string
constructor (
type: WechatyErrorType,
message: string,
) {
super()
this.type = type
this.message = message
}
}
Or we could make this parent error as an abstract class, then all the other errors extends this one.
Describe alternatives you've considered Haven't considered any alternatives...
Additional context
I've implemented one temporary solution in wechaty-puppet-padpro, but that's just a test, you could check it here:
https://github.com/botorange/wechaty-puppet-padpro/commit/47d8de1bf885201629c8dd6dd34aaf721260d1c5
Here is a small piece of code that how I use it:
bot
.on('error', error => {
const errorMessage = error.message
const subMessages = errorMessage.split(' ')
if (subMessages[0] === 'PADPRO_ERROR' && subMessages[1] === 'LOGIN') {
console.log(`-----------------------------------------------------
AutoLogin Error:
type: ${subMessages[2]}
message: ${subMessages[3]}
------------------------------------------------------`)
}
})
.start()
To be honest, this is ugly, but just treat this as 【抛砖引玉】(don't know how to translate this :P)
Let's make wechaty better and better.
[enhancement]
Thanks for the RFC, it's a very good proposal.
Could you be able to provide 3 of the best examples that you could find in other open source projects, and points out which part do you think they are the best?
I believe we need more 砖 to study first, then we will be able to discuss deeper based on them.
I could try to find some good examples. And will post it in the issue.
In the mean time, how about tensorflow, what kind of error classes do they have? Since you've been working on that project for a period of time, could you please share a little about that?
After thinking this RFC for the past 12 months, I believe that we can move forward to continue discussing how to implement it because we will have some huge improvements for the Wechaty recently after we landing the Multi-language Wechaty.
@windmemory Would you like to share some more thoughts from your experiences in the past year? I believe it would be a great help for us to understand what is the best design of our Error system.
From the previous experience, I think there are two key properties needs to be reported when an error happened. They are:
- error type (used to distinguish different errors)
- whether is recoverable (so we can decide whether we should retry the operation)
Error type
I think we can achieve this feature in two ways
- add a property
typeto the error class, we can distinguish the error by thetype - extend the base error class with different class, we can distinguish the error by
instanceoffunction
Recoverable
This can be solved in similar ways as above.
- add a property
recoverableto the error class - extend the base error class, create
RecoverableErrorandNonRecoverableError, then all the other error needs to extends these two classes.
Other topic needs to be considered and discussed
- where should we declare and implement these errors?
- how a developer extends the errors we have currently
- how to transfer these class to different languages?
- since we want use grpc protobuf as the union type for different language, shall we also declare the error using protobuf? But seems like there is no standard Error syntax supported by protobuf. We need to create the error model ourselves. I am not quite familiar with this part, @huan could you please share some insights related to protobuf?
Discussion Draft
enum WechatyErrorType {
UNKNOWN = 0,
NO_PAYLOAD = 1,
}
puppet.on('error', data => {
const e = new WechatyError(data)
})
class WechatyError extends Error {
public static from (data: grpcError) {
payload = JSON.parse(data)
const e = new this(payload)
return e
}
public to() {
return {
message: this.message,
name: this.name,
stack: this.stack,
type: this.type,
}
}
private type: WechatyErrorType
private constructor (
payload: any
) {
this.type = WechatyErrorType[payload.type] ?? WechatyErrorType.UNKNOWN
}
}
Google API Design Principle: Errors
- https://cloud.google.com/apis/design/errors
- https://github.com/googleapis/googleapis/blob/master/google/rpc/status.proto#L35
We have implemented the first version of a gRPC and ECMA compatible error class: GError.
Learn more at https://github.com/wechaty/puppet/blob/main/src/gerror/gerror.ts