Documentation ¶
Overview ¶
Package unleash is a client library for connecting to an Unleash feature toggle server.
See https://github.com/Unleash/unleash for more information.
Basics ¶
The API is very simple. The main functions of interest are Initialize and IsEnabled. Calling Initialize will create a default client and if a listener is supplied, it will start the sync loop. Internally the client consists of two components. The first is the repository which runs in a separate Go routine and polls the server to get the latest feature toggles. Once the feature toggles are fetched, they are stored by sending the data to an instance of the Storage interface which is responsible for storing the data both in memory and also persisting it somewhere. The second component is the metrics component which is responsible for tracking how often features were queried and whether or not they were enabled. The metrics components also runs in a separate Go routine and will occasionally upload the latest metrics to the Unleash server. The client struct creates a set of channels that it passes to both of the above components and it uses those for communicating asynchronously. It is important to ensure that these channels get regularly drained to avoid blocking those Go routines. There are two ways this can be done.
Using the Listener Interfaces ¶
The first and perhaps simplest way to "drive" the synchronization loop in the client is to provide a type that implements one or more of the listener interfaces. There are 3 interfaces and you can choose which ones you should implement:
- ErrorListener
- RepositoryListener
- MetricsListener
If you are only interesting in tracking errors and warnings and don't care about any of the other signals, then you only need to implement the ErrorListener and pass this instance to WithListener(). The DebugListener shows an example of implementing all of the listeners in a single type.
Reading the channels directly ¶
If you would prefer to have control over draining the channels yourself, then you must not call WithListener(). Instead, you should read all of the channels continuously inside a select. The WithInstance example shows how to do this. Note that all channels must be drained, even if you are not interested in the result.
Examples ¶
The following examples show how to use the client in different scenarios.
Example (CustomStrategy) ¶
ExampleCustomStrategy demonstrates using a custom strategy.
package main import ( "fmt" "github.com/Unleash/unleash-client-go/v3" "github.com/Unleash/unleash-client-go/v3/context" "strings" "time" ) type ActiveForUserWithEmailStrategy struct{} func (s ActiveForUserWithEmailStrategy) Name() string { return "ActiveForUserWithEmail" } func (s ActiveForUserWithEmailStrategy) IsEnabled(params map[string]interface{}, ctx *context.Context) bool { if ctx == nil { return false } value, found := params["emails"] if !found { return false } emails, ok := value.(string) if !ok { return false } for _, e := range strings.Split(emails, ",") { if e == ctx.Properties["emails"] { return true } } return false } // ExampleCustomStrategy demonstrates using a custom strategy. func main() { unleash.Initialize( unleash.WithListener(&unleash.DebugListener{}), unleash.WithAppName("my-application"), unleash.WithUrl("https://unleash.herokuapp.com/api/"), unleash.WithRefreshInterval(5*time.Second), unleash.WithMetricsInterval(5*time.Second), unleash.WithStrategies(&ActiveForUserWithEmailStrategy{}), ) ctx := context.Context{ Properties: map[string]string{ "emails": "example@example.com", }, } timer := time.NewTimer(1 * time.Second) for { <-timer.C enabled := unleash.IsEnabled("unleash.me", unleash.WithContext(ctx)) fmt.Printf("feature is enabled? %v\n", enabled) timer.Reset(1 * time.Second) } }
Output:
Example (FallbackFunc) ¶
ExampleFallbackFunc demonstrates how to specify a fallback function.
package main import ( "fmt" "github.com/Unleash/unleash-client-go/v3" "github.com/Unleash/unleash-client-go/v3/context" "time" ) const MissingFeature = "does_not_exist" // ExampleFallbackFunc demonstrates how to specify a fallback function. func main() { unleash.Initialize( unleash.WithListener(&unleash.DebugListener{}), unleash.WithAppName("my-application"), unleash.WithUrl("http://unleash.herokuapp.com/api/"), ) fallback := func(feature string, ctx *context.Context) bool { return feature == MissingFeature } timer := time.NewTimer(1 * time.Second) for { <-timer.C isEnabled := unleash.IsEnabled(MissingFeature, unleash.WithFallbackFunc(fallback)) fmt.Printf("'%s' enabled? %v\n", PropertyName, isEnabled) timer.Reset(1 * time.Second) } }
Output:
Example (SimpleUsage) ¶
ExampleSimpleUsage demonstrates the simplest way to use the unleash client.
package main import ( "fmt" "github.com/Unleash/unleash-client-go/v3" "time" ) const PropertyName = "eid.enabled" // ExampleSimpleUsage demonstrates the simplest way to use the unleash client. func main() { unleash.Initialize( unleash.WithListener(&unleash.DebugListener{}), unleash.WithAppName("my-application"), unleash.WithUrl("http://unleash.herokuapp.com/api/"), ) timer := time.NewTimer(1 * time.Second) for { <-timer.C fmt.Printf("'%s' enabled? %v\n", PropertyName, unleash.IsEnabled(PropertyName)) timer.Reset(1 * time.Second) } }
Output:
Example (WithInstance) ¶
ExampleWithInstance demonstrates how to create the client manually instead of using the default client. It also shows how to run the event loop manually.
package main import ( "fmt" "github.com/Unleash/unleash-client-go/v3" "time" ) // Sync runs the client event loop. All of the channels must be read to avoid blocking the // client. func Sync(client *unleash.Client) { timer := time.NewTimer(1 * time.Second) for { select { case e := <-client.Errors(): fmt.Printf("ERROR: %v\n", e) case w := <-client.Warnings(): fmt.Printf("WARNING: %v\n", w) case <-client.Ready(): fmt.Printf("READY\n") case m := <-client.Count(): fmt.Printf("COUNT: %+v\n", m) case md := <-client.Sent(): fmt.Printf("SENT: %+v\n", md) case cd := <-client.Registered(): fmt.Printf("REGISTERED: %+v\n", cd) case <-timer.C: fmt.Printf("ISENABLED: %v\n", client.IsEnabled("eid.enabled")) timer.Reset(1 * time.Second) } } } // ExampleWithInstance demonstrates how to create the client manually instead of using the default client. // It also shows how to run the event loop manually. func main() { // Create the client with the desired options client, err := unleash.NewClient( unleash.WithAppName("my-application"), unleash.WithUrl("http://unleash.herokuapp.com/api/"), ) if err != nil { fmt.Printf("ERROR: Starting client: %v", err) return } Sync(client) }
Output:
Index ¶
- Variables
- func Close() error
- func GetVariant(feature string, options ...VariantOption) *api.Variant
- func Initialize(options ...ConfigOption) (err error)
- func IsEnabled(feature string, options ...FeatureOption) bool
- func WaitForReady()
- type BootstrapStorage
- func (bs *BootstrapStorage) Get(key string) (interface{}, bool)
- func (bs *BootstrapStorage) Init(backupPath string, appName string)
- func (bs *BootstrapStorage) List() []interface{}
- func (bs *BootstrapStorage) Load() error
- func (bs *BootstrapStorage) Persist() error
- func (bs *BootstrapStorage) Reset(data map[string]interface{}, persist bool) error
- type Client
- func (uc *Client) Close() error
- func (uc *Client) Count() <-chan metric
- func (uc *Client) Errors() <-chan error
- func (uc *Client) GetVariant(feature string, options ...VariantOption) *api.Variant
- func (uc *Client) IsEnabled(feature string, options ...FeatureOption) (enabled bool)
- func (uc *Client) ListFeatures() []api.Feature
- func (uc *Client) Ready() <-chan bool
- func (uc *Client) Registered() <-chan ClientData
- func (uc *Client) Sent() <-chan MetricsData
- func (uc *Client) WaitForReady()
- func (uc *Client) Warnings() <-chan error
- type ClientData
- type ConfigOption
- func WithAppName(appName string) ConfigOption
- func WithBackupPath(backupPath string) ConfigOption
- func WithCustomHeaders(headers http.Header) ConfigOption
- func WithDisableMetrics(disableMetrics bool) ConfigOption
- func WithEnvironment(env string) ConfigOption
- func WithHttpClient(client *http.Client) ConfigOption
- func WithInstanceId(instanceId string) ConfigOption
- func WithListener(listener interface{}) ConfigOption
- func WithMetricsInterval(metricsInterval time.Duration) ConfigOption
- func WithProjectName(projectName string) ConfigOption
- func WithRefreshInterval(refreshInterval time.Duration) ConfigOption
- func WithStorage(storage Storage) ConfigOption
- func WithStrategies(strategies ...strategy.Strategy) ConfigOption
- func WithUrl(url string) ConfigOption
- type DebugListener
- type DefaultStorage
- func (ds DefaultStorage) Get(key string) (interface{}, bool)
- func (ds *DefaultStorage) Init(backupPath, appName string)
- func (ds *DefaultStorage) List() []interface{}
- func (ds *DefaultStorage) Load() error
- func (ds *DefaultStorage) Persist() error
- func (ds *DefaultStorage) Reset(data map[string]interface{}, persist bool) error
- type ErrorListener
- type FallbackFunc
- type FeatureOption
- type FeatureResolver
- type MetricListener
- type MetricsData
- type MockedListener
- type NoopListener
- type RepositoryListener
- type Storage
- type VariantFallbackFunc
- type VariantOption
- type WarnOnce
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var SEGMENT_CLIENT_SPEC_VERSION = "4.3.1"
Functions ¶
func GetVariant ¶ added in v3.2.0
func GetVariant(feature string, options ...VariantOption) *api.Variant
func Initialize ¶
func Initialize(options ...ConfigOption) (err error)
Initialize will specify the options to be used by the default client.
func IsEnabled ¶
func IsEnabled(feature string, options ...FeatureOption) bool
IsEnabled queries the default client whether or not the specified feature is enabled or not.
func WaitForReady ¶
func WaitForReady()
WaitForReady will block until the default client is ready or return immediately.
Types ¶
type BootstrapStorage ¶ added in v3.4.0
func (*BootstrapStorage) Get ¶ added in v3.4.0
func (bs *BootstrapStorage) Get(key string) (interface{}, bool)
func (*BootstrapStorage) Init ¶ added in v3.4.0
func (bs *BootstrapStorage) Init(backupPath string, appName string)
func (*BootstrapStorage) List ¶ added in v3.4.0
func (bs *BootstrapStorage) List() []interface{}
func (*BootstrapStorage) Load ¶ added in v3.4.0
func (bs *BootstrapStorage) Load() error
func (*BootstrapStorage) Persist ¶ added in v3.4.0
func (bs *BootstrapStorage) Persist() error
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client is a structure representing an API client of an Unleash server.
func NewClient ¶
func NewClient(options ...ConfigOption) (*Client, error)
NewClient creates a new client instance with the given options.
func (*Client) Count ¶
func (uc *Client) Count() <-chan metric
Count returns the count channel which gives an update when a toggle has been queried.
func (*Client) GetVariant ¶ added in v3.2.0
func (uc *Client) GetVariant(feature string, options ...VariantOption) *api.Variant
GetVariant queries a variant as the specified feature is enabled.
It is safe to call this method from multiple goroutines concurrently.
func (*Client) IsEnabled ¶
func (uc *Client) IsEnabled(feature string, options ...FeatureOption) (enabled bool)
IsEnabled queries whether the specified feature is enabled or not.
It is safe to call this method from multiple goroutines concurrently.
func (*Client) ListFeatures ¶ added in v3.2.0
ListFeatures returns all available features toggles.
func (*Client) Ready ¶
Ready returns the ready channel for the client. A value will be available on the channel when the feature toggles have been loaded from the Unleash server.
func (*Client) Registered ¶
func (uc *Client) Registered() <-chan ClientData
Registered returns the registered signal indicating that the client has successfully connected to the metrics service.
func (*Client) Sent ¶
func (uc *Client) Sent() <-chan MetricsData
Sent returns the sent channel which receives data whenever the client has successfully sent metrics to the metrics service.
func (*Client) WaitForReady ¶
func (uc *Client) WaitForReady()
WaitForReady will block until the client has loaded the feature toggles from the Unleash server. It will return immediately if the toggles have already been loaded,
It is safe to call this method from multiple goroutines concurrently.
type ClientData ¶
type ClientData struct { // AppName is the name of the application. AppName string `json:"appName"` // InstanceID is the instance identifier. InstanceID string `json:"instanceId"` // Optional field that describes the sdk version (name:version) SDKVersion string `json:"sdkVersion"` // Strategies is a list of names of the strategies supported by the client. Strategies []string `json:"strategies"` // Started indicates the time at which the client was created. Started time.Time `json:"started"` // Interval specifies the time interval (in ms) that the client is using for refreshing // feature toggles. Interval int64 `json:"interval"` }
ClientData represents the data sent to the unleash during registration.
type ConfigOption ¶
type ConfigOption func(*configOption)
ConfigOption represents a option for configuring the client.
func WithAppName ¶
func WithAppName(appName string) ConfigOption
WithAppName specifies the name of the application.
func WithBackupPath ¶
func WithBackupPath(backupPath string) ConfigOption
WithBackupPath specifies the path that is passed to the storage implementation for storing the feature toggles locally.
func WithCustomHeaders ¶
func WithCustomHeaders(headers http.Header) ConfigOption
WithCustomHeaders specifies any custom headers that should be sent along with requests to the server.
func WithDisableMetrics ¶
func WithDisableMetrics(disableMetrics bool) ConfigOption
WithDisableMetrics specifies that the client should not log metrics to the unleash server.
func WithEnvironment ¶ added in v3.1.0
func WithEnvironment(env string) ConfigOption
WithEnvironment specifies the environment
func WithHttpClient ¶
func WithHttpClient(client *http.Client) ConfigOption
WithHttpClient specifies which HttpClient the client should use for making requests to the server.
func WithInstanceId ¶
func WithInstanceId(instanceId string) ConfigOption
WithInstanceId specifies the instance identifier of the current instance. If not provided, one will be generated based on various parameters such as current user and hostname.
func WithListener ¶
func WithListener(listener interface{}) ConfigOption
WithListener allows users to register a type that implements one or more of the listener interfaces. If no listener is registered then the user is responsible for draining the various channels on the client. Failure to do so will stop the client from working as the worker routines will be blocked.
func WithMetricsInterval ¶
func WithMetricsInterval(metricsInterval time.Duration) ConfigOption
WithMetricsInterval specifies the time interval with which the client should upload the metrics data to the unleash server (default 60s).
func WithProjectName ¶ added in v3.2.0
func WithProjectName(projectName string) ConfigOption
WithProjectName defines a projectName on the config object and is used to filter toggles by project name.
func WithRefreshInterval ¶
func WithRefreshInterval(refreshInterval time.Duration) ConfigOption
WithRefreshInterval specifies the time interval with which the client should sync the feature toggles from the unleash server (default 15s).
func WithStorage ¶
func WithStorage(storage Storage) ConfigOption
WithStorage specifies which storage implementation the repository should use for storing feature toggles.
func WithStrategies ¶
func WithStrategies(strategies ...strategy.Strategy) ConfigOption
WithStrategies specifies which strategies (in addition to the defaults) should be used by the client.
func WithUrl ¶
func WithUrl(url string) ConfigOption
WithUrl specifies the url of the unleash server the user is connecting to.
type DebugListener ¶
type DebugListener struct{}
DebugListener is an implementation of all of the listener interfaces that simply logs debug info to stdout. It is meant for debugging purposes and an example of implementing the listener interfaces.
func (DebugListener) OnCount ¶
func (l DebugListener) OnCount(name string, enabled bool)
OnCount prints to the console when the feature is queried.
func (DebugListener) OnReady ¶
func (l DebugListener) OnReady()
OnReady prints to the console when the repository is ready.
func (DebugListener) OnRegistered ¶
func (l DebugListener) OnRegistered(payload ClientData)
OnRegistered prints to the console when the client has registered.
func (DebugListener) OnSent ¶
func (l DebugListener) OnSent(payload MetricsData)
OnSent prints to the console when the server has uploaded metrics.
func (DebugListener) OnWarning ¶
func (l DebugListener) OnWarning(warning error)
OnWarning prints out warning.
type DefaultStorage ¶ added in v3.2.0
type DefaultStorage struct {
// contains filtered or unexported fields
}
DefaultStorage is a default Storage implementation.
func (DefaultStorage) Get ¶ added in v3.2.0
func (ds DefaultStorage) Get(key string) (interface{}, bool)
func (*DefaultStorage) Init ¶ added in v3.2.0
func (ds *DefaultStorage) Init(backupPath, appName string)
func (*DefaultStorage) List ¶ added in v3.2.0
func (ds *DefaultStorage) List() []interface{}
func (*DefaultStorage) Load ¶ added in v3.2.0
func (ds *DefaultStorage) Load() error
func (*DefaultStorage) Persist ¶ added in v3.2.0
func (ds *DefaultStorage) Persist() error
type ErrorListener ¶
type ErrorListener interface { // OnError is called whenever the client experiences an error. OnError(error) // OnWarning is called whenever the client experiences a warning. OnWarning(error) }
ErrorListener defines an interface that be implemented in order to receive errors and warnings from the client.
type FallbackFunc ¶ added in v3.1.0
FallbackFunc represents a function to be called if the feature is not found.
type FeatureOption ¶
type FeatureOption func(*featureOption)
FeatureOption provides options for querying if a feature is enabled or not.
func WithContext ¶
func WithContext(ctx context.Context) FeatureOption
WithContext allows the user to provide a context that will be passed into the active strategy for determining if a specified feature should be enabled or not.
func WithFallback ¶
func WithFallback(fallback bool) FeatureOption
WithFallback specifies what the value should be if the feature toggle is not found on the unleash service.
func WithFallbackFunc ¶ added in v3.1.0
func WithFallbackFunc(fallback FallbackFunc) FeatureOption
WithFallbackFunc specifies a fallback function to evaluate a feature toggle in the event that it is not found on the service.
func WithResolver ¶ added in v3.7.0
func WithResolver(resolver FeatureResolver) FeatureOption
WithResolver allows you to bypass the repository when resolving a feature name to its actual instance.
type FeatureResolver ¶ added in v3.7.0
FeatureResolver represents a function to be called to resolve the feature instead of using the repository
type MetricListener ¶
type MetricListener interface { // OnCount is called whenever the specified feature is queried. OnCount(string, bool) // OnSent is called whenever the server has successfully sent metrics to the server. OnSent(MetricsData) // OnRegistered is called whenever the client has successfully registered with the metrics server. OnRegistered(ClientData) }
MetricListener defines an interface that can be implemented in order to receive events that are relevant to sending metrics.
type MetricsData ¶
type MetricsData struct { // AppName is the name of the application. AppName string `json:"appName"` // InstanceID is the instance identifier. InstanceID string `json:"instanceId"` // Bucket is the payload data sent to the server. Bucket api.Bucket `json:"bucket"` }
MetricsData represents the data sent to the unleash server.
type MockedListener ¶ added in v3.7.2
func (*MockedListener) OnCount ¶ added in v3.7.2
func (l *MockedListener) OnCount(name string, enabled bool)
func (*MockedListener) OnError ¶ added in v3.7.2
func (l *MockedListener) OnError(err error)
func (*MockedListener) OnReady ¶ added in v3.7.2
func (l *MockedListener) OnReady()
func (*MockedListener) OnRegistered ¶ added in v3.7.2
func (l *MockedListener) OnRegistered(payload ClientData)
func (*MockedListener) OnSent ¶ added in v3.7.2
func (l *MockedListener) OnSent(payload MetricsData)
func (*MockedListener) OnWarning ¶ added in v3.7.2
func (l *MockedListener) OnWarning(warning error)
type NoopListener ¶ added in v3.9.0
type NoopListener struct{}
NoopListener is an implementation of all of the listener interfaces that discards all messages. It's added if no other listener is added to drain the channels and as an example of implementing the listener interfaces.
func (NoopListener) OnCount ¶ added in v3.9.0
func (l NoopListener) OnCount(name string, enabled bool)
The feature is queried.
func (NoopListener) OnError ¶ added in v3.9.0
func (l NoopListener) OnError(err error)
func (NoopListener) OnReady ¶ added in v3.9.0
func (l NoopListener) OnReady()
The repository is ready.
func (NoopListener) OnRegistered ¶ added in v3.9.0
func (l NoopListener) OnRegistered(payload ClientData)
The client has registered.
func (NoopListener) OnSent ¶ added in v3.9.0
func (l NoopListener) OnSent(payload MetricsData)
The server has uploaded metrics.
func (NoopListener) OnWarning ¶ added in v3.9.0
func (l NoopListener) OnWarning(warning error)
type RepositoryListener ¶
type RepositoryListener interface { // OnReady is called when the client has loaded the feature toggles from // the Unleash server. OnReady() }
RepositoryListener defines an interface that can be implemented in order to receive events that are relevant to the feature toggle repository.
type Storage ¶
type Storage interface { // Init is called to initialize the storage implementation. The backupPath // is used to specify the location the data should be stored and the appName // can be used in naming. Init(backupPath string, appName string) // Reset is called after the repository has fetched the feature toggles from the server. // If persist is true the implementation of this function should call Persist(). The data // passed in here should be owned by the implementer of this interface. Reset(data map[string]interface{}, persist bool) error // Load is called to load the data from persistent storage and hold it in memory for fast // querying. Load() error // Persist is called when the data in the storage implementation should be persisted to disk. Persist() error // Get returns the data for the specified feature toggle. Get(string) (interface{}, bool) // List returns a list of all feature toggles. List() []interface{} }
Storage is an interface that can be implemented in order to have control over how the repository of feature toggles is persisted.
type VariantFallbackFunc ¶ added in v3.2.0
VariantFallbackFunc represents a function to be called if the variant is not found.
type VariantOption ¶ added in v3.2.0
type VariantOption func(*variantOption)
VariantOption provides options for querying if a variant is found or not.
func WithVariantContext ¶ added in v3.2.2
func WithVariantContext(ctx context.Context) VariantOption
WithVariantContext specifies a context for the GetVariant call
func WithVariantFallback ¶ added in v3.2.0
func WithVariantFallback(variantFallback *api.Variant) VariantOption
WithVariantFallback specifies what the value should be if the variant is not found on the unleash service.
func WithVariantFallbackFunc ¶ added in v3.2.0
func WithVariantFallbackFunc(variantFallbackFunc VariantFallbackFunc) VariantOption
WithVariantFallbackFunc specifies a fallback function to evaluate a variant is not found on the service.
func WithVariantResolver ¶ added in v3.7.0
func WithVariantResolver(resolver FeatureResolver) VariantOption
WithVariantResolver allows you to bypass the repository when resolving a feature name to its actual instance.