-
Notifications
You must be signed in to change notification settings - Fork 72
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
feat!: flagSetMetadata in OFREP/ResolveAll, core refactors #1540
Conversation
✅ Deploy Preview for polite-licorice-3db33c canceled.
|
@@ -1184,222 +1264,6 @@ func TestState_Evaluator(t *testing.T) { | |||
expectedError: true, | |||
expectedResync: false, | |||
}, | |||
"flag metadata": { |
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.
The idea of these tests is now moved above (metadata merging).
738c41d
to
575526c
Compare
Signed-off-by: Todd Baert <[email protected]>
575526c
to
0db0f4e
Compare
Signed-off-by: Todd Baert <[email protected]>
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.
There are a couple of TODO that should either be removed or actioned. The change looks great and the functionality aligns with that JS implementation. Thanks!
Signed-off-by: Todd Baert <[email protected]>
Signed-off-by: Todd Baert <[email protected]>
// TODO: We do not handle metadata in ADD/UPDATE operations. These are only relevant for grpc sync implementations. | ||
switch payload.Type { | ||
case sync.ALL: | ||
events, reSync = je.store.Merge(je.Logger, payload.Source, payload.Selector, newFlags.Flags) | ||
events, reSync = je.store.Merge(je.Logger, payload.Source, payload.Selector, definition.Flags, definition.Metadata) | ||
case sync.ADD: | ||
events = je.store.Add(je.Logger, payload.Source, payload.Selector, newFlags.Flags) | ||
events = je.store.Add(je.Logger, payload.Source, payload.Selector, definition.Flags) | ||
case sync.UPDATE: | ||
events = je.store.Update(je.Logger, payload.Source, payload.Selector, newFlags.Flags) | ||
events = je.store.Update(je.Logger, payload.Source, payload.Selector, definition.Flags) | ||
case sync.DELETE: | ||
events = je.store.DeleteFlags(je.Logger, payload.Source, newFlags.Flags) | ||
events = je.store.DeleteFlags(je.Logger, payload.Source, definition.Flags) |
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.
ADD/UPDATE are only relevant to hypothetical gRPC server implementations, and were a premature optimization to allow gRPC servers to tell flagd "just add these flags, or just change this flag" instead of sending a whole payload. I have never seen this implemented, and it's not relevant to any of the other sync types.
I think we should cease to enhance them and deprecate them in the protobuf.
🤖 I have created a release *beep* *boop* --- <details><summary>flagd: 0.12.0</summary> ## [0.12.0](flagd/v0.11.8...flagd/v0.12.0) (2025-01-31) ### ⚠ BREAKING CHANGES * flagSetMetadata in OFREP/ResolveAll, core refactors ([#1540](#1540)) ### 🐛 Bug Fixes * **deps:** update module buf.build/gen/go/open-feature/flagd/connectrpc/go to v1.18.1-20250127221518-be6d1143b690.1 ([#1535](#1535)) ([d5ec921](d5ec921)) * **deps:** update module buf.build/gen/go/open-feature/flagd/grpc/go to v1.5.1-20250127221518-be6d1143b690.2 ([#1536](#1536)) ([e23060f](e23060f)) * **deps:** update module buf.build/gen/go/open-feature/flagd/protocolbuffers/go to v1.36.4-20241220192239-696330adaff0.1 ([#1529](#1529)) ([8881a80](8881a80)) * **deps:** update module buf.build/gen/go/open-feature/flagd/protocolbuffers/go to v1.36.4-20250127221518-be6d1143b690.1 ([#1537](#1537)) ([f74207b](f74207b)) * **deps:** update module github.com/open-feature/flagd/core to v0.10.8 ([#1526](#1526)) ([fbf2ed5](fbf2ed5)) * **deps:** update module google.golang.org/grpc to v1.70.0 ([#1528](#1528)) ([79b2b0a](79b2b0a)) ### ✨ New Features * flagSetMetadata in OFREP/ResolveAll, core refactors ([#1540](#1540)) ([b49abf9](b49abf9)) </details> <details><summary>flagd-proxy: 0.7.0</summary> ## [0.7.0](flagd-proxy/v0.6.11...flagd-proxy/v0.7.0) (2025-01-31) ### ⚠ BREAKING CHANGES * flagSetMetadata in OFREP/ResolveAll, core refactors ([#1540](#1540)) ### 🐛 Bug Fixes * **deps:** update module buf.build/gen/go/open-feature/flagd/grpc/go to v1.5.1-20250127221518-be6d1143b690.2 ([#1536](#1536)) ([e23060f](e23060f)) * **deps:** update module buf.build/gen/go/open-feature/flagd/protocolbuffers/go to v1.36.4-20241220192239-696330adaff0.1 ([#1529](#1529)) ([8881a80](8881a80)) * **deps:** update module buf.build/gen/go/open-feature/flagd/protocolbuffers/go to v1.36.4-20250127221518-be6d1143b690.1 ([#1537](#1537)) ([f74207b](f74207b)) * **deps:** update module github.com/open-feature/flagd/core to v0.10.8 ([#1526](#1526)) ([fbf2ed5](fbf2ed5)) * **deps:** update module google.golang.org/grpc to v1.70.0 ([#1528](#1528)) ([79b2b0a](79b2b0a)) ### ✨ New Features * flagSetMetadata in OFREP/ResolveAll, core refactors ([#1540](#1540)) ([b49abf9](b49abf9)) </details> <details><summary>core: 0.11.0</summary> ## [0.11.0](core/v0.10.8...core/v0.11.0) (2025-01-31) ### ⚠ BREAKING CHANGES * flagSetMetadata in OFREP/ResolveAll, core refactors ([#1540](#1540)) ### 🐛 Bug Fixes * **deps:** update github.com/open-feature/flagd-schemas digest to bb76343 ([#1534](#1534)) ([8303353](8303353)) * **deps:** update golang.org/x/exp digest to 3edf0e9 ([#1538](#1538)) ([7a06567](7a06567)) * **deps:** update golang.org/x/exp digest to e0ece0d ([#1539](#1539)) ([4281c6e](4281c6e)) * **deps:** update module buf.build/gen/go/open-feature/flagd/grpc/go to v1.5.1-20250127221518-be6d1143b690.2 ([#1536](#1536)) ([e23060f](e23060f)) * **deps:** update module buf.build/gen/go/open-feature/flagd/protocolbuffers/go to v1.36.4-20241220192239-696330adaff0.1 ([#1529](#1529)) ([8881a80](8881a80)) * **deps:** update module buf.build/gen/go/open-feature/flagd/protocolbuffers/go to v1.36.4-20250127221518-be6d1143b690.1 ([#1537](#1537)) ([f74207b](f74207b)) * **deps:** update module google.golang.org/grpc to v1.70.0 ([#1528](#1528)) ([79b2b0a](79b2b0a)) ### ✨ New Features * flagSetMetadata in OFREP/ResolveAll, core refactors ([#1540](#1540)) ([b49abf9](b49abf9)) * support yaml in blob, file, and http syncs ([#1522](#1522)) ([76d673a](76d673a)) </details> --- This PR was generated with [Release Please](https://github.com/googleapis/release-please). See [documentation](https://github.com/googleapis/release-please#release-please). Signed-off-by: OpenFeature Bot <[email protected]> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
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.
Better late then never...I just finished reviewing & added a few questions :)
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.
[Q] When running the evaluation proto ResolveAll rpc command the result does not include the added metadata to the Response message. Is this how it should be or would it make sense to include the metadata as well?
The response looks like this:
{
"flags": {
"fibAlgo": {
"reason": "DEFAULT",
"variant": "recursive",
"stringValue": "recursive"
},
"headerColor": {
"reason": "DEFAULT",
"variant": "red",
"stringValue": "#FF0000"
},
"isColorYellow": {
"reason": "TARGETING_MATCH",
"variant": "off",
"boolValue": false
},
"myBoolFlag": {
"reason": "STATIC",
"variant": "on",
"boolValue": true
},
"myFloatFlag": {
"reason": "STATIC",
"variant": "one",
"doubleValue": 1.23
},
...
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 see it when I try - I suspect that the proto files you are pointing to in the command you are running are out of date, and don't have the latest additions of metadata. cd
into the schemas repo and pull it. We only very recently added this field to the proto. Sorry - I should have made sure to mention this in the testing instructions.
The proto files are essentially schemas that tell the unmarshaller how to parse the protobuf binary data; they need to know about every field.
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.
Ah, I see, makes sense! Thanks for explaining :)
@@ -119,15 +119,16 @@ func (je *JSON) SetState(payload sync.DataSync) (map[string]interface{}, bool, e | |||
var events map[string]interface{} | |||
var reSync bool | |||
|
|||
// TODO: We do not handle metadata in ADD/UPDATE operations. These are only relevant for grpc sync implementations. |
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.
[Q] did you miss this TODO or should it rather be a normal comment? reading your comment below the TODO would be to deprecate these cases (ADD/UPDATE/DELETE) for sync impls, or did I misunderstand it?
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.
You are understanding correctly. I left it as a TODO because I wanted to open an issue to discuss the deprecation of these, which I still intend to do.
@@ -156,14 +157,16 @@ func NewResolver(store store.IStore, logger *logger.Logger, jsonEvalTracer trace | |||
return Resolver{store: store, Logger: logger, tracer: jsonEvalTracer} | |||
} | |||
|
|||
func (je *Resolver) ResolveAllValues(ctx context.Context, reqID string, context map[string]any) ([]AnyValue, error) { | |||
func (je *Resolver) ResolveAllValues(ctx context.Context, reqID string, context map[string]any) ([]AnyValue, |
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.
[Q] is this the function that relates to this proto command (from evaluation.proto):
rpc ResolveAll(ResolveAllRequest) returns (ResolveAllResponse) {}
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.
Yes, this is the inner "domain layer" function satisfying that rpc. More directly, this function is the actual rpc endpoint.
} | ||
|
||
for _, test := range tests { | ||
_, _, _, metadata, _ := evaluator.ResolveBooleanValue(context.TODO(), reqID, test.flagKey, 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.
[Q] What does context.TODO() do?
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.
context
in Go is sort of like a very explicit (most things in Go are very explicit) ThreadLocal
in Java, or a continuation in Javascript; it's passed down the entire call chain (at least in cases of good design) and can be used to propagate signals and store data (for example, request data).
context.TODO()
is sort of a "bare" or "root" context often used in testing or at the very start of some call stack.
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 should finish my Go course 😁 I thought it was an OpenFeature context attribute
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.
That's understandable since there's a name collision here. It's not ideal. I try to refer to the OpenFeature one as "EvaluationContext" to disambiguate them.
@@ -303,3 +318,40 @@ func (f *Flags) Merge( | |||
} | |||
return notifications, resyncRequired | |||
} | |||
|
|||
func (f *State) getMetadataForSource(source string) model.Metadata { |
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.
[Q] What does source
represent?
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.
It's a "source" of flags. For example, when you start flagd like this:
flagd start -f file:../config/samples/example_flags.flagd.json -f http://some-domain.com/my-flags.json
you have set 2 sources (one file and one http). These provide flag definitions to flagd, and it will watch them for updates. There are many different styles of sources (syncs) in addition to file and http. See: https://flagd.dev/concepts/syncs/ for the full list.
IStore
interface now returns an additional value representing the flag set metadata. There are no breaking changes in flagd's behavior.Changes in flagd:
To Test
curl
,grpcurl
, andjq
RPC
grpcurl -import-path /...../schemas/protobuf/flagd/evaluation/v1 -proto evaluation.proto -plaintext localhost:8013 flagd.evaluation.v1.Service/ResolveAll | jq
OFREP
Sync