Просмотр исходного кода

DRY up breaker.Go and breaker.Run

Evan Huus 11 лет назад
Родитель
Сommit
ed2c12bb4a
1 измененных файлов с 27 добавлено и 42 удалено
  1. 27 42
      breaker/breaker.go

+ 27 - 42
breaker/breaker.go

@@ -55,6 +55,32 @@ func (b *Breaker) Run(work func() error) error {
 		return ErrBreakerOpen
 	}
 
+	return b.doWork(state, work)
+}
+
+// Go will either return ErrBreakerOpen immediately if the circuit-breaker is
+// already open, or it will run the given function in a separate goroutine.
+// If the function is run, Go will return nil immediately, and will *not* return
+// the return value of the function. It is safe to call Go concurrently on the
+// same Breaker.
+func (b *Breaker) Go(work func() error) error {
+	b.lock.RLock()
+	state := b.state
+	b.lock.RUnlock()
+
+	if state == open {
+		return ErrBreakerOpen
+	}
+
+	// errcheck complains about ignoring the error return value, but
+	// that's on purpose; if you want an error from a goroutine you have to
+	// get it over a channel or something
+	go b.doWork(state, work)
+
+	return nil
+}
+
+func (b *Breaker) doWork(state state, work func() error) error {
 	var panicValue interface{}
 
 	result := func() error {
@@ -70,6 +96,7 @@ func (b *Breaker) Run(work func() error) error {
 		return nil
 	}
 
+	// oh well, I guess we have to contend on the lock
 	b.processResult(result, panicValue)
 
 	if panicValue != nil {
@@ -81,48 +108,6 @@ func (b *Breaker) Run(work func() error) error {
 	return result
 }
 
-// Go will either return ErrBreakerOpen immediately if the circuit-breaker is
-// already open, or it will run the given function in a separate goroutine.
-// If the function is run, Go will return nil immediately, and will *not* return
-// the return value of the function. It is safe to call Go concurrently on the
-// same Breaker.
-func (b *Breaker) Go(work func() error) error {
-	b.lock.RLock()
-	state := b.state
-	b.lock.RUnlock()
-
-	if state == open {
-		return ErrBreakerOpen
-	}
-
-	go func() {
-		var panicValue interface{}
-
-		result := func() error {
-			defer func() {
-				panicValue = recover()
-			}()
-			return work()
-		}()
-
-		if result == nil && panicValue == nil && state == closed {
-			// short-circuit the normal, success path without
-			// contending on the lock
-			return
-		}
-
-		b.processResult(result, panicValue)
-
-		if panicValue != nil {
-			// as close as Go lets us come to a "rethrow" although
-			// unfortunately we lose the original panicing location
-			panic(panicValue)
-		}
-	}()
-
-	return nil
-}
-
 func (b *Breaker) processResult(result error, panicValue interface{}) {
 	b.lock.Lock()
 	defer b.lock.Unlock()