...

Source file src/github.com/launchdarkly/go-server-sdk-redis-redigo/v2/redis_builder.go

Documentation: github.com/launchdarkly/go-server-sdk-redis-redigo/v2

     1  package ldredis
     2  
     3  import (
     4  	"fmt"
     5  
     6  	r "github.com/gomodule/redigo/redis"
     7  
     8  	"github.com/launchdarkly/go-sdk-common/v3/ldvalue"
     9  	"github.com/launchdarkly/go-server-sdk/v6/subsystems"
    10  )
    11  
    12  const (
    13  	// DefaultURL is the default value for StoreBuilder.URL.
    14  	DefaultURL = "redis://localhost:6379"
    15  	// DefaultPrefix is the default value for StoreBuilder.Prefix.
    16  	DefaultPrefix = "launchdarkly"
    17  )
    18  
    19  // DataStore returns a configurable builder for a Redis-backed persistent data store.
    20  //
    21  // This is for the main data store that holds feature flag data. To configure a data store for
    22  // Big Segments, use [BigSegmentStore] instead.
    23  //
    24  // You can use methods of the builder to specify any non-default Redis options you may want,
    25  // before passing the builder to [github.com/launchdarkly/go-server-sdk/v6/ldcomponents.PersistentDataStore].
    26  // In this example, the store is configured to use a Redis host called "host1":
    27  //
    28  //	config.DataStore = ldcomponents.PersistentDataStore(
    29  //		ldredis.DataStore().HostAndPort("host1", 6379))
    30  //
    31  // Note that the SDK also has its own options related to data storage that are configured
    32  // at a different level, because they are independent of what database is being used. For
    33  // instance, the builder returned by [github.com/launchdarkly/go-server-sdk/v6/ldcomponents.PersistentDataStore]
    34  // has options for caching:
    35  //
    36  //	config.DataStore = ldcomponents.PersistentDataStore(
    37  //		ldredis.DataStore().HostAndPort("host1", 6379),
    38  //	).CacheSeconds(15)
    39  func DataStore() *StoreBuilder[subsystems.PersistentDataStore] {
    40  	return &StoreBuilder[subsystems.PersistentDataStore]{
    41  		builderOptions: builderOptions{
    42  			prefix: DefaultPrefix,
    43  			url:    DefaultURL,
    44  		},
    45  		factory: createPersistentDataStore,
    46  	}
    47  }
    48  
    49  // BigSegmentStore returns a configurable builder for a Redis-backed Big Segment store.
    50  //
    51  // You can use methods of the builder to specify any non-default Redis options you may want,
    52  // before passing the builder to [github.com/launchdarkly/go-server-sdk/v6/ldcomponents.BigSegments].
    53  // In this example, the store is configured to use a Redis host called "host2":
    54  //
    55  //	config.BigSegments = ldcomponents.BigSegments(
    56  //		ldredis.BigSegmentStore().HostAndPort("host2", 6379))
    57  //
    58  // Note that the SDK also has its own options related to Big Segments that are configured
    59  // at a different level, because they are independent of what database is being used. For
    60  // instance, the builder returned by [github.com/launchdarkly/go-server-sdk/v6/ldcomponents.BigSegments]
    61  // has an option for the status polling interval:
    62  //
    63  //	config.BigSegments = ldcomponents.BigSegments(
    64  //		ldredis.BigSegmentStore().HostAndPort("host2", 6379),
    65  //	).StatusPollInterval(time.Second * 30)
    66  func BigSegmentStore() *StoreBuilder[subsystems.BigSegmentStore] {
    67  	return &StoreBuilder[subsystems.BigSegmentStore]{
    68  		builderOptions: builderOptions{
    69  			prefix: DefaultPrefix,
    70  			url:    DefaultURL,
    71  		},
    72  		factory: createBigSegmentStore,
    73  	}
    74  }
    75  
    76  // StoreBuilder is a builder for configuring the Redis-based persistent data store and/or Big
    77  // Segment store.
    78  //
    79  // Both [DataStore] and [BigSegmentStore] return instances of this type. You can use methods of the
    80  // builder to specify any ny non-default Redis options you may want, before passing the builder to
    81  // either [github.com/launchdarkly/go-server-sdk/v6/ldcomponents.PersistentDataStore] or
    82  // [github.com/launchdarkly/go-server-sdk/v6/ldcomponents.BigSegments] as appropriate. The two types
    83  // of stores are independent of each other; you do not need a Big Segment store if you are not using
    84  // the Big Segments feature, and you do not need to use the same database for both.
    85  //
    86  // In this example, the main data store uses a Redis host called "host1", and the Big Segment
    87  // store uses a Redis host called "host2":
    88  //
    89  //     config.DataStore = ldcomponents.PersistentDataStore(
    90  //         ldredis.DataStore().URL("redis://host1:6379")
    91  //     config.BigSegments = ldcomponents.BigSegments(
    92  //         ldredis.DataStore().URL("redis://host2:6379")
    93  //
    94  // Note that the SDK also has its own options related to data storage that are configured
    95  // at a different level, because they are independent of what database is being used. For
    96  // instance, the builder returned by [github.com/launchdarkly/go-server-sdk/v6/ldcomponents.PersistentDataStore]
    97  // has options for caching:
    98  //
    99  //	config.DataStore = ldcomponents.PersistentDataStore(
   100  //		ldredis.DataStore().HostAndPort("host1", 6379),
   101  //	).CacheSeconds(15)
   102  type StoreBuilder[T any] struct {
   103  	builderOptions builderOptions
   104  	factory        func(*StoreBuilder[T], subsystems.ClientContext) (T, error)
   105  }
   106  
   107  type builderOptions struct {
   108  	prefix      string
   109  	pool        Pool
   110  	url         string
   111  	dialOptions []r.DialOption
   112  }
   113  
   114  // Prefix specifies a string that should be prepended to all Redis keys used by the data store.
   115  // A colon will be added to this automatically. If this is unspecified or empty, [DefaultPrefix] will be used.
   116  func (b *StoreBuilder[T]) Prefix(prefix string) *StoreBuilder[T] {
   117  	if prefix == "" {
   118  		prefix = DefaultPrefix
   119  	}
   120  	b.builderOptions.prefix = prefix
   121  	return b
   122  }
   123  
   124  // URL specifies the Redis host URL. If not specified, the default value is [DefaultURL].
   125  //
   126  // Note that some Redis client features can also be specified as part of the URL: Redigo supports
   127  // the redis:// syntax (https://www.iana.org/assignments/uri-schemes/prov/redis), which can include a
   128  // password and a database number, as well as rediss://
   129  // (https://www.iana.org/assignments/uri-schemes/prov/rediss), which enables TLS.
   130  func (b *StoreBuilder[T]) URL(url string) *StoreBuilder[T] {
   131  	if url == "" {
   132  		url = DefaultURL
   133  	}
   134  	b.builderOptions.url = url
   135  	return b
   136  }
   137  
   138  // HostAndPort is a shortcut for specifying the Redis host address as a hostname and port.
   139  func (b *StoreBuilder[T]) HostAndPort(host string, port int) *StoreBuilder[T] {
   140  	return b.URL(fmt.Sprintf("redis://%s:%d", host, port))
   141  }
   142  
   143  // Pool specifies that the data store should use a specific connection pool configuration. If not
   144  // specified, it will create a default configuration (see package description). Specifying this
   145  // option will cause any address specified with URL or HostAndPort to be ignored.
   146  //
   147  // If you only need to change basic connection options such as providing a password, it is
   148  // simpler to use DialOptions.
   149  //
   150  // Use PoolInterface if you want to provide your own implementation of a connection pool.
   151  func (b *StoreBuilder[T]) Pool(pool *r.Pool) *StoreBuilder[T] {
   152  	b.builderOptions.pool = pool
   153  	return b
   154  }
   155  
   156  // PoolInterface is equivalent to Pool, but uses an interface type rather than a concrete
   157  // implementation type. This allows implementation of custom behaviors for connection management.
   158  func (b *StoreBuilder[T]) PoolInterface(pool Pool) *StoreBuilder[T] {
   159  	b.builderOptions.pool = pool
   160  	return b
   161  }
   162  
   163  // DialOptions specifies any of the advanced Redis connection options supported by Redigo, such as
   164  // DialPassword.
   165  //
   166  //     import (
   167  //         redigo "github.com/garyburd/redigo/redis"
   168  //         ldredis "github.com/launchdarkly/go-server-sdk-redis-redigo/v2"
   169  //     )
   170  //     config.DataSource = ldcomponents.PersistentDataStore(
   171  //         ldredis.DataStore().DialOptions(redigo.DialPassword("verysecure123")),
   172  //     )
   173  // Note that some Redis client features can also be specified as part of the URL: see  URL().
   174  func (b *StoreBuilder[T]) DialOptions(options ...r.DialOption) *StoreBuilder[T] {
   175  	b.builderOptions.dialOptions = options
   176  	return b
   177  }
   178  
   179  // Build is called internally by the SDK.
   180  func (b *StoreBuilder[T]) Build(context subsystems.ClientContext) (T, error) {
   181  	return b.factory(b, context)
   182  }
   183  
   184  // DescribeConfiguration is used internally by the SDK to inspect the configuration.
   185  func (b *StoreBuilder[T]) DescribeConfiguration() ldvalue.Value {
   186  	return ldvalue.String("Redis")
   187  }
   188  
   189  // Pool is an interface representing a Redis connection pool.
   190  //
   191  // The methods of this interface are the same as the basic methods of the Pool type in
   192  // the Redigo client. Any type implementing the interface can be passed to
   193  // StoreBuilder.PoolInterface to provide custom connection behavior.
   194  type Pool interface {
   195  	// Get obtains a Redis connection.
   196  	//
   197  	// See: https://pkg.go.dev/github.com/gomodule/redigo/redis#Pool.Get
   198  	Get() r.Conn
   199  
   200  	// Close releases the resources used by the pool.
   201  	//
   202  	// See: https://pkg.go.dev/github.com/gomodule/redigo/redis#Pool.Close
   203  	Close() error
   204  }
   205  
   206  func createPersistentDataStore(
   207  	builder *StoreBuilder[subsystems.PersistentDataStore],
   208  	clientContext subsystems.ClientContext,
   209  ) (subsystems.PersistentDataStore, error) {
   210  	store := newRedisDataStoreImpl(builder.builderOptions, clientContext.GetLogging().Loggers)
   211  	return store, nil
   212  }
   213  
   214  func createBigSegmentStore(
   215  	builder *StoreBuilder[subsystems.BigSegmentStore],
   216  	clientContext subsystems.ClientContext,
   217  ) (subsystems.BigSegmentStore, error) {
   218  	store := newRedisBigSegmentStoreImpl(builder.builderOptions, clientContext.GetLogging().Loggers)
   219  	return store, nil
   220  }
   221  

View as plain text