Skip to content
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

Hook ordering & state #40

Closed
Tracked by #42
justinabrahms opened this issue Apr 26, 2022 · 5 comments
Closed
Tracked by #42

Hook ordering & state #40

justinabrahms opened this issue Apr 26, 2022 · 5 comments
Labels
architecture Architecture or specification related

Comments

@justinabrahms
Copy link
Member

We need to have a concept of hook ordering. In our case, we have a client hook EmitMetrics. Sometimes, devs don't want to emit metrics, so we want to selectively overwrite it.

client.registerHook(EmitMetrics())

client.getBooleanValues('key', defaultValue) # This emits metrics

client.getBooleanValues('key', defaultValue, FlagOptions(DONT_EMIT_METRICS)) # This doesnt emit metrics.

We're thinking that we'll build this like:

class EmitMetrics:
  def after(ctx, details):
    if not ctx.state['dont-emit-metrics']:
      emitMetrics()

class DONT_EMIT_METRICS:
  def before(ctx):
    ctx.state['dont-emit-metrics'] = True

This means we'll need precise control around when hooks run (with associated APIs to insert at specific ordering) as well as a change to HookContext to hold some state.

@toddbaert
Copy link
Member

toddbaert commented Apr 27, 2022

I think well-defined ordering is certainly a good idea, likely a necessity. I created a stub markdown file for hooks in the spec: specification/flag-evaluation/hooks.md. We should mention that topic when we flesh it out.

I'm less sure about storing arbitrary state on the HookContext. It might be the right approach, but I also am wary of encouraging dependencies between hooks that way. It could be a footgun.

In the sample OTel Hook, we used a private WeakMap member (Java has this concept too: https://docs.oracle.com/javase/7/docs/api/java/util/WeakHashMap.html) to store state, using the Hook Context object reference itself as the key (since the reference doesnt change across flag evaluation, the before, after, etc stages can access the same state). This means that only the OTel hook can access this map, and so only it can modify state stored in this map having to do with it's OTel related logic, maintaining good separation of concerns. Another nice aspect of this pattern is that when the HookContext is garbage collected the values it indexes in the WeakMap are as well.

Do you think this pattern would satisfy your use-case @justinabrahms ?

@toddbaert toddbaert added the architecture Architecture or specification related label Apr 27, 2022
@justinabrahms
Copy link
Member Author

Without passing state, I'm not clear how we could represent:

I want this hook to do the thing it does on every invocation... except this one in particular.

The other thing we've talked about is having users put some sentinel values within the evaluation context, which feels super gross.

Maybe we have some immutable state that's included on FlagEvaluationOptions when the user kicks off the request?

@toddbaert
Copy link
Member

toddbaert commented Apr 27, 2022

The other thing we've talked about is having users put some sentinel values within the evaluation context, which feels super gross.

Very gross, I couldn't agree more on that. It actually even caused bugs in some vendor SDKs in my JS experimentation, because of circular references that broke JSON parsing (presumably to build an HTTP POST body).

I want this hook to do the thing it does on every invocation... except this one in particular.

Ya, I think that's certainly valid, I'm just not sure about doing it with "side-effects" between hooks.

Maybe we have some immutable state that's included on FlagEvaluationOptions when the user kicks off the request?

I think this is a really good solution, and a perfect use of FlagEvaluationOptions, which is pretty bare at the moment.

I should add, I'm not 100% opposed to the mutable state between hooks, I just suspect it's something we should avoid if possible. I could be wrong though 🤷 .

@toddbaert toddbaert mentioned this issue Apr 28, 2022
5 tasks
@toddbaert
Copy link
Member

toddbaert commented May 2, 2022

Addressed by #45. Once that's merged we can likely close this.

@beeme1mr
Copy link
Member

Addressed by hook hints

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
architecture Architecture or specification related
Projects
None yet
Development

No branches or pull requests

4 participants