func TestRepeatingDelayOK(tst *testing.T) { decoupler := NewDecoupler(10, nil, nil) go decoupler.ProcessLoop(1 * time.Second) l := latch.NewCountdownLatch(5) latchShort := latch.NewCountdownLatch(1) task := func() (executor.ExecutionResult, error) { l.CountDown() if !latchShort.Completed() { latchShort.CountDown() } return executor.EX_OK, nil } decoupler.ExecuteEvery(1*time.Second, 1*time.Second, 5, task) // We want this latch to time out. if !latchShort.AwaitTimeout(1 * time.Second) { tst.Fatal("Should fail.") } // This one should not time out. if l.AwaitTimeout(12 * time.Second) { tst.Fatal("Task did not complete", l.Canceled(), l.TimedOut()) } decoupler.StopProcessLoop(1 * time.Second) }
func TestErrorCalled(tst *testing.T) { decoupler := NewDecoupler(10, nil, nil) go decoupler.ProcessLoop(1 * time.Second) l := latch.NewCountdownLatch(1) errorLatch := latch.NewCountdownLatch(1) decoupler.SetOnError(func(*Decoupler, *executor.TaskCell) executor.ExecutionResult { errorLatch.CountDown() return executor.EX_DROP }) task := func() (executor.ExecutionResult, error) { l.CountDown() return executor.EX_FAILED, errors.New("Aardvark application error") } decoupler.ExecuteEvery(1*time.Second, 1*time.Second, 5, task) // We want this latch to time out. if errorLatch.AwaitTimeout(5 * time.Second) { tst.Fatal("Error latch failed to fire.") } // This one should not time out. if l.AwaitTimeout(5 * time.Second) { tst.Fatal("Task did not complete", l.Canceled(), l.TimedOut()) } decoupler.StopProcessLoop(1 * time.Second) }
func TestDropCalled(tst *testing.T) { decoupler := NewDecoupler(1, nil, nil) go decoupler.ProcessLoop(1 * time.Second) dropLatch := latch.NewCountdownLatch(2) decoupler.SetOnDrop(func(*Decoupler, *executor.TaskCell) { dropLatch.CountDown() }) task := func() (executor.ExecutionResult, error) { time.Sleep(2 * time.Second) return executor.EX_OK, nil } time.AfterFunc(2*time.Second, func() { decoupler.Execute(task) // This may get picked up immediately. decoupler.Execute(task) // So we need three to ensure while the first is blocking decoupler.Execute(task) // The remainder attempt to overflow. }) // We want this latch to time out. if dropLatch.AwaitTimeout(5 * time.Second) { tst.Fatal("Error latch failed to fire.") } decoupler.StopProcessLoop(1 * time.Second) }
func (c *CatServiceProviderLocal) AddCat(name string, legs int) { l := latch.NewCountdownLatch(1) acr := addCatRequest{name, legs, l, c} c.dec.Execute(acr.Run) l.Await() // Use the timeout version if you wish.. }
// // Set a value on the map. // func (r *Register) AddEntry(name string) { ltch := latch.NewCountdownLatch(1) task := registerAddTask{r, ltch, name} r.dec.Execute(task.Run) ltch.Await() }
func TestNormalExecute(tst *testing.T) { decoupler := NewDecoupler(10, nil, nil) go decoupler.ProcessLoop(1 * time.Second) l := latch.NewCountdownLatch(1) task := func() (executor.ExecutionResult, error) { l.CountDown() return executor.EX_OK, nil } decoupler.ExecuteAfter(2*time.Second, task) // This one should not time out. if l.AwaitTimeout(3 * time.Second) { tst.Fatal("Task did not complete", l.Canceled(), l.TimedOut()) } decoupler.StopProcessLoop(1 * time.Second) }
// NewFutureWithListener with an optional listener. // func NewFutureWithListener(onValue func(bool, interface{})) *Future { return &Future{latch.NewCountdownLatch(1), nil, 0, &sync.Mutex{}, &sync.Mutex{}, onValue} }
// NewFuture creates a new future with no listener. // func NewFuture() *Future { return &Future{latch.NewCountdownLatch(1), nil, 0, &sync.Mutex{}, &sync.Mutex{}, nil} }
func main() { sites := []string{"http://www.theage.com.au", "http://www.cisco.com", "http://www.dilbert.com", "www.google.com"} results := make([]*QueryResult, len(sites)) l := latch.NewCountdownLatch(len(sites)) // A function that fetches the content of a web page and sets a pointer to the content into a result array. search := func(resultIndex int, query string) { // // Note the order of declaration of each defer statement. // defer func() { // If the await has completed(finished an await) then an attempt to count down will fail. // We can catch this and squash it for the sake of the example. r := recover() if r != nil { if lerr, ok := r.(latch.LatchError); ok { println(query, lerr.Error()) } } }() // // Attempt a latch countdown. // defer l.CountDown() resp, err := http.Get(query) if err != nil { results[resultIndex] = &QueryResult{Error: err} return } defer resp.Body.Close() body, err := ioutil.ReadAll(resp.Body) if err != nil { results[resultIndex] = &QueryResult{Error: err} return } results[resultIndex] = &QueryResult{query, nil, body} } // // Spin up a new go routine for each query. // for t, v := range sites { go search(t, v) } // // Wait 2 seconds for the requests to complete.. // if l.AwaitTimeout(2 * time.Second) { // An issue occurred. if l.Canceled() { // It was canceled. } if l.TimedOut() { println("Distributed query timed out..") } } // // Print the results. // for t, v := range results { if v == nil { println("Query ", t, "Did not return in time.") continue } println(t, "Query: ", v.Query) if v.Error != nil { println(" Error:", v.Error.Error()) } else { println(" Body Length: ", len(v.Body)) } } }