...

Source file src/github.com/launchdarkly/go-server-sdk/v6/interfaces/data_source_status_provider.go

Documentation: github.com/launchdarkly/go-server-sdk/v6/interfaces

     1  package interfaces
     2  
     3  import (
     4  	"fmt"
     5  	"time"
     6  )
     7  
     8  // DataSourceStatusProvider is an interface for querying the status of a DataSource. The data source is the
     9  // component that receives updates to feature flag data; normally this is a streaming connection, but it
    10  // could be polling or file data depending on your configuration.
    11  //
    12  // An implementation of this interface is returned by
    13  // [github.com/launchdarkly/go-server-sdk/v6.LDClient.GetDataSourceStatusProvider()].
    14  // Application code should not implement this interface.
    15  //
    16  // There are three ways to interact with the data source status. One is to simply get the current status;
    17  // if its State property is DataSourceStateValid, then the SDK is able to receive feature flag updates.
    18  //
    19  //	status := client.GetDataSourceStatusProvider().GetStatus()
    20  //	isValid = status.State == interfaces.DataSourceStateValid
    21  //
    22  // Second, you can use AddStatusListener to get a channel that provides a status update whenever the
    23  // connection has an error or starts working again.
    24  //
    25  //	statusCh := client.GetDataSourceStatusProvider().AddStatusListener()
    26  //	go func() {
    27  //	    for newStatus := range statusCh {
    28  //	        log.Printf("data source status is now: %+v", newStatus)
    29  //	    }
    30  //	}()
    31  //
    32  // Third, you can use WaitFor to block until the data source has the desired status. For instance, if you
    33  // did not want to wait for a connection when you originally created the client, you could set the
    34  // timeout to zero so that the connection happens in the background. Then, when you need to do something
    35  // that requires a valid connection (possibly on another goroutine), you can wait until it is valid.
    36  //
    37  //	client, _ := ld.MakeCustomClient(sdkKey, config, 0)
    38  //
    39  //	// later...
    40  //	inited := client.GetDataSourceStatusProvider().WaitFor(interfaces.DataSourceStateValid, 10 * time.Second)
    41  //	if !inited {
    42  //	    // do whatever is appropriate if initialization has timed out
    43  //	}
    44  type DataSourceStatusProvider interface {
    45  	// GetStatus returns the current status of the data source.
    46  	//
    47  	// All of the built-in data source implementations are guaranteed to update this status whenever they
    48  	// successfully initialize, encounter an error, or recover after an error.
    49  	GetStatus() DataSourceStatus
    50  
    51  	// AddStatusListener subscribes for notifications of status changes. The returned channel will receive a
    52  	// new DataSourceStatus value for any change in status.
    53  	//
    54  	// The listener will be notified whenever any property of the status has changed. See DataSourceStatus for
    55  	// an explanation of the meaning of each property and what could cause it to change.
    56  	//
    57  	// It is the caller's responsibility to consume values from the channel. Allowing values to accumulate in
    58  	// the channel can cause an SDK goroutine to be blocked. If you no longer need the channel, call
    59  	// RemoveStatusListener.
    60  	AddStatusListener() <-chan DataSourceStatus
    61  
    62  	// RemoveStatusListener unsubscribes from notifications of status changes. The specified channel must be
    63  	// one that was previously returned by AddStatusListener(); otherwise, the method has no effect.
    64  	RemoveStatusListener(listener <-chan DataSourceStatus)
    65  
    66  	// WaitFor is a synchronous method for waiting for a desired connection state.
    67  	//
    68  	// If the current state is already desiredState when this method is called, it immediately returns.
    69  	// Otherwise, it blocks until 1. the state has become desiredState, 2. the state has become
    70  	// DataSourceStateOff (since that is a permanent condition), or 3. the specified timeout elapses.
    71  	//
    72  	// A scenario in which this might be useful is if you want to create the LDClient without waiting
    73  	// for it to initialize, and then wait for initialization at a later time or on a different goroutine:
    74  	//
    75  	//     // create the client but do not wait
    76  	//     client = ld.MakeCustomClient(sdkKey, config, 0)
    77  	//
    78  	//     // later, possibly on another goroutine:
    79  	//     inited := client.GetDataSourceStatusProvider().WaitFor(DataSourceStateValid, 10 * time.Second)
    80  	//     if !inited {
    81  	//         // do whatever is appropriate if initialization has timed out
    82  	//     }
    83  	WaitFor(desiredState DataSourceState, timeout time.Duration) bool
    84  }
    85  
    86  // DataSourceStatus is information about the data source's status and the last status change.
    87  //
    88  // See [DataSourceStatusProvider].
    89  type DataSourceStatus struct {
    90  	// State represents the overall current state of the data source. It will always be one of the
    91  	// DataSourceState constants such as DataSourceStateValid.
    92  	State DataSourceState
    93  
    94  	// StateSince is the date/time that the value of State most recently changed.
    95  	//
    96  	// The meaning of this depends on the current State:
    97  	//   - For DataSourceStateInitializing, it is the time that the SDK started initializing.
    98  	//   - For DataSourceStateValid, it is the time that the data source most recently entered a valid
    99  	//     state, after previously having been either Initializing or Interrupted.
   100  	//   - For DataSourceStateInterrupted, it is the time that the data source most recently entered an
   101  	//     error state, after previously having been Valid.
   102  	//   - For DataSourceStateOff, it is the time that the data source encountered an unrecoverable error
   103  	//     or that the SDK was explicitly shut down.
   104  	StateSince time.Time
   105  
   106  	// LastError is information about the last error that the data source encountered, if any.
   107  	//
   108  	// This property should be updated whenever the data source encounters a problem, even if it does
   109  	// not cause State to change. For instance, if a stream connection fails and the
   110  	// state changes to DataSourceStateInterrupted, and then subsequent attempts to restart the
   111  	// connection also fail, the state will remain Interrupted but the error information
   112  	// will be updated each time-- and the last error will still be reported in this property even if
   113  	// the state later becomes Valid.
   114  	//
   115  	// If no error has ever occurred, this field will be an empty DataSourceErrorInfo{}.
   116  	LastError DataSourceErrorInfo
   117  }
   118  
   119  // String returns a simple string representation of the status.
   120  func (e DataSourceStatus) String() string {
   121  	return fmt.Sprintf("Status(%s,%s,%s)", e.State, e.StateSince.Format(time.RFC3339), e.LastError)
   122  }
   123  
   124  // DataSourceState is any of the allowable values for [DataSourceStatus].State.
   125  //
   126  // See [DataSourceStatusProvider].
   127  type DataSourceState string
   128  
   129  const (
   130  	// DataSourceStateInitializing is the initial state of the data source when the SDK is being
   131  	// initialized.
   132  	//
   133  	// If it encounters an error that requires it to retry initialization, the state will remain at
   134  	// Initializing until it either succeeds and becomes DataSourceStateValid, or permanently fails and
   135  	// becomes DataSourceStateOff.
   136  	DataSourceStateInitializing DataSourceState = "INITIALIZING"
   137  
   138  	// DataSourceStateValid indicates that the data source is currently operational and has not had
   139  	// any problems since the last time it received data.
   140  	//
   141  	// In streaming mode, this means that there is currently an open stream connection and that at least
   142  	// one initial message has been received on the stream. In polling mode, it means that the last poll
   143  	// request succeeded.
   144  	DataSourceStateValid DataSourceState = "VALID"
   145  
   146  	// DataSourceStateInterrupted indicates that the data source encountered an error that it will
   147  	// attempt to recover from.
   148  	//
   149  	// In streaming mode, this means that the stream connection failed, or had to be dropped due to some
   150  	// other error, and will be retried after a backoff delay. In polling mode, it means that the last poll
   151  	// request failed, and a new poll request will be made after the configured polling interval.
   152  	DataSourceStateInterrupted DataSourceState = "INTERRUPTED"
   153  
   154  	// DataSourceStateOff indicates that the data source has been permanently shut down.
   155  	//
   156  	// This could be because it encountered an unrecoverable error (for instance, the LaunchDarkly service
   157  	// rejected the SDK key; an invalid SDK key will never become valid), or because the SDK client was
   158  	// explicitly shut down.
   159  	DataSourceStateOff DataSourceState = "OFF"
   160  )
   161  
   162  // DataSourceErrorInfo is a description of an error condition that the data source encountered.
   163  //
   164  // See [DataSourceStatusProvider].
   165  type DataSourceErrorInfo struct {
   166  	// Kind is the general category of the error. It will always be one of the DataSourceErrorKind
   167  	// constants such as DataSourceErrorKindNetworkError, or "" if there have not been any errors.
   168  	Kind DataSourceErrorKind
   169  
   170  	// StatusCode is the HTTP status code if the error was DataSourceErrorKindErrorResponse, or zero
   171  	// otherwise.
   172  	StatusCode int
   173  
   174  	// Message is any any additional human-readable information relevant to the error. The format of
   175  	// this message is subject to change and should not be relied on programmatically.
   176  	Message string
   177  
   178  	// Time is the date/time that the error occurred.
   179  	Time time.Time
   180  }
   181  
   182  // String returns a simple string representation of the error.
   183  func (e DataSourceErrorInfo) String() string {
   184  	ret := string(e.Kind)
   185  	if e.StatusCode > 0 || e.Message != "" {
   186  		ret += "("
   187  		if e.StatusCode > 0 {
   188  			ret += fmt.Sprintf("%d", e.StatusCode)
   189  		}
   190  		if e.Message != "" {
   191  			if e.StatusCode > 0 {
   192  				ret += ","
   193  			}
   194  			ret += e.Message
   195  		}
   196  		ret += ")"
   197  	}
   198  	if !e.Time.IsZero() {
   199  		ret += fmt.Sprintf("@%s", e.Time.Format(time.RFC3339))
   200  	}
   201  	return ret
   202  }
   203  
   204  // DataSourceErrorKind is any of the allowable values for [DataSourceErrorInfo].Kind.
   205  //
   206  // See [DataSourceStatusProvider].
   207  type DataSourceErrorKind string
   208  
   209  const (
   210  	// DataSourceErrorKindUnknown indicates an unexpected error, such as an uncaught exception,
   211  	// further described by DataSourceErrorInfo.Message.
   212  	DataSourceErrorKindUnknown DataSourceErrorKind = "UNKNOWN"
   213  
   214  	// DataSourceErrorKindNetworkError represents an I/O error such as a dropped connection.
   215  	DataSourceErrorKindNetworkError DataSourceErrorKind = "NETWORK_ERROR"
   216  
   217  	// DataSourceErrorKindErrorResponse means the LaunchDarkly service returned an HTTP response
   218  	// with an error status, available in DataSourceErrorInfo.StatusCode.
   219  	DataSourceErrorKindErrorResponse DataSourceErrorKind = "ERROR_RESPONSE"
   220  
   221  	// DataSourceErrorKindInvalidData means the SDK received malformed data from the LaunchDarkly
   222  	// service.
   223  	DataSourceErrorKindInvalidData DataSourceErrorKind = "INVALID_DATA"
   224  
   225  	// DataSourceErrorKindStoreError means the data source itself is working, but when it tried
   226  	// to put an update into the data store, the data store failed (so the SDK may not have the
   227  	// latest data).
   228  	//
   229  	// Data source implementations do not need to report this kind of error; it will be
   230  	// automatically reported by the SDK whenever one of the update methods of DataSourceUpdateSink
   231  	// encounters a failure.
   232  	DataSourceErrorKindStoreError DataSourceErrorKind = "STORE_ERROR"
   233  )
   234  

View as plain text