Created
May 27, 2020 06:33
-
-
Save kayslay/ae7c3d74de74244b3a6ca66c69730a73 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"log" | |
"sync" | |
"time" | |
) | |
var ( | |
duration = time.Second * 5 | |
) | |
type infoModel struct { | |
// INFO FIELDS | |
Name string | |
Age int | |
Sex string | |
Hobbies []string | |
InfoID string | |
} | |
// infoSaver defines the interface required to save infoModel to a db | |
type infoSaver interface { | |
CreateInfo(i *infoModel) error | |
} | |
// infoChan the struct passed in the channel | |
// contains the info model and an error | |
type infoChan struct { | |
info infoModel | |
err error | |
} | |
// infoBatchRequester this handles the request to the slow api/operation | |
// ensures only the first request call the api/op | |
type infoBatchRequester struct { | |
mx sync.RWMutex | |
pending map[string][]chan<- infoChan // this holds pending requests | |
infoSaver | |
} | |
// Request makes request to the api | |
func (i *infoBatchRequester) Request(infoID string, result chan<- infoChan) { | |
var done chan infoChan | |
i.mx.Lock() | |
_, ok := i.pending[infoID] | |
i.mx.Unlock() | |
if !ok { | |
// create the first pending request | |
done = make(chan infoChan) | |
i.mx.Lock() | |
i.pending[infoID] = []chan<- infoChan{result} | |
i.mx.Unlock() | |
// make the request to get the info | |
go func() { | |
var ( | |
infoResp infoModel | |
err error | |
) | |
//pretend to do long running task | |
log.Println("DOING LONG RUNNING TASK FOR. CALLED ONCE", infoID) | |
time.Sleep(duration) | |
infoResp = infoModel{ | |
Name: "John Doe", | |
Age: 50, | |
Sex: "Male", | |
Hobbies: []string{"eating"}, | |
InfoID: infoID, | |
} | |
//send info and error to done chan | |
done <- infoChan{info: infoResp, err: err} | |
}() | |
} else { | |
// append info to list of pending requests with the same infoID | |
i.mx.Lock() | |
i.pending[infoID] = append(i.pending[infoID], result) | |
i.mx.Unlock() | |
return | |
} | |
//wait for done to receive a value | |
value := <-done | |
i.mx.RLock() | |
results, ok := i.pending[infoID] | |
i.mx.RUnlock() | |
if ok { | |
for _, r := range results { | |
r <- value | |
close(r) | |
} | |
} | |
defer func() { | |
//delete the key when func execution is complete | |
i.mx.Lock() | |
delete(i.pending, infoID) | |
i.mx.Unlock() | |
}() | |
if value.err == nil { | |
log.Println("SAVED TO DB") | |
log.Println(i.infoSaver.CreateInfo(&value.info)) | |
} else { | |
log.Println("Error returned", value.err) | |
} | |
return | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment