openfeatureflags

package
v11.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 18, 2026 License: AGPL-3.0 Imports: 8 Imported by: 0

Documentation

Overview

Package openfeatureflags is the flag evaluation both of this module's OpenFeature-backed providers do.

The PostHog and LaunchDarkly managers differ in exactly two places: how they build a vendor client and register it as an OpenFeature provider, and how they close it. Everything between — the context conversion, the breaker protocol, the not-found classification, and the five evaluation methods — goes through *openfeature.Client and is therefore the same code, which is why it had been written twice.

That makes this a different case from the provider families this module deliberately leaves duplicated (see llm/doc.go). Those are two translations to two different vendor APIs, where the shape is shared and the details are the point. This is one implementation against one seam, copied — and the copies had already begun to differ in the error descriptions they returned.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Context

Context converts a featureflags.EvaluationContext into the SDK's own representation. It is the only place a provider crosses the boundary between the platform-owned type and the OpenFeature type.

Types

type Evaluator

type Evaluator struct {
	// O11y is the provider's observer. Exported because the embedding provider
	// builds it — the instrumentation scope is the provider's name, not this
	// package's.
	O11y observability.Observer

	// CircuitBreaker guards every evaluation. Required: a nil one panics on
	// first use rather than silently evaluating unguarded.
	CircuitBreaker circuitbreaking.CircuitBreaker

	// EvalCounter counts evaluations that answered.
	EvalCounter metrics.Int64Counter

	// ErrorCounter counts evaluations that failed for a reason the breaker
	// should hear about.
	ErrorCounter metrics.Int64Counter

	// NotFoundCounter counts evaluations of a flag the provider does not have,
	// which is a correct negative answer rather than a failure.
	NotFoundCounter metrics.Int64Counter

	// LatencyHist records how long an evaluation took, in milliseconds.
	LatencyHist metrics.Float64Histogram

	// Client is the OpenFeature client bound to the provider's domain.
	Client *openfeature.Client

	// Domain is the name the provider registered under, and is what Close
	// detaches.
	Domain string
}

Evaluator evaluates flags through an OpenFeature client, under a circuit breaker, with the instrumentation both providers record.

It is embedded by the provider types rather than held as a field, so their exported surfaces stay the flag-manager interface a caller expects while the implementation lives once.

func (*Evaluator) CanUseFeature

func (e *Evaluator) CanUseFeature(ctx context.Context, feature string, evalCtx featureflags.EvaluationContext) (bool, error)

CanUseFeature returns whether the supplied evaluation context is permitted to use the named feature.

This is the one method here that never reports featureflags.ErrFlagNotFound. A provider's API generally answers false for a boolean flag it does not know, which is indistinguishable from a flag that exists and is off, so the OpenFeature provider skips the found check for booleans rather than call every false a not-found. A caller therefore sees (false, nil) for a flag nobody has created — the same inert answer this package's distinction is there to produce, reached one layer lower. The four typed getters do report it, because a missing key is distinguishable once the flag has a value to be missing.

func (*Evaluator) Detach

func (e *Evaluator) Detach() error

Detach replaces this evaluator's registration with the no-op provider, releasing the vendor client it held.

Each construction registers a uniquely-named provider in OpenFeature's process-global registry, which has no removal API — so without this, every reload cycle left another registration holding a reference to a client that had just been closed, and the process accumulated them until it exited. The (small, clientless) map entry itself is not removable and is left behind.

It is the provider's Close that calls this, because closing the vendor client is the provider's own business.

func (*Evaluator) GetFloat64Value

func (e *Evaluator) GetFloat64Value(ctx context.Context, feature string, defaultValue float64, evalCtx featureflags.EvaluationContext) (float64, error)

GetFloat64Value returns the float value of a feature flag, falling back to defaultValue on error.

func (*Evaluator) GetInt64Value

func (e *Evaluator) GetInt64Value(ctx context.Context, feature string, defaultValue int64, evalCtx featureflags.EvaluationContext) (int64, error)

GetInt64Value returns the integer value of a feature flag, falling back to defaultValue on error.

func (*Evaluator) GetObjectValue

func (e *Evaluator) GetObjectValue(ctx context.Context, feature string, defaultValue any, evalCtx featureflags.EvaluationContext) (any, error)

GetObjectValue returns the object (JSON) value of a feature flag, falling back to defaultValue on error.

func (*Evaluator) GetStringValue

func (e *Evaluator) GetStringValue(ctx context.Context, feature, defaultValue string, evalCtx featureflags.EvaluationContext) (string, error)

GetStringValue returns the string value of a feature flag, falling back to defaultValue on error.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL