1 package subsystems 2 3 import ( 4 "io" 5 6 "github.com/launchdarkly/go-server-sdk/v6/subsystems/ldstoretypes" 7 ) 8 9 // PersistentDataStore is an interface for a data store that holds feature flags and related data in a 10 // serialized form. 11 // 12 // This interface should be used for database integrations, or any other data store implementation that 13 // stores data in some external service. The SDK will provide its own caching layer on top of the 14 // persistent data store; the data store implementation should not provide caching, but simply do every 15 // query or update that the SDK tells it to do. 16 // 17 // Implementations must be safe for concurrent access from multiple goroutines. 18 // 19 // Error handling is defined as follows: if any data store operation encounters a database error, or 20 // is otherwise unable to complete its task, it should return an error value to make the SDK aware of 21 // The SDK will log the exception and will assume that the data store is now in a non-operational 22 // non-operational state; the SDK will then start polling IsStoreAvailable() to determine when the 23 // store has started working again. 24 // 25 // Whenever a new implementation of this interface is written, it should have unit tests that use 26 // testhelpers.storetest.PersistentDataStoreTestSuite. This ensures that all of the interface methods 27 // are exercised consistently in various scenarios that might be encountered in real SDK usage. 28 type PersistentDataStore interface { 29 io.Closer 30 31 // Init overwrites the store's contents with a set of items for each collection. 32 // 33 // All previous data should be discarded, regardless of versioning. 34 // 35 // The update should be done atomically. If it cannot be done atomically, then the store 36 // must first add or update each item in the same order that they are given in the input 37 // data, and then delete any previously stored items that were not in the input data. 38 Init(allData []ldstoretypes.SerializedCollection) error 39 40 // Get retrieves an item from the specified collection, if available. 41 // 42 // If the specified key does not exist in the collection, it should return a SerializedItemDescriptor 43 // with a Version of -1 and an Item of nil. 44 // 45 // If the item has been deleted and the store contains a placeholder, it should return that 46 // placeholder rather than filtering it out. 47 Get(kind ldstoretypes.DataKind, key string) (ldstoretypes.SerializedItemDescriptor, error) 48 49 // GetAll retrieves all items from the specified collection. 50 // 51 // If the store contains placeholders for deleted items, it should include them in the results, 52 // not filter them out. 53 GetAll(kind ldstoretypes.DataKind) ([]ldstoretypes.KeyedSerializedItemDescriptor, error) 54 55 // Upsert updates or inserts an item in the specified collection. For updates, the object will only be 56 // updated if the existing version is less than the new version. 57 // 58 // The SDK may pass a SerializedItemDescriptor that represents a placeholder for a deleted item. In 59 // that case, assuming the version is greater than any existing version of that item, the store should 60 // retain that placeholder rather than simply not storing anything. 61 // 62 // The method returns the updated item if the update was successful; or, if the update was not 63 // successful because the store contained an equal or higher version, it returns the item that is 64 // in the store. 65 Upsert(kind ldstoretypes.DataKind, key string, item ldstoretypes.SerializedItemDescriptor) (bool, error) 66 67 // IsInitialized returns true if the data store contains a data set, meaning that Init has been 68 // called at least once. 69 // 70 // In a shared data store, it should be able to detect this even if Init was called in a 71 // different process: that is, the test should be based on looking at what is in the data store. 72 // Once this has been determined to be true, it can continue to return true without having to 73 // check the store again; this method should be as fast as possible since it may be called during 74 // feature flag evaluations. 75 IsInitialized() bool 76 77 // IsStoreAvailable tests whether the data store seems to be functioning normally. 78 // 79 // This should not be a detailed test of different kinds of operations, but just the smallest possible 80 // operation to determine whether (for instance) we can reach the database. 81 // 82 // Whenever one of the store's other methods returns an error, the SDK will assume that it may have 83 // become unavailable (e.g. the database connection was lost). The SDK will then call 84 // IsStoreAvailable() at intervals until it returns true. 85 IsStoreAvailable() bool 86 } 87