2016-08-31 3 views
0

私はexec.Commandコマンドを実行したいと思いますが、失敗した場合は、テストのために定義した時間Xで再試行します。このようなことをやっています。テストtime.AfterFuncのために:サーキットブレーカのデザインパターンsleep vs time.AfterFunc

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{}{} 
      } 
     } 
    } 
} 
:下記の例のための

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と交換しなければなりませんでした210

./sleepの内容:

#!/bin/sh 

sleep 3 

とテストのための

、エラーを作成し、私は切り替えパーマ:そこで疑問に思っ

chmod -x sleep 
chmod +x sleep 

time.AfterFunctime.Sleepを使用して、最高の何ができるかの違いは何ですかこのパターンを実装する方法。

+0

上の例では、再試行時間が完了するまでエラーが発生すると、ビジー待機をしています。 AfterFuncが実行されるまで、ループはできるだけ速く実行されます。 – captncraig

+0

**予想される結果**は達成できませんか? 3秒間待たずに、パニックになりますか? – sberry

+0

@sberryはい、基本的には、もう一度やり直す前にXの時間を待っています。 – nbari

答えて

0

デフォルトの場合を選択すると、すぐに選択が終了します。上の例では、AfterFuncを実行した後、forループは、runに項目があるまで(3秒後)連続して実行されます。忙しい待ち時間は通常悪いです。 sleepソリューションでは、ビジー状態を待つことはありません。私は2番目の例で入れ子になった選択肢で達成しようとしていることを完全にフォローしているかどうかはわかりません。

なぜチャネルと非同期が必要なのですか?なぜでしょうか:

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. 
+0

こんにちは、私は、コマンドが主に '' cmd.Wait() ''が – nbari

+0

で終了したことを知る必要があるので、チャンネルが必要です。 '' cmd.Wait() 'が返ったときにコマンドが終了します。タイムアウトを行う場合は、チャネルベースのアプローチが適切かもしれませんが、今は再試行しています。 – captncraig