-
Notifications
You must be signed in to change notification settings - Fork 903
chore: Compile rego once to save CPU cycles in testing #4169
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
Conversation
coderd/rbac/authz.go
Outdated
func init() { | ||
var err error | ||
query, err = rego.New( | ||
// Bind the results to 2 variables for easy checking later. | ||
rego.Query( | ||
fmt.Sprintf("%s := data.authz.role_allow "+ | ||
"%s := data.authz.scope_allow", | ||
rolesOkCheck, scopeOkCheck), | ||
), | ||
rego.Module("policy.rego", policy), | ||
).PrepareForEval(ctx) | ||
|
||
).PrepareForEval(context.Background()) | ||
if err != nil { | ||
return nil, xerrors.Errorf("prepare query: %w", err) | ||
panic(err) | ||
} | ||
return &RegoAuthorizer{query: query}, nil | ||
} | ||
|
||
const ( | ||
rolesOkCheck = "role_ok" | ||
scopeOkCheck = "scope_ok" | ||
) | ||
|
||
func NewAuthorizer() *RegoAuthorizer { | ||
return &RegoAuthorizer{query: query} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can we just do this with a sync.Once instead of a init()
? I just don't like inits()
in packages.
var authorizerOnce = sync.Once{}
// cachedQuery is cached to only be compiled once.
var cachedQuery *rego.PreparedEvalQuery
func NewAuthorizer() (*RegoAuthorizer, error) {
ctx := context.Background()
var query rego.PreparedEvalQuery
var err error
// Only compile the authorizer once and reuse it.
authorizerOnce.Do(func() {
query, err = rego.New(
// Bind the results to 2 variables for easy checking later.
rego.Query(
fmt.Sprintf("%s := data.authz.role_allow "+
"%s := data.authz.scope_allow",
rolesOkCheck, scopeOkCheck),
),
rego.Module("policy.rego", policy),
).PrepareForEval(ctx)
if err != nil {
err = xerrors.Errorf("prepare query: %w", err)
}
cachedQuery = &query
})
// Error from the first call
if err != nil {
return nil, err
}
if cachedQuery == nil {
return nil, xerrors.Errorf("cached query failed to compile")
}
return &RegoAuthorizer{query: *cachedQuery}, nil
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think erroring from the first call will result in more strange behavior... because you'd get an indirect error on the second execution. We panic'd before in coderd.go
, so I tried to keep the same behavior.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yea, that is annoying. Could cache the error, but panicing is fine
coderd/rbac/authz.go
Outdated
rego.Module("policy.rego", policy), | ||
).PrepareForEval(context.Background()) | ||
if err != nil { | ||
panic(err) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Wrap the error with some context?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
true
Compiling rego isn't very fast, so this should speed up tests in CI!
Compiling rego isn't very fast, so this should speed up tests in CI!