Initialize Go SDK
This topic describes how to initialize the Optimizely Feature Experimentation Go SDK in your application.
To initialize the OptimizelyClient that exposes API methods like Decide, you need either the SDK key or a hard-coded JSON datafile.
Basic initialization with SDK Key
import optly "github.com/optimizely/go-sdk"
// Instantiates a client that syncs the datafile in the background
optlyClient, er := optly.Client("SDK_KEY_HERE")
Advanced configuration
Static client instance
If you do not want the client to periodically sync the datafile in the background, you can instantiate a static client. This is useful for using the SDK in short-lived environments, such as Lambda functions. You can use the OptimizelyFactory for these more advanced use cases:
import "github.com/optimizely/go-sdk/pkg/client"
optimizelyFactory := &client.OptimizelyFactory{
Datafile: []byte("DATAFILE_JSON_STRING_HERE"),
}
// Instantiate a static client (no datafile polling)
staticOptlyClient, err := optimizelyFactory.StaticClient()
If you want the SDK to initialize and perform just a one-time remote datafile fetch you can pass in the SDK key instead and instantiate a static client:
import "github.com/optimizely/go-sdk/pkg/client"
optimizelyFactory := &client.OptimizelyFactory{
SDKKey: "[SDK_KEY_HERE]",
}
// Instantiate a static client that will pull down the datafile one time
staticOptlyClient, err := optimizelyFactory.StaticClient()
Custom initialization
You can further customize the top-level components of the SDKs: Event Processor, Config Manager, ODP Manager, Default Decide Options, and Decision Service using the OptimizelyFactory:
import (
"time"
"github.com/optimizely/go-sdk/pkg/client"
)
optimizelyFactory := &client.OptimizelyFactory{
SDKKey: "[SDK_KEY_HERE]",
}
datafilePollingInterval := 2 * time.Second
eventBatchSize := 20
eventQueueSize := 1500
eventFlushInterval := 10 * time.Second
defaultDecideOptions := decide.OptimizelyDecideOptions{
IgnoreUserProfileService: true,
}
// Instantiate a client with custom configuration
optimizelyClient, _ := optimizelyFactory.Client(
client.WithPollingConfigManager(datafilePollingInterval, nil),
client.WithBatchEventProcessor(
eventBatchSize,
eventQueueSize,
eventFlushInterval,
),
client.WithDefaultDecideOptions(defaultDecideOptions),
)
For more details on configuring the event batching please see Event Batching. For more details on configuring default decide options, see Decide methods.
ODPManager
ODPManager
contains all the logic supporting Optimizely Data Platform (ODP)-related features, including audience segments.
Note
Advanced Audience Targeting and audience segments are currently in beta. Contact your Customer Success Manager for more information or register now on Optimizely.com.
ODPSegmentManager
This module provides an interface to the remote ODP server for audience segment mappings.
It fetches all qualified segments for the given user context and returns true
if the qualified segments array in the user context was updated.
It also manages a segment's cache shared for all user contexts. The cache is in memory (not persistent), so it will be reset when the device is rebooted or the app is terminated.
ODPEventManager
This module provides an interface to the remote ODP server for events.
It queues all pending events (persistent) and sends them (in batches of up to 10) to the ODP server when all resources are available, including network connection and ODP public key (in the SDK's datafile).
Note
The Go SDK will try to dispatch all events (stored in a persistent queue and retried on recoverable errors), but completion is not guaranteed.
// You must first enable the Advanced Audience Targeting integration
// before being able to calling ODPApiManager, ODPEventManager, and ODPSegmentManager.
defaultEventApiManager := event.NewEventAPIManager(sdkKey, nil)
odpEventManager := event.NewBatchEventManager(event.WithAPIManager(defaultEventApiManager))
defaultSegmentApiManager := segment.NewSegmentAPIManager(sdkKey, nil)
odpSegmentManager := segment.NewSegmentManager(sdkKey, segment.WithAPIManager(defaultSegmentApiManager))
odpManager := odp.NewOdpManager(sdkKey,
false,
odp.WithEventManager(odpEventManager), // Optional
odp.WithSegmentManager(odpSegmentManager), // Optional
)
Customize EventApiManager
APIManager
is an interface, and its implementation requires the user to provide the functionality of the following methods:
// APIManager represents the event API manager.
type APIManager interface {
SendOdpEvents(apiKey, apiHost string, events []Event) (canRetry bool, err error)
}
Moreover, you can provide eventDispatchTimeout
in the constructor of DefaultEventAPIManager
.
eventDispatchTimeoutMillis := 20000 * time.Millisecond
defaultEventApiManager := event.NewEventAPIManager(sdkKey, utils.NewHTTPRequester(logging.GetLogger(sdkKey, "EventAPIManager"), utils.Timeout(eventDispatchTimeoutMillis)))
Customize SegmentAPIManager
APIManager
is an interface, and its implementation requires the user to provide the functionality of the following methods:
// APIManager represents the segment API manager.
type APIManager interface {
FetchQualifiedSegments(apiKey, apiHost, userID string, segmentsToCheck []string) ([]string, error)
}
Moreover, you can provide segmentFetchTimeoutMillis
in the constructor of DefaultSegmentAPIManager
.
segmentFetchTimeoutMillis := 20000 * time.Millisecond
defaultSegmentApiManager := segment.NewSegmentAPIManager(sdkKey, utils.NewHTTPRequester(logging.GetLogger(sdkKey, "SegmentAPIManager"), utils.Timeout(segmentFetchTimeoutMillis)))
Customize ODPEventManager
You can provide custom queueSize
and flushInterval
(if set to zero, then batchSize
will be set to 1; otherwise, batchSize
will be the default, 10, in the constructor).
queueSize := 20000
// Note: if this is set to 0 then batchSize will be set to 1, otherwise batchSize will be default, which is 10.
flushIntervalInMillis := 10000 * time.Millisecond // 10,000 msecs = 10 secs
odpEventManager := event.NewBatchEventManager(
event.WithAPIManager(defaultEventApiManager),
event.WithQueueSize(queueSize),
event.WithFlushInterval(flushIntervalInMillis),
)
Customize ODPSegmentManager
You can provide cacheSize
and cacheTimeout
in the constructor, but these values will be ignored if the user provides a custom cache in ODPManager
. By default, SegmentManager
is using LRUCache
.
cacheSize := 600
cacheTimeoutInSeconds := 600 * time.Second // 10 mins = 600 secs
odpSegmentManager := segment.NewSegmentManager(
sdkKey,
segment.WithAPIManager(defaultSegmentApiManager),
segment.WithSegmentsCacheSize(cacheSize),
segment.WithSegmentsCacheTimeout(cacheTimeoutInSeconds),
)
// Second method to set custom cache size and timeout using odpManager
odpManager := odp.NewOdpManager(
sdkKey, false,
odp.WithSegmentsCacheSize(cacheSize),
odp.WithSegmentsCacheTimeout(cacheTimeoutInSeconds),
)
Custom cache:
You can use the custom cache, which will be used in storing the FetchQualifiedSegments
results. To provide a custom cache, you have to implement the Cache
interface.
// Cache is used for caching ODP segments
type Cache interface {
Save(key string, value interface{})
Lookup(key string) interface{}
Reset()
}
Here is an example of customCache implementation:
type CustomSegmentsCache struct {
Cache map[string]interface{}
lock sync.Mutex
}
func (c *CustomSegmentsCache) Save(key string, value interface{}) {
c.lock.Lock()
defer c.lock.Unlock()
c.Cache[key] = value
}
func (c *CustomSegmentsCache) Lookup(key string) interface{} {
c.lock.Lock()
defer c.lock.Unlock()
return c.Cache[key]
}
func (c *CustomSegmentsCache) Reset() {
c.lock.Lock()
defer c.lock.Unlock()
c.Cache = map[string]interface{}{}
}
Pass this customCache
object to OdpManager
using its builder option and do not pass SegmentManager
object:
customCache := &CustomSegmentsCache{
Cache: map[string]interface{}{},
}
// Note: To use custom Cache user should not pass SegmentManager
odpManager = odp.NewOdpManager(
sdkKey,
false,
odp.WithSegmentsCache(customCache),
)
Use authenticated datafile in secure environment
Note
Authenticated datafiles are in beta. Contact your Customer Success Manager if you are interested in becoming an early user of authenticated datafiles as part of the beta secure environment feature.
You can fetch the Optimizely Feature Experimentation datafile from an authenticated endpoint using a server-side (only) Optimizely Feature Experimentation SDK. To use an authenticated datafile, download your environment's access token from the Optimizely app in Settings > Environments. Select your secure environment, and copy the Datafile access token. The example below shows how to initialize the Optimizely client using an access token and sdk_key, enabling the client to fetch the authenticated datafile and complete initialization.
// fetch the datafile from an authenticated endpoint
accessToken := `<YOUR_DATAFILE_ACCESS_TOKEN>`
sdkKey := `<YOUR_SDK_KEY>`
factory := client.OptimizelyFactory{SDKKey: sdkKey}
optimizelyClient, err := factory.Client(client.WithDatafileAccessToken(accessToken))
// fetch the datafile from an authenticated endpoint
accessToken := `<YOUR_DATAFILE_ACCESS_TOKEN>`
sdkKey := `<YOUR_SDK_KEY>`
factory := client.OptimizelyFactory{SDKKey: sdkKey}
optimizelyClient, err := factory.Client(client.WithDatafileAccessToken(accessToken))
Updated 3 days ago