断路器设计模式睡眠与时间.AfterFunc

时间:2016-08-31 23:45:09

标签: design-patterns go

我正在尝试创建Circuit breaker pattern,我想执行命令exec.Command,如果失败,请在X定义的时间内重试,出于测试目的,我正在做类似这样的事情测试time.AfterFunc

package main

import (
    "fmt"
    "time"
)

func myFunc() error {
    for i := 1; i < 10; i++ {
        fmt.Printf("i = %+v\n", i)
        if i%3 == 0 {
            return fmt.Errorf("error")
        }
    }
    return nil
}

func main() {

    run := make(chan struct{}, 1)

    run <- struct{}{}

    for {
        select {
        case <-run:
            err := myFunc()
            if err != nil {
                time.AfterFunc(3*time.Second, func() {
                    run <- struct{}{}
                })
            }
        default:
        }
    }
}

time.AfterFunc适用于上述代码,但不适用于以下示例,我必须将其替换为sleep才能达到预期效果:

package main

import (
    "fmt"
    "os/exec"
    "time"
)

func Exec(done chan<- error) error {
    cmd := exec.Command("./start")
    if err := cmd.Start(); err != nil {
        return err
    }
    go func() {
        done <- cmd.Wait()
    }()
    return nil
}

func main() {
    var (
        run  = make(chan struct{}, 1)
        done = make(chan error, 1)
    )

    Exec(done)

    for {
        select {
        case <-run:
            err := Exec(done)
            if err != nil {
                fmt.Println(err)
                // time.AfterFunc(3*time.Second, func() {
                time.Sleep(3 * time.Second)
                run <- struct{}{}
            }
        default:
            select {
            case err := <-done:
                fmt.Println(err)
                run <- struct{}{}
            }
        }
    }
}

./sleep的内容:

#!/bin/sh

sleep 3

为了测试,创建错误,我切换perms:

chmod -x sleep
chmod +x sleep

因此想知道使用time.AfterFunctime.Sleep之间有什么区别,这可能是实现此模式的最佳方式。

1 个答案:

答案 0 :(得分:0)

每当您点击默认情况时,选择会立即结束。在上面的示例中,执行AfterFunc后,for循环会持续运行,直到run有项目(3秒后)。忙碌的等待通常很糟糕。使用sleep解决方案,您永远不会有忙碌的等待,这很好。我不确定我是否完全按照第二个例子中的嵌套选择完成了你想要完成的任务。

为什么你需要频道和异步?为什么不呢:

retryCount := 0
for retryCount < 3 {
   err := doSomethingScary()
   if err == nil{
     //success! return results!
   } else{
     //failure! wait and retry
     time.Sleep(time.Second) //time.sleep is a good non-busy wait
   }
}
// max tries exceeded. Return error.