Conversation
Signed-off-by: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com>
c42ef76 to
d391718
Compare
Signed-off-by: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com>
cb5cabb to
2110b92
Compare
beeme1mr
left a comment
There was a problem hiding this comment.
I like this proposal, but I would like to see how it could be implemented in an SDK. Properly scoping hook data may be complicated.
Co-authored-by: Michael Beemer <beeme1mr@users.noreply.github.com> Signed-off-by: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com>
toddbaert
left a comment
There was a problem hiding this comment.
I definitely support this idea. I left a few comments. My biggest question is how we can define this so it's non-breaking for existing hooks.
Signed-off-by: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com>
c84eebd to
29bc48c
Compare
Signed-off-by: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com>
Signed-off-by: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com>
Signed-off-by: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com>
Signed-off-by: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com>
I should be able to find time to update a OF SDK to demonstrate, but it may take me a bit. It will be a little different now that we added it to hook context, but you can see what we did in the LD SDKs as its own argument: In our case we create the data when we call the hook, and the return is the new data. Which means we can just map it to an array. But, if that was not the case, as it will be in the OF example you instead do this.
Some pseudocode: The hooks are stable for a specific invocation of stages, so you just need an equal sized list of hook data. |
lukas-reining
left a comment
There was a problem hiding this comment.
I like the change and as far as I can see, adding the hook data does not break the old hooks when it is implemented.
Co-authored-by: Lukas Reining <lukas.reining@codecentric.de> Signed-off-by: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com>
Signed-off-by: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com>
Signed-off-by: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com>
I think this was resolved via the pseudocode. |
guidobrei
left a comment
There was a problem hiding this comment.
Not that my approval changes anything, but this proposal looks really promising.
There was a problem hiding this comment.
👍 This has been open for a while. @kinyoklion feel free to merge whenever, and we can do a release.
I'd like to propose additional hardening of the specification soon, and possibly moving this section out of experimental (probably after we've implemented what's outlined in this PR in a few SDKs). When this is merged I'll create a parent issue in the spec and sub issues in each SDK.
<!-- Please use this template for your pull request. --> <!-- Please use the sections that you need and delete other sections --> ## This PR Adds support for hook data. open-feature/spec#273 ### Related Issues <!-- add here the GitHub issue that this PR resolves if applicable --> ### Notes <!-- any additional notes for this PR --> I realized that the 4.6.1 section of the spec wasn't consistent with the expected usage. Basically it over-specifies the typing of the hook data matching that of the evaluation context. That is one possible approach, it would just mean a bit more work on the part of the hook implementers. In the earlier example in the spec I put a `Span` in the hook data: ``` public Optional<EvaluationContext> before(HookContext context, HookHints hints) { SpanBuilder builder = tracer.spanBuilder('sample') .setParent(Context.current().with(Span.current())); Span span = builder.startSpan() context.hookData.set("span", span); } public void after(HookContext context, FlagEvaluationDetails details, HookHints hints) { // Only accessible by this hook for this specific evaluation. Object value = context.hookData.get("span"); if (value instanceof Span) { Span span = (Span) value; span.end(); } } ``` This is only possible if the hook data allows specification of any `object` instead of being limited to the immutable types of a context. For hooks hook data this is safe because only the hook mutating the data will have access to that data. Additionally the execution of the hook will be in sequence with the evaluation (likely in a single thread). The alternative would be to store data in the hook, and use the hook data to know when to remove it. Something like this: ``` public Optional<EvaluationContext> before(HookContext context, HookHints hints) { SpanBuilder builder = tracer.spanBuilder('sample') .setParent(Context.current().with(Span.current())); Span span = builder.startSpan() String storageId = Uuid(); this.tmpData.set(storageId, span); context.hookData.set("span", storageId); } public void after(HookContext context, FlagEvaluationDetails details, HookHints hints) { // Only accessible by this hook for this specific evaluation. Object value = context.hookData.get("span"); if (value) { String id = value.AsString(); Span span= this.tmpData.get(id); span.end(); } } ``` ### Follow-up Tasks <!-- anything that is related to this PR but not done here should be noted under this section --> <!-- if there is a need for a new issue, please link it here --> ### How to test <!-- if applicable, add testing instructions under this section --> --------- Signed-off-by: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com> Co-authored-by: chrfwow <christian.lutnik@dynatrace.com>
<!-- Please use this template for your pull request. --> <!-- Please use the sections that you need and delete other sections --> ## This PR Adds support for hook data. open-feature/spec#273 ### Related Issues <!-- add here the GitHub issue that this PR resolves if applicable --> ### Notes <!-- any additional notes for this PR --> I realized that the 4.6.1 section of the spec wasn't consistent with the expected usage. Basically it over-specifies the typing of the hook data matching that of the evaluation context. That is one possible approach, it would just mean a bit more work on the part of the hook implementers. In the earlier example in the spec I put a `Span` in the hook data: ``` public Optional<EvaluationContext> before(HookContext context, HookHints hints) { SpanBuilder builder = tracer.spanBuilder('sample') .setParent(Context.current().with(Span.current())); Span span = builder.startSpan() context.hookData.set("span", span); } public void after(HookContext context, FlagEvaluationDetails details, HookHints hints) { // Only accessible by this hook for this specific evaluation. Object value = context.hookData.get("span"); if (value instanceof Span) { Span span = (Span) value; span.end(); } } ``` This is only possible if the hook data allows specification of any `object` instead of being limited to the immutable types of a context. For hooks hook data this is safe because only the hook mutating the data will have access to that data. Additionally the execution of the hook will be in sequence with the evaluation (likely in a single thread). The alternative would be to store data in the hook, and use the hook data to know when to remove it. Something like this: ``` public Optional<EvaluationContext> before(HookContext context, HookHints hints) { SpanBuilder builder = tracer.spanBuilder('sample') .setParent(Context.current().with(Span.current())); Span span = builder.startSpan() String storageId = Uuid(); this.tmpData.set(storageId, span); context.hookData.set("span", storageId); } public void after(HookContext context, FlagEvaluationDetails details, HookHints hints) { // Only accessible by this hook for this specific evaluation. Object value = context.hookData.get("span"); if (value) { String id = value.AsString(); Span span= this.tmpData.get(id); span.end(); } } ``` ### Follow-up Tasks <!-- anything that is related to this PR but not done here should be noted under this section --> <!-- if there is a need for a new issue, please link it here --> ### How to test <!-- if applicable, add testing instructions under this section --> --------- Signed-off-by: Ryan Lamb <4955475+kinyoklion@users.noreply.github.com> Co-authored-by: chrfwow <christian.lutnik@dynatrace.com> Signed-off-by: Weihan Li <weihanli@outlook.com>
This PR
Add support for the hook-data concept for hooks. Hook-data allows for per-evaluation data to be propagated between hooks.
This is especially useful for analytics purposes where you may want to measure things that happen between stages, or you want to do something like create a span in one stage and close it in another.
This concept is similar to the
series dataconcept for LaunchDarkly hooks. https://github.com/launchdarkly/open-sdk-specs/tree/main/specs/HOOK-hooks#evaluationseriesdataUnlike
series datathe data in this approach is mutable. This is because thebeforestage already has a return value. We could workaround this by specifying a return structure, but it maybe seems more complex. The data is only passed to a specific hook instance, so mutability is not of great concern.Some functional languages may still need to use an immutable with return values approach.
I can create an OFEP if we think this merits discussion prior to proposal.
Related Issues
Related discussion in a PR comment.
open-feature/java-sdk#1049 (comment)