Skip to main content

Assignments

Assignments are the mechanism through which a given Subject is assigned to a variation for a feature flag or experiment.

The Eppo SDK supports the following assignment types:

  • String
  • Boolean
  • JSON
  • Integer
  • Float

Assignment Types

String Assignments

String assignments return a string value that is set as the variation. String flags are the most common type of flags and are useful for both A/B/n tests and advanced targeting use cases.

import (
"github.com/eppo-exp/golang-sdk/v6/eppoclient"
)

subjectAttributes := map[string]interface{}{
"country": user.Country,
"age": 30,
}

variation, err := client.GetStringAssignment(
"flag-key-123",
user.ID,
subjectAttributes,
"control",
)
if err != nil {
log.Printf("Error getting assignment: %v", err)
return
}

switch variation {
case "version-a":
handleVersionA()
case "version-b":
handleVersionB()
default:
handleControl()
}

Boolean Assignments

Boolean flags support simple on/off toggles. They're useful for simple, binary feature switches like blue/green deployments or enabling/disabling a new feature.

enabled, err := client.GetBooleanAssignment(
"new-feature",
user.ID,
subjectAttributes,
false, // default value
)
if err != nil {
log.Printf("Error getting assignment: %v", err)
return
}

if enabled {
handleFeatureEnabled()
} else {
handleFeatureDisabled()
}

JSON Assignments

JSON flags work best for advanced configuration use cases. The JSON flag can include structured information such as:

  • Marketing copy for a promotional campaign
  • Configuration parameters for a feature
  • UI customization settings
defaultCampaign := map[string]interface{}{
"hero": false,
"hero_image": "placeholder.png",
"hero_title": "Placeholder Hero Title",
"hero_description": "Placeholder Hero Description",
}

campaignConfig, err := client.GetJSONAssignment(
"campaign-config",
user.ID,
subjectAttributes,
defaultCampaign,
)
if err != nil {
log.Printf("Error getting assignment: %v", err)
return
}

// You can also get the raw JSON bytes
campaignBytes, err := client.GetJSONBytesAssignment(
"campaign-config",
user.ID,
subjectAttributes,
defaultCampaignBytes,
)

Numeric Assignments

The SDK provides both integer and floating-point numeric assignments. These are useful for testing different numeric values like:

  • Price points
  • Number of items to display
  • Timeout durations
// Integer assignment
numItems, err := client.GetIntegerAssignment(
"items-to-show",
user.ID,
subjectAttributes,
10, // default value
)

// Float assignment
price, err := client.GetNumericAssignment(
"price-test",
user.ID,
subjectAttributes,
9.99, // default value
)

Assignment Logging

The SDK will invoke an assignment logger function if it is available when the assignment is made. This function will send the assignment to your storage system.

Assignment Logger Schema

The SDK will invoke the LogAssignment method with an AssignmentEvent struct that contains the following fields:

TimestampstringDefault: ""

The time when the subject was assigned to the variation in ISO format. Example: "2021-06-22T17:35:12.000Z"

FeatureFlagstringDefault: ""

An Eppo feature flag key. Example: "recommendation-algo"

AllocationstringDefault: ""

An Eppo allocation key. Example: "allocation-17"

ExperimentstringDefault: ""

An Eppo experiment key. Example: "recommendation-algo-allocation-17"

SubjectstringDefault: ""

An identifier of the subject or user assigned to the experiment variation. Example: UUID

SubjectAttributesmap[string]interface{}Default: nil

A map of metadata about the subject. These attributes are only logged if passed to the SDK assignment function. Example: {"country": "US"}

VariationstringDefault: ""

The experiment variation the subject was assigned to. Example: "control"

MetaDatamap[string]stringDefault: {}

A map of key-value pairs that allows you to attach custom metadata to the assignment event. This metadata is logged alongside the assignment event and can be used for additional context or filtering in analytics.

ExtraLoggingmap[string]stringDefault: {}

An optional map of key-value pairs for additional logging information that doesn't fit into the standard metadata category. This field can be used for debugging, temporary logging needs, or specialized tracking without affecting the core assignment data.

Logging to Your Data Warehouse

Eppo's architecture ensures that raw user data never leaves your system. Instead of pushing subject-level exposure events to Eppo's servers, Eppo's SDKs integrate with your existing logging system.

Here are examples of implementing the IAssignmentLogger interface for different logging systems:

type ConsoleLogger struct{}

func (l *ConsoleLogger) LogAssignment(event eppoclient.AssignmentEvent) error {
log.Printf("Assignment: %+v", event)
return nil
}

Deduplicating Logs

The SDK can encounter a large number of duplicate assignments over a short period of time. If you have a logging function, the SDK will send the same assignment to your storage system multiple times. This increases the cost storage and bloat analysis costs for no additional benefit.

Solve this problem by using the in-memory assigment cache with an expiration based on the least recently accessed time.

You can configure caching individually for assignment logs and bandit action logs using LruAssignmentLogger and LruBanditLogger respectively. Both loggers are configured with a maximum size to fit your desired memory allocation.

type CachingLogger struct {
wrapped eppoclient.IAssignmentLogger
cache *lru.Cache
}

func NewCachingLogger(wrapped eppoclient.IAssignmentLogger) *CachingLogger {
cache, _ := lru.New(1024)
return &CachingLogger{
wrapped: wrapped,
cache: cache,
}
}

func (l *CachingLogger) LogAssignment(event eppoclient.AssignmentEvent) error {
cacheKey := fmt.Sprintf("%s-%s", event.Subject, event.FeatureFlag)
if _, exists := l.cache.Get(cacheKey); exists {
return nil
}

err := l.wrapped.LogAssignment(event)
if err == nil {
l.cache.Add(cacheKey, true)
}
return err
}