SCB-1059 Optimize backoff package (#530)

diff --git a/pkg/util/backoff.go b/pkg/backoff/backoff.go
similarity index 98%
rename from pkg/util/backoff.go
rename to pkg/backoff/backoff.go
index 7f96cfd..aa02747 100644
--- a/pkg/util/backoff.go
+++ b/pkg/backoff/backoff.go
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package util
+package backoff
 
 import (
 	"math"
diff --git a/pkg/util/backoff_test.go b/pkg/backoff/backoff_test.go
similarity index 98%
rename from pkg/util/backoff_test.go
rename to pkg/backoff/backoff_test.go
index 301a914..8e9ae1f 100644
--- a/pkg/util/backoff_test.go
+++ b/pkg/backoff/backoff_test.go
@@ -14,7 +14,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package util
+package backoff
 
 import (
 	"testing"
diff --git a/pkg/backoff/common.go b/pkg/backoff/common.go
new file mode 100644
index 0000000..e0ce7df
--- /dev/null
+++ b/pkg/backoff/common.go
@@ -0,0 +1,40 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package backoff
+
+import (
+	"fmt"
+	"time"
+)
+
+const DefaultRetryTimes = 5
+
+func DelayIn(times int, f func() error) (err error) {
+	for t := 1; t <= times; t++ {
+		if err = f(); err == nil {
+			return
+		}
+		<-time.After(GetBackoff().Delay(t))
+	}
+	if err == nil {
+		return fmt.Errorf("over max retry times[%d]", times)
+	}
+	return err
+}
+
+func Delay(f func() error) error {
+	return DelayIn(DefaultRetryTimes, f)
+}
diff --git a/pkg/backoff/common_test.go b/pkg/backoff/common_test.go
new file mode 100644
index 0000000..c009131
--- /dev/null
+++ b/pkg/backoff/common_test.go
@@ -0,0 +1,52 @@
+// Licensed to the Apache Software Foundation (ASF) under one or more
+// contributor license agreements.  See the NOTICE file distributed with
+// this work for additional information regarding copyright ownership.
+// The ASF licenses this file to You under the Apache License, Version 2.0
+// (the "License"); you may not use this file except in compliance with
+// the License.  You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package backoff
+
+import (
+	"errors"
+	"testing"
+)
+
+func TestDelay(t *testing.T) {
+	if nil == DelayIn(0, func() error {
+		t.Fatal("TestDelay failed")
+		return nil
+	}) {
+		t.Fatal("TestDelay failed")
+	}
+
+	var times = 0
+	if nil != DelayIn(2, func() error {
+		times++
+		return nil
+	}) || times > 1 {
+		t.Fatal("TestDelay failed")
+	}
+
+	times = 0
+	if nil == DelayIn(2, func() error {
+		times++
+		return errors.New("error")
+	}) || times != 2 {
+		t.Fatal("TestDelay failed")
+	}
+
+	if nil != Delay(func() error {
+		return nil
+	}) {
+		t.Fatal("TestDelay failed")
+	}
+}
diff --git a/pkg/client/sc/client_lb.go b/pkg/client/sc/client_lb.go
index 914b902..55818b1 100644
--- a/pkg/client/sc/client_lb.go
+++ b/pkg/client/sc/client_lb.go
@@ -16,9 +16,9 @@
 package sc
 
 import (
+	"github.com/apache/servicecomb-service-center/pkg/backoff"
 	"github.com/apache/servicecomb-service-center/pkg/lb"
 	"github.com/apache/servicecomb-service-center/pkg/rest"
-	"github.com/apache/servicecomb-service-center/pkg/util"
 	"golang.org/x/net/context"
 	"net/http"
 )
@@ -46,13 +46,9 @@
 }
 
 func (c *LBClient) RestDoWithContext(ctx context.Context, method string, api string, headers http.Header, body []byte) (resp *http.Response, err error) {
-	for i := 0; i < c.Retries; i++ {
-		resp, err = c.HttpDoWithContext(ctx, method, c.Next()+api, headers, body)
-		if err != nil {
-			util.GetBackoff().Delay(i)
-			continue
-		}
-		break
-	}
+	err = backoff.DelayIn(c.Retries, func() (rerr error) {
+		resp, rerr = c.HttpDoWithContext(ctx, method, c.Next()+api, headers, body)
+		return
+	})
 	return
 }
diff --git a/server/core/backend/registry.go b/server/core/backend/registry.go
index 2a1d06e..4534d33 100644
--- a/server/core/backend/registry.go
+++ b/server/core/backend/registry.go
@@ -19,9 +19,9 @@
 import (
 	"errors"
 	"fmt"
+	"github.com/apache/servicecomb-service-center/pkg/backoff"
 	"github.com/apache/servicecomb-service-center/pkg/gopool"
 	"github.com/apache/servicecomb-service-center/pkg/log"
-	"github.com/apache/servicecomb-service-center/pkg/util"
 	"github.com/apache/servicecomb-service-center/server/core"
 	pb "github.com/apache/servicecomb-service-center/server/core/proto"
 	"github.com/apache/servicecomb-service-center/server/plugin"
@@ -77,7 +77,7 @@
 				return engineInstance
 			}
 
-			t := util.GetBackoff().Delay(i)
+			t := backoff.GetBackoff().Delay(i)
 			log.Errorf(nil, "initialize service center failed, retry after %s", t)
 			<-time.After(t)
 		}
diff --git a/server/plugin/pkg/discovery/etcd/cacher_kv.go b/server/plugin/pkg/discovery/etcd/cacher_kv.go
index aa82b42..20596c1 100644
--- a/server/plugin/pkg/discovery/etcd/cacher_kv.go
+++ b/server/plugin/pkg/discovery/etcd/cacher_kv.go
@@ -19,6 +19,7 @@
 import (
 	"errors"
 	"fmt"
+	"github.com/apache/servicecomb-service-center/pkg/backoff"
 	"github.com/apache/servicecomb-service-center/pkg/gopool"
 	"github.com/apache/servicecomb-service-center/pkg/log"
 	"github.com/apache/servicecomb-service-center/pkg/util"
@@ -179,7 +180,7 @@
 		nextPeriod := minWaitInterval
 		if err := c.ListAndWatch(ctx); err != nil {
 			retries++
-			nextPeriod = util.GetBackoff().Delay(retries)
+			nextPeriod = backoff.GetBackoff().Delay(retries)
 		} else {
 			retries = 0
 		}
diff --git a/server/plugin/pkg/registry/etcd/etcd.go b/server/plugin/pkg/registry/etcd/etcd.go
index bac5e43..7af3300 100644
--- a/server/plugin/pkg/registry/etcd/etcd.go
+++ b/server/plugin/pkg/registry/etcd/etcd.go
@@ -20,6 +20,7 @@
 	"crypto/tls"
 	"errors"
 	"fmt"
+	"github.com/apache/servicecomb-service-center/pkg/backoff"
 	errorsEx "github.com/apache/servicecomb-service-center/pkg/errors"
 	"github.com/apache/servicecomb-service-center/pkg/gopool"
 	"github.com/apache/servicecomb-service-center/pkg/log"
@@ -720,7 +721,7 @@
 			for i := 0; i < retries; i++ {
 				ctx, _ := context.WithTimeout(c.Client.Ctx(), healthCheckTimeout)
 				if err = c.SyncMembers(ctx); err != nil {
-					d := util.GetBackoff().Delay(i)
+					d := backoff.GetBackoff().Delay(i)
 					log.Errorf(err, "retry to sync members from etcd %s after %s", c.Endpoints, d)
 					select {
 					case <-pctx.Done():
diff --git a/server/service/event/dependency_event_handler.go b/server/service/event/dependency_event_handler.go
index 6dc50f7..2af407b 100644
--- a/server/service/event/dependency_event_handler.go
+++ b/server/service/event/dependency_event_handler.go
@@ -18,6 +18,7 @@
 
 import (
 	"fmt"
+	"github.com/apache/servicecomb-service-center/pkg/backoff"
 	"github.com/apache/servicecomb-service-center/pkg/gopool"
 	"github.com/apache/servicecomb-service-center/pkg/log"
 	"github.com/apache/servicecomb-service-center/pkg/queue"
@@ -53,10 +54,10 @@
 	h.signals.Put(struct{}{})
 }
 
-func (h *DependencyEventHandler) backoff(backoff func(), retries int) int {
-	if backoff != nil {
-		<-time.After(util.GetBackoff().Delay(retries))
-		backoff()
+func (h *DependencyEventHandler) backoff(f func(), retries int) int {
+	if f != nil {
+		<-time.After(backoff.GetBackoff().Delay(retries))
+		f()
 	}
 	return retries + 1
 }