Skip to content

Add Hook Data Support #384

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

Open
beeme1mr opened this issue Jun 5, 2025 · 0 comments
Open

Add Hook Data Support #384

beeme1mr opened this issue Jun 5, 2025 · 0 comments
Labels
help wanted Extra attention is needed

Comments

@beeme1mr
Copy link
Member

beeme1mr commented Jun 5, 2025

Summary

The OpenFeature specification now includes support for hook data, which allows hooks to maintain state across their execution stages (before → after/error → finally). This feature enables use cases like distributed tracing, performance monitoring, and multi-stage validation.

This issue tracks the implementation of hook data support in this SDK to achieve compliance with the latest specification.

Action Required

SDK maintainers need to implement hook data support according to the specification defined in:

A reference implementation is available in the .NET SDK PR: open-feature/dotnet-sdk#387

Hook data specification enables stateful hook operations

The OpenFeature hook data specification provides a mechanism for different stages of the same hook to share state during a single flag evaluation. This feature supports implementing telemetry, performance monitoring, and resource management use cases. The .NET SDK's implementation in open-feature/dotnet-sdk#387 demonstrates a successful approach that other SDKs can follow.

Reference Links

Understanding hook data fundamentals

Hook data provides the ability for hooks to maintain state across their execution lifecycle. When a hook starts an operation in the before stage (like opening a telemetry span), it needs a way to access that same data in the after stage to complete the operation. Without hook data, developers resort to workarounds like global state, weak maps, or thread-local storage, which introduce complexity and potential bugs.

The specification defines hook data as a mutable, per-hook, per-evaluation data structure. This scoping means each hook instance gets its own isolated data store that persists only for the duration of a single flag evaluation. Different hooks evaluating the same flag don't share data, preventing interference and ensuring predictable behavior.

Core specification requirements

Data structure and access patterns

Hook data MUST be implemented as a structure supporting arbitrary properties with string keys and values of any type. The structure must be mutable to allow stages to modify shared state. SDKs typically implement this as a map-like interface with set(key, value) and get(key) methods.

The data structure must be created before the first hook stage executes and remain available throughout all stages (before → after/error → finally). This lifecycle management is the SDK's responsibility, not the hook developer's.

Isolation and scoping guarantees

Each hook instance maintains its own hook data - there's no sharing between different hooks. This isolation extends to:

  • Different hook types running for the same evaluation
  • Multiple instances of the same hook type
  • Hooks registered at different levels (global, client, invocation)

The specification explicitly states that hook data is not shared between different hooks, ensuring separation of concerns.

Integration with hook context

Hook data must be accessible through the hook context parameter passed to all hook stages. The typical pattern follows:

context.hookData.set("key", value)  // In before stage
value = context.hookData.get("key") // In after stage

Learning from the .NET SDK implementation

The .NET SDK's PR open-feature/dotnet-sdk#387 provides implementation insights. Their approach enhanced the existing HookContext<T> class with a Data property, maintaining backward compatibility while adding new functionality. Lessons include:

API Design: The implementation uses a simple key-value store pattern that's intuitive for developers. Type safety is handled through casting when retrieving values, following .NET conventions.

No Breaking Changes: Existing hooks continue working without modification. The hook data feature is additive - hooks can opt-in to using it without requiring changes to hooks that don't need state sharing.

Examples: The implementation includes examples like timing hooks that measure execution duration, demonstrating the feature's value to developers.

Implementation roadmap for SDK maintainers

Phase 1: Core implementation

Start by implementing the basic hook data structure with these capabilities:

  • String-keyed storage with any-type values
  • Mutable data access through set/get operations
  • Proper lifecycle management (creation before first stage, cleanup after finally)
  • Thread-safe access for concurrent evaluations

Phase 2: Integration and testing

Integrate hook data with your existing hook infrastructure:

  • Add data property to hook context
  • Ensure data flows through all hook stages
  • Implement isolation between hook instances
  • Create comprehensive test suites covering edge cases

Phase 3: Documentation and examples

Provide guidance for hook developers:

  • API documentation with type signatures
  • Examples (timing, telemetry, validation)
  • Best practices and anti-patterns
  • Migration guide if introducing any changes

Implementation considerations

Memory management

Hook data should be garbage collected after the evaluation completes. Consider implementing weak references or explicit cleanup to prevent memory leaks in long-running applications.

Thread safety

Many applications evaluate flags concurrently. Ensure hook data access is thread-safe without introducing significant performance overhead. Consider using concurrent data structures appropriate for your language.

Type safety

In statically-typed languages, consider providing type-safe access patterns while maintaining the flexibility of arbitrary value storage. Generic methods or type assertions can help balance safety with usability.

Performance impact

Hook data should add minimal overhead to flag evaluations. Consider lazy initialization - only create the data structure when a hook actually uses it. Benchmark the implementation to ensure acceptable performance.

Common use cases to support

OpenTelemetry integration

The canonical use case involves creating spans in the before stage and ending them in after:

// Before stage
Span span = tracer.spanBuilder("feature-flag-evaluation").startSpan();
context.hookData.set("span", span);

// After stage
Span span = (Span) context.hookData.get("span");
span.end();

Performance monitoring

Tracking evaluation duration is a common requirement:

// Before stage
context.Data.Set("startTime", DateTime.UtcNow);

// After stage
var duration = DateTime.UtcNow - (DateTime)context.Data.Get("startTime");
logger.LogInformation($"Evaluation took {duration.TotalMilliseconds}ms");

Multi-stage validation

Complex validation scenarios benefit from accumulating results:

# Before stage
context.hook_data.set("validation_errors", [])

# Multiple validation stages can add errors
errors = context.hook_data.get("validation_errors")
if not is_valid(context):
    errors.append("Validation failed")

# Finally stage checks accumulated errors
if context.hook_data.get("validation_errors"):
    logger.warning(f"Validation issues: {errors}")

Testing requirements

Comprehensive test coverage should include:

  1. Basic functionality: Set and get operations work correctly
  2. Isolation: Data doesn't leak between hook instances
  3. Lifecycle: Data persists through all stages but not beyond
  4. Type handling: Various data types can be stored and retrieved
  5. Edge cases: Null values, missing keys, concurrent access
  6. Performance: Minimal overhead for evaluations not using hook data

Migration and compatibility

When implementing hook data support:

  1. Maintain backward compatibility: Existing hooks must continue working
  2. Version appropriately: Follow semantic versioning based on impact
  3. Provide migration guides: Help developers adopt the new feature
  4. Consider feature flags: Allow gradual rollout of hook data support

Success criteria

A complete hook data implementation should:

  • Pass all specification compliance tests
  • Support the primary use cases (telemetry, monitoring, validation)
  • Add minimal performance overhead
  • Provide good developer experience
  • Include comprehensive documentation
  • Maintain backward compatibility

Conclusion

Hook data provides a feature that enables observability and monitoring capabilities in OpenFeature. By following the specification requirements and learning from successful implementations like the .NET SDK, maintainers can provide consistent, reliable hook data support across all OpenFeature SDKs. The implementation should balance flexibility with safety, performance with functionality, and maintain the isolation guarantees that make hook data predictable and useful.

Additional Resources

@beeme1mr beeme1mr added the help wanted Extra attention is needed label Jun 5, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed
Projects
None yet
Development

No branches or pull requests

1 participant