doubu2730 2016-08-31 23:45
浏览 34
已采纳

断路器设计模式睡眠与时间的关系。

I am trying to create a Circuit breaker pattern, I want to execute a command exec.Command and if it fails, retry in X defined amount of time, for testing purposes, I am doing something like this for testing time.AfterFunc:

package main

import (
    "fmt"
    "time"
)

func myFunc() error {
    for i := 1; i < 10; i++ {
        fmt.Printf("i = %+v
", 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 works for the above code, but not for the example below, I had to replace it with a sleep in order to achieve the expected results:

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{}{}
            }
        }
    }
}

The content of ./sleep:

#!/bin/sh

sleep 3

And for testing, creating an error, I toggle perms:

chmod -x sleep
chmod +x sleep

Therefore wondering what are the differences between using time.AfterFunc and time.Sleep and what could be the best way of implementing this pattern.

  • 写回答

1条回答 默认 最新

  • duanjia4220 2016-09-01 00:19
    关注

    Any time you hit the default case, the select ends immediately. In the top example, after you execute AfterFunc the for loop runs continually until run has items (after 3 seconds). Busy waits are usually bad. With the sleep solution, you never have a busy wait, which is good. I'm not sure I fully follow what you are trying to accomplish with the nested selects in the second example though.

    Why do you need channels and asynchrony at all? Why not just:

    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.
    
    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

悬赏问题

  • ¥50 comsol稳态求解器 找不到解,奇异矩阵有1个空方程返回的解不收敛。没有返回所有参数步长;pid控制
  • ¥15 怎么让wx群机器人发送音乐
  • ¥15 fesafe材料库问题
  • ¥35 beats蓝牙耳机怎么查看日志
  • ¥15 Fluent齿轮搅油
  • ¥15 八爪鱼爬数据为什么自己停了
  • ¥15 交替优化波束形成和ris反射角使保密速率最大化
  • ¥15 树莓派与pix飞控通信
  • ¥15 自动转发微信群信息到另外一个微信群
  • ¥15 outlook无法配置成功