Help us shape the future of Go! Take the 2026 Go Developer Survey

memoryfeature

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Nov 1, 2026 License: MIT Imports: 6 Imported by: 0

README

Arkoren Feature Flag Memory Driver

arkoren.dev/core/service/feature/memoryfeature is an in-process implementation of feature.Driver using only the standard library.

It is suitable for tests, local development, and single-process applications. Use it in application tests instead of a fake: set the flags a test needs, then hand the driver to feature.New.

Using the driver

Run go get arkoren.dev/core in your application's Go module. With your operation context ctx, populate a flag and evaluate it through the facade:

import (
	"arkoren.dev/core/service/feature"
	"arkoren.dev/core/service/feature/memoryfeature"
)

driver := memoryfeature.New()
checkout := feature.NewFlag("new-checkout", false)
err := driver.Set(checkout, true)
flags := feature.New(driver)
on, err := flags.Value(ctx, checkout, feature.Subject{Key: "user-42"})

on is true with a nil error. Unknown flags return the chosen default and feature.ErrNotFound. The driver has no lifecycle hooks, and its state is not persistent or shared between processes.

Each flag has an optional default value and optional overrides for single subject keys. Set creates or replaces the default and keeps the overrides; SetFor adds an override and creates the flag, with no default value, when it is missing; Disable turns a flag off without forgetting it and Enable turns it back on; Delete removes the flag and its overrides. Set and SetFor share the application's immutable feature.Flag[T] definition and accept only values of its Go type, including named primitive types. Unsupported or mismatched types fail to compile. Invalid or zero definitions return feature.ErrInvalidFlag without mutation. The definition's fallback is not installed as a default by SetFor; only evaluation applies it when no value matches. Definitions do not create external provider schemas or remove runtime provider type checks.

Optional feature.NewNamespace(prefix, fallback) joins with ":" by default and returns ordinary flags through Flag(name). Share that same child definition with Set, SetFor, and evaluation; its fallback is inherited exactly, not installed as a stored provider value. Namespaces add no targeting or isolation.

Evaluate answers in this order:

  1. A canceled context fails with the context's error.
  2. An empty or unknown Kind fails with feature.ErrTypeMismatch before lookup.
  3. An unknown key fails with feature.ErrNotFound.
  4. A disabled flag returns no value with ReasonDisabled.
  5. An override for the subject key returns its value with ReasonTargetingMatch.
  6. A default value returns ReasonStatic.
  7. A flag with only overrides, none matching, returns no value with ReasonDefault.

Raw requests accept only KindBool, KindString, KindInt, and KindFloat. Disabled flags and default-only results do not bypass kind validation. Unknown kind strings still round-trip unchanged through JSON and String; this does not make them valid for evaluation. Typed flag definitions retain their separate feature.ErrInvalidFlag validation before driver access.

A stored value that cannot be read as the requested kind fails with feature.ErrTypeMismatch; integers are stored as int64, floats as float64, and an integer read as a float is converted. Subject attributes and anonymous subjects are accepted and ignored: an empty subject key never matches an override.

See the feature flag testing guide and memory driver reference.

Documentation

Overview

Package memoryfeature provides an in-memory feature.Driver for tests, local development, and single-process applications.

Flags are set from code with Driver.Set and Driver.SetFor, switched off with Driver.Disable, and removed with Driver.Delete. Each flag has an optional default value and optional per-subject overrides keyed by feature.Subject.Key. There are no targeting rules or percentage rollouts: attributes are ignored. Raw Evaluate checks cancellation, then rejects an empty or unknown Kind with feature.ErrTypeMismatch before reading any flag. Disabled flags and flags with no matching value do not bypass this validation. Valid kinds are Bool, String, Int, and Float; typed zero definitions remain invalid during setup.

driver := memoryfeature.New()
checkout := feature.NewFlag("new-checkout", false)
if err := driver.Set(checkout, false); err != nil {
	log.Print(err)
	return
}
if err := driver.SetFor(checkout, "user-42", true); err != nil {
	log.Print(err)
	return
}
flags := feature.New(driver)
on, err := flags.Value(ctx, checkout, feature.Subject{Key: "user-42"})
if err != nil {
	log.Print(err) // on is false.
}

The driver is safe for concurrent use and has no Start or Stop.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Driver

type Driver struct {
	// contains filtered or unexported fields
}

Driver implements feature.Driver in process memory. It is safe for concurrent use and needs no Start or Stop.

Values passed to Driver.Set and Driver.SetFor share the exact Go type of a feature.Flag definition. Integers are stored as int64 and floats as float64, including named types. Definitions do not create provider schemas.

driver := memoryfeature.New()
if err := driver.Set(feature.NewFlag("max-upload-mb", 10), 25); err != nil {
	log.Print(err)
}

func New

func New() *Driver

New returns an empty Driver. It starts no background work and requires no lifecycle registration.

Example:

driver := memoryfeature.New()
if err := driver.Set(feature.NewFlag("checkout", false), true); err != nil {
	return err
}

func (*Driver) Delete

func (driver *Driver) Delete(key string)

Delete removes the flag key and its overrides. Deleting a missing key does nothing.

Example: driver.Delete(definition.Name())

func (*Driver) Disable

func (driver *Driver) Disable(key string)

Disable turns key off. The flag stays known, so Evaluate returns no value with feature.ReasonDisabled instead of feature.ErrNotFound. Disabling a missing key does nothing.

Example: driver.Disable(definition.Name())

func (*Driver) Enable

func (driver *Driver) Enable(key string)

Enable undoes Driver.Disable. Enabling a missing key does nothing. Overrides and the stored default are retained while disabled.

Example: driver.Enable(definition.Name())

func (*Driver) Evaluate

func (driver *Driver) Evaluate(ctx context.Context, request feature.Request) (feature.Result, error)

Evaluate implements feature.Driver. A canceled ctx fails with its error, then an empty or unknown request.Kind fails with feature.ErrTypeMismatch before flag lookup. Known kinds are Bool, String, Int, and Float. An unknown key fails with feature.ErrNotFound. A stored value that cannot be read as a known kind fails with feature.ErrTypeMismatch. A disabled flag returns no value with feature.ReasonDisabled; a matching override returns feature.ReasonTargetingMatch; a default value returns feature.ReasonStatic; a flag with only non-matching overrides returns no value with feature.ReasonDefault. Subject attributes are ignored and an empty subject key never matches an override.

Example:

result, err := driver.Evaluate(ctx, feature.Request{Key: "checkout", Kind: feature.KindBool})
if err != nil {
	return err
}
_ = result.Value

func (*Driver) Set

func (driver *Driver) Set[T feature.Primitive](definition feature.Flag[T], value T) error

Set creates definition's provider key or replaces its stored default value, keeping overrides and disabled state. The definition's fallback is not installed: evaluation alone applies it. Invalid definitions return their Err without mutating the driver; value must have the definition's Go type.

checkout := feature.NewFlag("new-checkout", false)
if err := driver.Set(checkout, true); err != nil {
	log.Print(err)
}

func (*Driver) SetFor

func (driver *Driver) SetFor[T feature.Primitive](definition feature.Flag[T], subjectKey string, value T) error

SetFor sets definition's value for the subject whose feature.Subject.Key is subjectKey. It creates the flag, with no default value, when it is missing, and keeps the default of an existing one. Like Set it validates the definition before mutation, and requires its exact Go type. An empty subject key never matches during evaluation.

checkout := feature.NewFlag("new-checkout", false)
if err := driver.SetFor(checkout, "user-42", true); err != nil {
	log.Print(err)
}

Jump to

Keyboard shortcuts

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