Ралица обнови решението на 31.12.2015 19:53 (преди над 2 години)
+package main
+
+import (
+ "container/ring"
+ //"sync"
+)
+
+type Request interface {
+ ID() string
+ Run() (result interface{}, err error)
+ Cacheable() bool
+ SetResult(result interface{}, err error)
+}
+
+type Requester interface {
+ AddRequest(request Request)
+ Stop()
+}
+
+const (
+ Working = iota
+ Stopped
+)
+
+type RequestHandler struct {
+ requests chan Request
+ working int
+ sem chan struct{}
+ cache *ring.Ring
+ running map[string]bool
+ // waitgroup sync.WaitGroup
+}
+
+type CacheElement struct {
+ Id string
+ Result interface{}
+ Err error
+}
+
+func NewRequester(cacheSize int, throttleSize int) Requester {
+ requestChannel := make(chan Request)
+ cache := ring.New(cacheSize)
+ running := make(map[string]bool)
+
+ requester := RequestHandler{requests: requestChannel, working: Working, cache: cache, running: running}
+
+ requester.sem = make(chan struct{})
+
+ //requester.waitgroup.Add(throttleSize)
+
+ go func() {
+ for request := range requester.requests {
+
+ ready := false
+
+ requester.cache.Do(func(cacheElement interface{}) {
+ element, _ := cacheElement.(CacheElement)
+
+ if element.Id == request.ID() {
+ request.SetResult(element.Result, element.Err)
+ ready = true
+ }
+ })
+
+ if ready {
+ continue
+ }
+
+ if requester.running[request.ID()] {
+ go func() {
+ requester.requests <- request
+ }()
+ continue
+ }
+
+ requester.running[request.ID()] = true
+ result, err := request.Run()
+ requester.running[request.ID()] = false
+
+ if request.Cacheable() {
+ requester.cache = requester.cache.Next()
+
+ cacheElement := CacheElement{}
+ cacheElement.Id = request.ID()
+ cacheElement.Result, cacheElement.Err = result, err
+
+ requester.cache.Value = cacheElement
+ }
+
+ }
+ requester.sem <- struct{}{}
+ }()
+
+ return &requester
+}
+
+func (r *RequestHandler) AddRequest(request Request) {
+ if r.working == Working {
+ r.requests <- request
+ }
+}
+
+func (r *RequestHandler) Stop() {
+ r.working = Stopped
+ //requester.waitgroup.Wait()
+ close(r.requests)
+ <-r.sem
+}