-
Notifications
You must be signed in to change notification settings - Fork 15
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
Runtime panic occurs if there are multiple Conjure errors with the same name #415
Comments
The issue is that the generated
The In the steps above, the repository ends with with 2 copies of the same It is an intentional design decision to require that error types be globally unique, but this poses a problem in the above scenario. In such a scenario, currently the only workaround is to modify the generated code (basically, to remove the error registration). Although this works, it involves manual edits and also makes it such that typed errors aren't returned for the locally generated code. Possible SolutionsAssociate error registration with particular clientThe purpose of registering the errors is to allow The problem in this circumstance is that there are now 2 separate Go types that both map to the same error. However, in most cases the "scope" should be fairly well-defined -- any calls that use the vendored version of the type (declare the vendored error type as a return error type or operate on it) should use that type, while "local" code should use the local type. Right now As an example of this proposal, the current function signature:
Could be changed to:
Then the generated
We could then change the It's not totally clear that this would be the best approach, but it's an illustration of a possible way to solve this general issue. |
UpdatesI looked into Nick's suggested possible solution today and drafted the beginnings of something I think will work: conjure-go changesI opened this PR to add "conjuremoduleregistrar" package generation. This adds one package per conjure project, where the contents of the package record the package's path:
The value of ConjureModuleIdentifier will depend on the root path of the conjure package, letting us discern between vendored and locally generated code. conjure-go-runtime changesI opened this PR adding support for per-module error registries, as well as method for storing retrieving module names from contexts. A later conjure-go PR can use this new method in the following way:
If vendored conjure and locally generated conjure update to use this instead of the existing RegisterErrorType method, they can deconflict their error registration. still to doThe following is the remaining work I'm aware of in terms of getting this wired up fully:
I don't love using request contexts for wiring here so I'm open to any alternatives people think of. |
Given the global error registry is strictly used for CGR clients to know how to unmarshal a given error type, what if we instead defined a new interface for a conjure error decoder that knows how to unmarshal a specific/strongly-typed error and return a conjure error. Something like this that takes in the name of the error and the body and returns a conjure error. The name is already parsed out in the type ConjureErrorDecoder interface {
DecodeConjureError(name string, body []byte) (errors.Error, error)
} Then we can generate an implementation of this func (e errorDecoder) DecodeConjureError(name string, body []byte) (errors.Error, error) {
switch name {
case "V6:EntityNotFound":
var entityNotFoundErr EntityNotFound
if err := codecs.JSON.Unmarshal(body, &entityNotFoundErr); err != nil {
return nil, err
}
return &entityNotFoundErr, nil
}
return nil, errors.New("Unsupported type")
} Example service client that wires in the ConjureErrorDecoder above. func (c *v6Client) GetEntity(ctx context.Context, authHeader bearertoken.Token, requestArg GetEntityRequest) (EntityResp, error) {
var defaultReturnVal EntityResp
var returnVal *EntityResp
var requestParams []httpclient.RequestParam
requestParams = append(requestParams, httpclient.WithRPCMethodName("GetEntity"))
requestParams = append(requestParams, httpclient.WithRequestMethod("GET"))
requestParams = append(requestParams, httpclient.WithPathf("/entity"))
requestParams = append(requestParams, httpclient.WithJSONRequest(requestArg))
requestParams = append(requestParams, httpclient.WithJSONResponse(&returnVal))
// This is where we wire in the error decoder above.
requestParams = append(requestParams, httpclient.WithRequestConjureErrorDecoder(errorDecoder{}))
if _, err := c.client.Do(ctx, requestParams...); err != nil {
return defaultReturnVal, werror.WrapWithContextParams(ctx, err, "getEntity failed")
}
if returnVal == nil {
return defaultReturnVal, werror.ErrorWithContextParams(ctx, "getEntity response cannot be nil")
}
return *returnVal, nil
} where the func WithRequestConjureErrorDecoder(ced ConjureErrorDecoder) RequestParam {
return requestParamFunc(func(b *requestBuilder) error {
b.errorDecoderMiddleware = errorDecoderMiddleware{
errorDecoder: restErrorDecoder{
conjureErrorDecoder: ced,
},
}
return nil
})
} This allows us to remove the global registry altogether and more tightly couples the errors defined to the endpoints that use them. I prototyped this approach One major flaw with this approach is that we do not know the full set of errors that each service/endpoint returns. This could be solved if error attribution (RFC) is implemented in both the conjure IR and the languages, but that's not done yet. Alternatively, we would need to generate a single errors pkg for each conjure API that contains a new error decoder with all of the API defined errors and then use that in all service requests. |
What did you do?
common-service.conjure.json
):github.com/palantir/test-library-module
that generates code using thecommon-service.conjure.json
definition and references the generated codegithub.com/palantir/test-service-module
that generates code using thecommon-service.conjure.json
definition and references the generated code AND that hasgithub.com/palantir/test-library-module
as a module dependency ingo.mod
github.com/palantir/test-service-module
What happened?
The program crashes on startup with the following error:
What did you want to happen?
Program should start normally
The text was updated successfully, but these errors were encountered: