Tree @v1.8.0 (Download .tar.gz)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | # goswarm Go Stale While Asynchronously Revalidate Memoization ## DESCRIPTION goswarm is a library written in Go for storing the results of expensive function calls and returning the cached result when the same input key occurs again. In addition to the examples provided below, documentation can be found at [![GoDoc](https://godoc.org/github.com/karrick/goswarm?status.svg)](https://godoc.org/github.com/karrick/goswarm). ```Go simple, err := goswarm.NewSimple(nil) if err != nil { log.Fatal(err) } // you can store any Go type in a Swarm simple.Store("someKeyString", 42) simple.Store("anotherKey", struct{}{}) simple.Store("yetAnotherKey", make(chan interface{})) // but when you retrieve it, you are responsible to perform type assertions key := "yetAnotherKey" value, ok := simple.Load(key) if !ok { panic(fmt.Errorf("cannot find %q", key)) } value = value.(chan interface{}) simple.Delete("anotherKey") ``` As seen above, goswarm's API is similar to that of any associative array, also known as a map in Go terminology: It allows storing a value to be retrieved using a specified key, and overwriting any value that might already be present in the map. It allows loading the value associated with the specified key already stored in the map. It allows deleting a specified key and its associated value stored in the map. goswarm differs from most traditional associative array APIs in that it provides a method to load the value associated with a specified key, and if that key is not found in the map, to invoke a specified lookup function to fetch the value for that key. ```Go simple, err := goswarm.NewSimple(&goswarm.Config{ Lookup: func(key string) (interface{}, error) { // TODO: do slow calculation or make a network call result := key // example return result, nil }, }) if err != nil { log.Fatal(err) } defer func() { _ = simple.Close() }() value, err := simple.Query("%version") if !err { panic(fmt.Errorf("cannot retrieve value for key %q: %s", key, err)) } fmt.Printf("The value is: %v\n", value) ``` ## Stale-While-Revalidate and Stale-If-Error In addition, goswarm provides stale-while-revalidate and stale-if-error compatible features in its simple API. ### Stale-While-Revalidate When the user requests the value associated with a particular key, goswarm determines whether that key-value pair is present, and if so, whether that value has become stale. If the value is stale, goswarm will return the previously stored value to the client, but spawn an asynchronous routine to fetch a new value for that key and store that value in the map to be used for future queries. When the user requests the value associated with a particular key that has expired, goswarm will not return that value, but rather synchronously fetch an updated value to store in the map and return to the user. ### Stale-If-Error When fetching a new value to replace a value that has become stale, the lookup callback funciton might return an error. Perhaps the remote network resource used to fetch responses is offline. In these cases, goswarm will not overwrite the stale value with the error, but continue to serve the stale value until the lookup callback function returns a new value rather than an error, or the value expires, in which case, the error is returned to the user. ## Periodic Removal Of Expired Keys If `GCPeriodicty` configuration value is greater than the zero-value for time.Duration, goswarm spawns a separate go-routine that invokes the `GC` method periodically, removing all key-value pairs from the data map that have an expired time. When this feature is used, the `Close` method must be invoked to stop and release that go-routine. ```Go simple, err := goswarm.NewSimple(&goswarm.Config{ GoodExpiryDuration: 24 * time.Hour, BadExpiryDuration: 5 * time.Minute, GCPeriodicity: time.Hour, Lookup: func(key string) (interface{}, error) { // TODO: do slow calculation or make a network call result := key // example return result, nil }, }) if err != nil { log.Fatal(err) } defer func() { _ = simple.Close() }() ``` ## Note About Choosing Stale and Expiry Durations Different applications may require different logic, however if your application needs to continue processing data and serving requests even when a downstream dependency is subject to frequent high latency periods or faults, it is recommended to set the GoodStaleDuration period to a low enough value to ensure data is reasonably up-to-date, but extend the GoodExpiryDuration to be long enough that your application can still operate using possibly stale data. The goswarm library will repeatedly attempt to fetch a new value from the downstream service, but until a defined very long period of time transpires, your service will be relatively insulated from these type of downstream faults and latencies. ```Go simple, err := goswarm.NewSimple(&goswarm.Config{ GoodStaleDuration: time.Minute, GoodExpiryDuration: 24 * time.Hour, BadStaleDuration: time.Minute, BadExpiryDuration: 5 * time.Minute, GCPeriodicity: time.Hour, Lookup: func(key string) (interface{}, error) { // TODO: do slow calculation or make a network call result := key // example return result, nil }, }) if err != nil { log.Fatal(err) } defer func() { _ = simple.Close() }() value, err := simple.Query("%version") if !err { panic(fmt.Errorf("cannot retrieve value for key %q: %s", key, err)) } fmt.Printf("The value is: %v\n", value) ``` |
Commit History @v1.8.0
0
»»
- added go.mod Karrick S. McDermott 6 years ago
- Simple.Query fires at most 1 go routine to asynchronously update value Karrick S. McDermott 6 years ago
- each Simple maintains its own gc flag Karrick S. McDermott 6 years ago
- documentation formatting Karrick S. McDermott 7 years ago
- go vet && golint safe Karrick S. McDermott 7 years ago
- no longer requires Go version 1.7 or above Karrick S. McDermott 7 years ago
- documentation updates Karrick S. McDermott 7 years ago
- uses context for mark and collection phase timeout Karrick S. McDermott 7 years ago
- GC looks more like a mark/sweep algorithm with a hard timeout Karrick S. McDermott 7 years ago
- no more r-w data race during GC Karrick S. McDermott 7 years ago
- Update replaces EnqueueAsynchronousUpdate method Karrick S. McDermott 7 years ago
- EnqueueAsyncUpdate enqueues an asynchronous request to update the value associated with the specified key. Karrick S. McDermott 7 years ago
- code flow comments in the form of commented out log messages Karrick S. McDermott 7 years ago
- TimedValue provides methods to determe whether value is stale or expired Karrick S. McDermott 7 years ago
- code refactors Karrick S. McDermott 7 years ago
- improved fetching and delete logic Karrick S. McDermott 7 years ago
- documentation update Karrick S. McDermott 7 years ago
- simplified Range method Karrick S. McDermott 7 years ago
- Range method runs a callback function for each key-value pair in the data map. Karrick S. McDermott 7 years ago
- NewSimple may be called with no Lookup method for map-like use when Query is not invoked Karrick S. McDermott 7 years ago
- no longer panics when initial fetch results in an error Karrick S. McDermott 7 years ago
- created goswarm.Simple type that provides low-level time-based control of how values go stale or expire Karrick S. McDermott (commit: Karrick S. McDermott) 7 years ago
- initial commit Karrick S. McDermott 7 years ago
- Initial commit Karrick McDermott 7 years ago
0
»»