Repository: go-kratos/kratos
Pull request #3387 (2024-08-05 18:13:38)

build(deps): bump golang.org/x/sync from 0.7.0 to 0.8.0 in /contrib/registry/zookeeper
Bumps [golang.org/x/sync](https://github.com/golang/sync) from 0.7.0 to 0.8.0.
<details>
<summary>Commits</summary>
<ul>
<li><a href="https://github.com/golang/sync/commit/411f99ef121375a146e962b6eab78b03b7429483"><code>411f99e</code></a> LICENSE: update per Google Legal</li>
<li>See full diff in <a href="https://github.com/golang/sync/compare/v0.7.0...v0.8.0">compare view</a></li>
</ul>
</details>
<br />


[![Dependabot compatibility score](https://dependabot-badges.githubapp.com/badges/compatibility_score?dependency-name=golang.org/x/sync&package-manager=go_modules&previous-version=0.7.0&new-version=0.8.0)](https://docs.github.com/en/github/managing-security-vulnerabilities/about-dependabot-security-updates#about-compatibility-scores)

You can trigger a rebase of this PR by commenting `@dependabot rebase`.

[//]: # (dependabot-automerge-start)
[//]: # (dependabot-automerge-end)

---

<details>
<summary>Dependabot commands and options</summary>
<br />

You can trigger Dependabot actions by commenting on this PR:
- `@dependabot rebase` will rebase this PR
- `@dependabot recreate` will recreate this PR, overwriting any edits that have been made to it
- `@dependabot merge` will merge this PR after your CI passes on it
- `@dependabot squash and merge` will squash and merge this PR after your CI passes on it
- `@dependabot cancel merge` will cancel a previously requested merge and block automerging
- `@dependabot reopen` will reopen this PR if it is closed
- `@dependabot close` will close this PR and stop Dependabot recreating it. You can achieve the same result by closing it manually
- `@dependabot show <dependency name> ignore conditions` will show all of the ignore conditions of the specified dependency
- `@dependabot ignore this major version` will close this PR and stop Dependabot creating any more for this major version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this minor version` will close this PR and stop Dependabot creating any more for this minor version (unless you reopen the PR or upgrade to it yourself)
- `@dependabot ignore this dependency` will close this PR and stop Dependabot creating any more for this dependency (unless you reopen the PR or upgrade to it yourself)


</details>

> **Note**
> Automatic rebases have been disabled on this pull request as it has been open for over 30 days.



Patch:
diff --git a/.github/workflows/go.yml b/.github/workflows/go.yml
index 6b8c22df..2f9af451 100644
--- a/.github/workflows/go.yml
+++ b/.github/workflows/go.yml
@@ -25,7 +25,7 @@ jobs:
           ETCD_LISTEN_CLIENT_URLS: http://0.0.0.0:2379
           ETCD_ADVERTISE_CLIENT_URLS: http://0.0.0.0:2379
       consul:
-        image: consul:1.12.3
+        image: hashicorp/consul:1.20
         ports:
           - 8500:8500
       nacos:
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index e6ee0642..e6cb8848 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -31,6 +31,5 @@ jobs:
       - name: Lint
         uses: golangci/golangci-lint-action@v6
         with:
-          version: v1.54.2
-          working-directory: ${{ matrix.workdir }}
-          skip-pkg-cache: true
+          version: v1.61.0
+          working-directory: ${{ matrix.workdir }}
\ No newline at end of file
diff --git a/.golangci.yml b/.golangci.yml
index 556fcfbc..5e7c6d23 100644
--- a/.golangci.yml
+++ b/.golangci.yml
@@ -10,14 +10,15 @@ linters:
     - dogsled
     - durationcheck
     - errcheck
-    - exportloopref
+    # - copyloopvar # need upgrade to Go 1.22
     - govet
+    - staticcheck
     - gosimple
     - gofmt
     - gofumpt
     - goconst
     - goimports
-    - gomnd
+    - mnd
     - gocyclo
     - ineffassign
     - lll
@@ -49,14 +50,15 @@ linters:
 
 linters-settings:
   govet:
-    check-shadowing: true
+    enable:
+      - shadow
   whitespace:
     multi-func: true
   lll:
     line-length: 160
-  gomnd:
+  mnd:
     # don't include the "operation", "argument" and "assign"
-    checks: 
+    checks:
       - case
       - condition
       - return
diff --git a/api/metadata/server.go b/api/metadata/server.go
index e3d5e373..3b9d7c34 100644
--- a/api/metadata/server.go
+++ b/api/metadata/server.go
@@ -148,7 +148,7 @@ func parseMetadata(meta interface{}) (*dpb.FileDescriptorProto, error) {
 	if enc, ok := meta.([]byte); ok {
 		return decodeFileDesc(enc)
 	}
-	return nil, fmt.Errorf("proto not sumpport metadata: %v", meta)
+	return nil, fmt.Errorf("proto does not support metadata: %v", meta)
 }
 
 // decodeFileDesc does decompression and unmarshalling on the given
diff --git a/app.go b/app.go
index 1fa23132..bb406aac 100644
--- a/app.go
+++ b/app.go
@@ -9,12 +9,12 @@ import (
 	"syscall"
 	"time"
 
+	"github.com/google/uuid"
+	"golang.org/x/sync/errgroup"
+
 	"github.com/go-kratos/kratos/v2/log"
 	"github.com/go-kratos/kratos/v2/registry"
 	"github.com/go-kratos/kratos/v2/transport"
-
-	"github.com/google/uuid"
-	"golang.org/x/sync/errgroup"
 )
 
 // AppInfo is application context value.
@@ -99,17 +99,17 @@ func (a *App) Run() error {
 		}
 	}
 	for _, srv := range a.opts.servers {
-		srv := srv
+		server := srv
 		eg.Go(func() error {
 			<-ctx.Done() // wait for stop signal
 			stopCtx, cancel := context.WithTimeout(NewContext(a.opts.ctx, a), a.opts.stopTimeout)
 			defer cancel()
-			return srv.Stop(stopCtx)
+			return server.Stop(stopCtx)
 		})
 		wg.Add(1)
 		eg.Go(func() error {
 			wg.Done() // here is to ensure server start has begun running before register, so defer is not needed
-			return srv.Start(NewContext(a.opts.ctx, a))
+			return server.Start(NewContext(a.opts.ctx, a))
 		})
 	}
 	wg.Wait()
diff --git a/cmd/kratos/internal/change/get.go b/cmd/kratos/internal/change/get.go
index 32046d1e..f1fea42c 100644
--- a/cmd/kratos/internal/change/get.go
+++ b/cmd/kratos/internal/change/get.go
@@ -116,6 +116,7 @@ func ParseCommitsInfo(info []CommitInfo) string {
 		"fix":   {},
 		"feat":  {},
 		"deps":  {},
+		"build": {},
 		"break": {},
 		"chore": {},
 		"other": {},
@@ -127,7 +128,7 @@ func ParseCommitsInfo(info []CommitInfo) string {
 		if index != -1 {
 			msg = msg[:index-1]
 		}
-		prefix := []string{"fix", "feat", "deps", "break", "chore"}
+		prefix := []string{"fix", "feat", "build", "deps", "break", "chore"}
 		var matched bool
 		for _, v := range prefix {
 			msg = strings.TrimPrefix(msg, " ")
@@ -153,6 +154,8 @@ func ParseCommitsInfo(info []CommitInfo) string {
 			text = "### New Features\n"
 		case "fix":
 			text = "### Bug Fixes\n"
+		case "build":
+			text = "### Builds\n"
 		case "chore":
 			text = "### Chores\n"
 		case "other":
@@ -166,7 +169,7 @@ func ParseCommitsInfo(info []CommitInfo) string {
 			md[key] += fmt.Sprintf("- %s\n", value)
 		}
 	}
-	return fmt.Sprint(md["break"], md["deps"], md["feat"], md["fix"], md["chore"], md["other"])
+	return fmt.Sprint(md["break"], md["deps"], md["feat"], md["fix"], md["build"], md["chore"], md["other"])
 }
 
 func ParseReleaseInfo(info ReleaseInfo) string {
diff --git a/cmd/kratos/internal/proto/client/client.go b/cmd/kratos/internal/proto/client/client.go
index cb3f4a76..07e4b490 100644
--- a/cmd/kratos/internal/proto/client/client.go
+++ b/cmd/kratos/internal/proto/client/client.go
@@ -72,7 +72,7 @@ func walk(dir string, args []string) error {
 	if dir == "" {
 		dir = "."
 	}
-	return filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
+	return filepath.Walk(dir, func(path string, _ os.FileInfo, _ error) error {
 		if ext := filepath.Ext(path); ext != ".proto" || strings.HasPrefix(path, "third_party") {
 			return nil
 		}
diff --git a/cmd/kratos/internal/run/run.go b/cmd/kratos/internal/run/run.go
index 2def97a1..3137016f 100644
--- a/cmd/kratos/internal/run/run.go
+++ b/cmd/kratos/internal/run/run.go
@@ -98,7 +98,7 @@ func findCMD(base string) (map[string]string, error) {
 	var root bool
 	next := func(dir string) (map[string]string, error) {
 		cmdPath := make(map[string]string)
-		err := filepath.Walk(dir, func(walkPath string, info os.FileInfo, err error) error {
+		err := filepath.Walk(dir, func(walkPath string, info os.FileInfo, _ error) error {
 			// multi level directory is not allowed under the cmdPath directory, so it is judged that the path ends with cmdPath.
 			if strings.HasSuffix(walkPath, "cmd") {
 				paths, err := os.ReadDir(walkPath)
diff --git a/cmd/kratos/version.go b/cmd/kratos/version.go
index c2115a74..8a5d5093 100644
--- a/cmd/kratos/version.go
+++ b/cmd/kratos/version.go
@@ -1,4 +1,4 @@
 package main
 
 // release is the current kratos tool version.
-const release = "v2.8.0"
+const release = "v2.8.1"
diff --git a/cmd/protoc-gen-go-errors/buf.gen.yaml b/cmd/protoc-gen-go-errors/buf.gen.yaml
new file mode 100644
index 00000000..27ea54a0
--- /dev/null
+++ b/cmd/protoc-gen-go-errors/buf.gen.yaml
@@ -0,0 +1,6 @@
+version: v2
+plugins:
+  - remote: buf.build/protocolbuffers/go:v1.33.0
+    out: .
+    opt:
+      - paths=source_relative
diff --git a/cmd/protoc-gen-go-errors/buf.lock b/cmd/protoc-gen-go-errors/buf.lock
new file mode 100644
index 00000000..4f98143f
--- /dev/null
+++ b/cmd/protoc-gen-go-errors/buf.lock
@@ -0,0 +1,2 @@
+# Generated by buf. DO NOT EDIT.
+version: v2
diff --git a/cmd/protoc-gen-go-errors/buf.yaml b/cmd/protoc-gen-go-errors/buf.yaml
new file mode 100644
index 00000000..8c3d4ddb
--- /dev/null
+++ b/cmd/protoc-gen-go-errors/buf.yaml
@@ -0,0 +1,16 @@
+version: v2
+name: buf.build/go-kratos/protoc-gen-go-errors
+lint:
+  use:
+    - DEFAULT
+  except:
+    - PACKAGE_DIRECTORY_MATCH
+    - ENUM_VALUE_UPPER_SNAKE_CASE
+    - ENUM_VALUE_PREFIX
+    - ENUM_ZERO_VALUE_SUFFIX
+    - FIELD_LOWER_SNAKE_CASE
+deps:
+  - buf.build/googleapis/googleapis
+breaking:
+  use:
+    - FILE
diff --git a/cmd/protoc-gen-go-errors/version.go b/cmd/protoc-gen-go-errors/version.go
index f7a3aa86..92f84a09 100644
--- a/cmd/protoc-gen-go-errors/version.go
+++ b/cmd/protoc-gen-go-errors/version.go
@@ -1,4 +1,4 @@
 package main
 
 // release is the current protoc-gen-go-errors version.
-const release = "v2.8.0"
+const release = "v2.8.1"
diff --git a/cmd/protoc-gen-go-http/version.go b/cmd/protoc-gen-go-http/version.go
index ec82da2b..1c973e7a 100644
--- a/cmd/protoc-gen-go-http/version.go
+++ b/cmd/protoc-gen-go-http/version.go
@@ -1,4 +1,4 @@
 package main
 
 // release is the current protoc-gen-go-http version.
-const release = "v2.8.0"
+const release = "v2.8.1"
diff --git a/config/env/env.go b/config/env/env.go
index cdd30e1b..ecd5c6ff 100644
--- a/config/env/env.go
+++ b/config/env/env.go
@@ -23,7 +23,7 @@ func (e *env) load(envs []string) []*config.KeyValue {
 	var kv []*config.KeyValue
 	for _, env := range envs {
 		var k, v string
-		subs := strings.SplitN(env, "=", 2) //nolint:gomnd
+		subs := strings.SplitN(env, "=", 2) //nolint:mnd
 		k = subs[0]
 		if len(subs) > 1 {
 			v = subs[1]
diff --git a/config/options.go b/config/options.go
index 95d6f6d3..7395660d 100644
--- a/config/options.go
+++ b/config/options.go
@@ -137,7 +137,7 @@ func resolver(input map[string]interface{}, mapper func(name string) string, toT
 
 func mapper(input map[string]interface{}) func(name string) string {
 	mapper := func(name string) string {
-		args := strings.SplitN(strings.TrimSpace(name), ":", 2) //nolint:gomnd
+		args := strings.SplitN(strings.TrimSpace(name), ":", 2) //nolint:mnd
 		if v, has := readValue(input, args[0]); has {
 			s, _ := v.String()
 			return s
@@ -183,7 +183,7 @@ func expand(s string, mapping func(string) string, toType bool) interface{} {
 	re := r.FindAllStringSubmatch(s, -1)
 	var ct interface{}
 	for _, i := range re {
-		if len(i) == 2 { //nolint:gomnd
+		if len(i) == 2 { //nolint:mnd
 			m := mapping(i[1])
 			if toType {
 				ct = convertToType(m)
diff --git a/contrib/config/apollo/go.mod b/contrib/config/apollo/go.mod
index f1a0293a..736f97ca 100644
--- a/contrib/config/apollo/go.mod
+++ b/contrib/config/apollo/go.mod
@@ -4,7 +4,7 @@ go 1.19
 
 require (
 	github.com/apolloconfig/agollo/v4 v4.3.1
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 )
 
 require (
diff --git a/contrib/config/consul/go.mod b/contrib/config/consul/go.mod
index cb0d0422..34880590 100644
--- a/contrib/config/consul/go.mod
+++ b/contrib/config/consul/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/config/consul/v2
 go 1.19
 
 require (
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 	github.com/hashicorp/consul/api v1.26.1
 )
 
diff --git a/contrib/config/etcd/go.mod b/contrib/config/etcd/go.mod
index cfe94b62..e739f30f 100644
--- a/contrib/config/etcd/go.mod
+++ b/contrib/config/etcd/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/config/etcd/v2
 go 1.19
 
 require (
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 	go.etcd.io/etcd/client/v3 v3.5.11
 	google.golang.org/grpc v1.61.1
 )
diff --git a/contrib/config/kubernetes/go.mod b/contrib/config/kubernetes/go.mod
index d1203d74..3746535f 100644
--- a/contrib/config/kubernetes/go.mod
+++ b/contrib/config/kubernetes/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/config/kubernetes/v2
 go 1.19
 
 require (
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 	k8s.io/api v0.26.3
 	k8s.io/apimachinery v0.26.3
 	k8s.io/client-go v0.26.3
diff --git a/contrib/config/nacos/go.mod b/contrib/config/nacos/go.mod
index fb7391bb..fb7773dc 100644
--- a/contrib/config/nacos/go.mod
+++ b/contrib/config/nacos/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/config/nacos/v2
 go 1.19
 
 require (
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 	github.com/nacos-group/nacos-sdk-go v1.0.9
 )
 
diff --git a/contrib/config/polaris/go.mod b/contrib/config/polaris/go.mod
index 11b9c4bd..c10dd6b5 100644
--- a/contrib/config/polaris/go.mod
+++ b/contrib/config/polaris/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/config/polaris/v2
 go 1.19
 
 require (
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 	github.com/polarismesh/polaris-go v1.1.0
 )
 
diff --git a/contrib/encoding/msgpack/go.mod b/contrib/encoding/msgpack/go.mod
index 11d0e8bf..0de42d06 100644
--- a/contrib/encoding/msgpack/go.mod
+++ b/contrib/encoding/msgpack/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/encoding/msgpack/v2
 go 1.19
 
 require (
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 	github.com/vmihailenco/msgpack/v5 v5.4.1
 )
 
diff --git a/contrib/errortracker/sentry/go.mod b/contrib/errortracker/sentry/go.mod
index 4604ca97..0720da6d 100644
--- a/contrib/errortracker/sentry/go.mod
+++ b/contrib/errortracker/sentry/go.mod
@@ -4,7 +4,7 @@ go 1.19
 
 require (
 	github.com/getsentry/sentry-go v0.25.0
-	github.com/go-kratos/kratos/v2 v2.0.0-00010101000000-000000000000
+	github.com/go-kratos/kratos/v2 v2.8.1
 )
 
 require (
diff --git a/contrib/log/aliyun/go.mod b/contrib/log/aliyun/go.mod
index a9086725..e6fbbeee 100644
--- a/contrib/log/aliyun/go.mod
+++ b/contrib/log/aliyun/go.mod
@@ -4,7 +4,7 @@ go 1.19
 
 require (
 	github.com/aliyun/aliyun-log-go-sdk v0.1.75
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 	google.golang.org/protobuf v1.33.0
 )
 
diff --git a/contrib/log/fluent/go.mod b/contrib/log/fluent/go.mod
index 15a99cd2..e0996bae 100644
--- a/contrib/log/fluent/go.mod
+++ b/contrib/log/fluent/go.mod
@@ -4,7 +4,7 @@ go 1.19
 
 require (
 	github.com/fluent/fluent-logger-golang v1.9.0
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 )
 
 require (
diff --git a/contrib/log/logrus/go.mod b/contrib/log/logrus/go.mod
index d6d54f60..5f8c9b3e 100644
--- a/contrib/log/logrus/go.mod
+++ b/contrib/log/logrus/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/log/logrus/v2
 go 1.19
 
 require (
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 	github.com/sirupsen/logrus v1.8.1
 )
 
diff --git a/contrib/log/tencent/go.mod b/contrib/log/tencent/go.mod
index 5ebacf7a..c77d1670 100644
--- a/contrib/log/tencent/go.mod
+++ b/contrib/log/tencent/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/log/tencent/v2
 go 1.19
 
 require (
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 	github.com/tencentcloud/tencentcloud-cls-sdk-go v1.0.2
 	google.golang.org/protobuf v1.33.0
 )
diff --git a/contrib/log/zap/go.mod b/contrib/log/zap/go.mod
index e630c836..faf10ee1 100644
--- a/contrib/log/zap/go.mod
+++ b/contrib/log/zap/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/log/zap/v2
 go 1.19
 
 require (
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 	go.uber.org/zap v1.26.0
 )
 
diff --git a/contrib/log/zap/zap.go b/contrib/log/zap/zap.go
index acf453fe..812afb95 100644
--- a/contrib/log/zap/zap.go
+++ b/contrib/log/zap/zap.go
@@ -4,6 +4,7 @@ import (
 	"fmt"
 
 	"go.uber.org/zap"
+	"go.uber.org/zap/zapcore"
 
 	"github.com/go-kratos/kratos/v2/log"
 )
@@ -32,6 +33,11 @@ func NewLogger(zlog *zap.Logger) *Logger {
 }
 
 func (l *Logger) Log(level log.Level, keyvals ...interface{}) error {
+	// If logging at this level is completely disabled, skip the overhead of
+	// string formatting.
+	if zapcore.Level(level) < zapcore.DPanicLevel && !l.log.Core().Enabled(zapcore.Level(level)) {
+		return nil
+	}
 	var (
 		msg    = ""
 		keylen = len(keyvals)
diff --git a/contrib/log/zerolog/go.mod b/contrib/log/zerolog/go.mod
index 3a4a7b9c..ac37f0f2 100644
--- a/contrib/log/zerolog/go.mod
+++ b/contrib/log/zerolog/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/log/zerolog/v2
 go 1.19
 
 require (
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 	github.com/rs/zerolog v1.30.0
 )
 
diff --git a/contrib/opensergo/go.mod b/contrib/opensergo/go.mod
index 57c904fe..4d0ec72a 100644
--- a/contrib/opensergo/go.mod
+++ b/contrib/opensergo/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/opensergo/v2
 go 1.19
 
 require (
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 	github.com/opensergo/opensergo-go v0.0.0-20220331070310-e5b01fee4d1c
 	golang.org/x/net v0.24.0
 	google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917
diff --git a/contrib/polaris/go.mod b/contrib/polaris/go.mod
index e732af84..e59ee435 100644
--- a/contrib/polaris/go.mod
+++ b/contrib/polaris/go.mod
@@ -4,7 +4,7 @@ go 1.19
 
 require (
 	github.com/go-kratos/aegis v0.2.0
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 	github.com/google/uuid v1.4.0
 	github.com/polarismesh/polaris-go v1.3.0
 	google.golang.org/protobuf v1.33.0
diff --git a/contrib/polaris/registry.go b/contrib/polaris/registry.go
index 4d1e4a33..9a8472c0 100644
--- a/contrib/polaris/registry.go
+++ b/contrib/polaris/registry.go
@@ -115,15 +115,16 @@ func (r *Registry) Register(_ context.Context, instance *registry.ServiceInstanc
 		}
 
 		// metadata
-		if instance.Metadata == nil {
-			instance.Metadata = make(map[string]string)
+		rmd := mapClone(instance.Metadata)
+		if rmd == nil {
+			rmd = make(map[string]string)
 		}
-		instance.Metadata["merge"] = id
-		if _, ok := instance.Metadata["weight"]; !ok {
-			instance.Metadata["weight"] = strconv.Itoa(r.opt.Weight)
+		rmd["merge"] = id
+		if _, ok := rmd["weight"]; !ok {
+			rmd["weight"] = strconv.Itoa(r.opt.Weight)
 		}
 
-		weight, _ := strconv.Atoi(instance.Metadata["weight"])
+		weight, _ := strconv.Atoi(rmd["weight"])
 
 		_, err = r.provider.RegisterInstance(
 			&polaris.InstanceRegisterRequest{
@@ -137,7 +138,7 @@ func (r *Registry) Register(_ context.Context, instance *registry.ServiceInstanc
 					Weight:       &weight,
 					Priority:     &r.opt.Priority,
 					Version:      &instance.Version,
-					Metadata:     instance.Metadata,
+					Metadata:     rmd,
 					Healthy:      &r.opt.Healthy,
 					Isolate:      &r.opt.Isolate,
 					TTL:          &r.opt.TTL,
@@ -378,3 +379,18 @@ func instancesToServiceInstances(instances map[string][]model.Instance) []*regis
 	}
 	return serviceInstances
 }
+
+// Clone returns a copy of m. This is a shallow clone:
+// the new keys and values are set using ordinary assignment.
+func mapClone[M ~map[K]V, K comparable, V any](m M) M {
+	// Preserve nil in case it matters.
+	if m == nil {
+		return nil
+	}
+	// Make a shallow copy of the map.
+	m2 := make(M, len(m))
+	for k, v := range m {
+		m2[k] = v
+	}
+	return m2
+}
diff --git a/contrib/polaris/router.go b/contrib/polaris/router.go
index 2478b58b..93202eb5 100644
--- a/contrib/polaris/router.go
+++ b/contrib/polaris/router.go
@@ -139,7 +139,7 @@ func buildPolarisInstance(namespace string, nodes []selector.Node) *pb.ServiceIn
 		Service:   &v1.Service{Name: wrapperspb.String(nodes[0].ServiceName()), Namespace: wrapperspb.String("default")},
 		Instances: ins,
 	}
-	return pb.NewServiceInstancesInProto(d, func(s string) local.InstanceLocalValue {
+	return pb.NewServiceInstancesInProto(d, func(string) local.InstanceLocalValue {
 		return local.NewInstanceLocalValue()
 	}, &pb.SvcPluginValues{Routers: nil, Loadbalancer: nil}, nil)
 }
diff --git a/contrib/registry/consul/go.mod b/contrib/registry/consul/go.mod
index d739fbc4..26f526fa 100644
--- a/contrib/registry/consul/go.mod
+++ b/contrib/registry/consul/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/consul/v2
 go 1.19
 
 require (
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 	github.com/hashicorp/consul/api v1.26.1
 )
 
diff --git a/contrib/registry/consul/registry.go b/contrib/registry/consul/registry.go
index c83fa74c..5b098384 100644
--- a/contrib/registry/consul/registry.go
+++ b/contrib/registry/consul/registry.go
@@ -190,7 +190,6 @@ func (r *Registry) Watch(ctx context.Context, name string) (registry.Watcher, er
 			services:    &atomic.Value{},
 			serviceName: name,
 		}
-		set.ctx, set.cancel = context.WithCancel(context.Background())
 		r.registry[name] = set
 	}
 
@@ -209,10 +208,8 @@ func (r *Registry) Watch(ctx context.Context, name string) (registry.Watcher, er
 		// otherwise the initial data may be blocked forever during the watch.
 		w.event <- struct{}{}
 	}
-	if !ok {
-		if err := r.resolve(set.ctx, set); err != nil {
-			return nil, err
-		}
+	if err := r.resolve(ctx, set); err != nil {
+		return nil, err
 	}
 	return w, nil
 }
@@ -248,9 +245,6 @@ func (r *Registry) resolve(ctx context.Context, ss *serviceSet) error {
 				}
 				idx = tmpIdx
 			case <-ctx.Done():
-				r.lock.Lock()
-				delete(r.registry, ss.serviceName)
-				r.lock.Unlock()
 				return
 			}
 		}
diff --git a/contrib/registry/consul/service.go b/contrib/registry/consul/service.go
index 6567b772..a0a16609 100644
--- a/contrib/registry/consul/service.go
+++ b/contrib/registry/consul/service.go
@@ -1,7 +1,6 @@
 package consul
 
 import (
-	"context"
 	"sync"
 	"sync/atomic"
 
@@ -13,9 +12,6 @@ type serviceSet struct {
 	watcher     map[*watcher]struct{}
 	services    *atomic.Value
 	lock        sync.RWMutex
-
-	ctx    context.Context
-	cancel context.CancelFunc
 }
 
 func (s *serviceSet) broadcast(ss []*registry.ServiceInstance) {
diff --git a/contrib/registry/consul/watcher.go b/contrib/registry/consul/watcher.go
index f84caeb4..0a5d3575 100644
--- a/contrib/registry/consul/watcher.go
+++ b/contrib/registry/consul/watcher.go
@@ -36,9 +36,5 @@ func (w *watcher) Stop() error {
 	w.set.lock.Lock()
 	defer w.set.lock.Unlock()
 	delete(w.set.watcher, w)
-	// close resolve
-	if len(w.set.watcher) == 0 {
-		w.set.cancel()
-	}
 	return nil
 }
diff --git a/contrib/registry/discovery/go.mod b/contrib/registry/discovery/go.mod
index eb260ac6..2331b533 100644
--- a/contrib/registry/discovery/go.mod
+++ b/contrib/registry/discovery/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/discovery/v2
 go 1.19
 
 require (
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 	github.com/go-resty/resty/v2 v2.11.0
 	github.com/pkg/errors v0.9.1
 )
diff --git a/contrib/registry/etcd/go.mod b/contrib/registry/etcd/go.mod
index 3c1e7e68..3c39306a 100644
--- a/contrib/registry/etcd/go.mod
+++ b/contrib/registry/etcd/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/etcd/v2
 go 1.19
 
 require (
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 	go.etcd.io/etcd/client/v3 v3.5.11
 	google.golang.org/grpc v1.61.1
 )
diff --git a/contrib/registry/etcd/registry.go b/contrib/registry/etcd/registry.go
index 476436e2..1a931153 100644
--- a/contrib/registry/etcd/registry.go
+++ b/contrib/registry/etcd/registry.go
@@ -162,7 +162,7 @@ func (r *Registry) heartBeat(ctx context.Context, leaseID clientv3.LeaseID, key
 	if err != nil {
 		curLeaseID = 0
 	}
-	rand.Seed(time.Now().Unix())
+	randSource := rand.New(rand.NewSource(time.Now().Unix()))
 
 	for {
 		if curLeaseID == 0 {
@@ -200,7 +200,7 @@ func (r *Registry) heartBeat(ctx context.Context, leaseID clientv3.LeaseID, key
 					break
 				}
 				retreat = append(retreat, 1<<retryCnt)
-				time.Sleep(time.Duration(retreat[rand.Intn(len(retreat))]) * time.Second)
+				time.Sleep(time.Duration(retreat[randSource.Intn(len(retreat))]) * time.Second)
 			}
 			if _, ok := <-kac; !ok {
 				// retry failed
diff --git a/contrib/registry/eureka/client.go b/contrib/registry/eureka/client.go
index 3b985c5b..0c19cd3f 100644
--- a/contrib/registry/eureka/client.go
+++ b/contrib/registry/eureka/client.go
@@ -292,10 +292,10 @@ func (e *Client) pickServer(currentTimes int) string {
 }
 
 func (e *Client) shuffle() {
-	rand.Seed(time.Now().UnixNano())
-	rand.Shuffle(len(e.urls), func(i, j int) {
-		e.urls[i], e.urls[j] = e.urls[j], e.urls[i]
-	})
+	rand.New(rand.NewSource(time.Now().UnixNano())).
+		Shuffle(len(e.urls), func(i, j int) {
+			e.urls[i], e.urls[j] = e.urls[j], e.urls[i]
+		})
 }
 
 func (e *Client) buildAPI(currentTimes int, params ...string) string {
diff --git a/contrib/registry/eureka/go.mod b/contrib/registry/eureka/go.mod
index d0dd0c48..0dd9f250 100644
--- a/contrib/registry/eureka/go.mod
+++ b/contrib/registry/eureka/go.mod
@@ -2,6 +2,6 @@ module github.com/go-kratos/kratos/contrib/registry/eureka/v2
 
 go 1.19
 
-require github.com/go-kratos/kratos/v2 v2.8.0
+require github.com/go-kratos/kratos/v2 v2.8.1
 
 replace github.com/go-kratos/kratos/v2 => ../../../
diff --git a/contrib/registry/kubernetes/go.mod b/contrib/registry/kubernetes/go.mod
index 2631508b..711a963a 100644
--- a/contrib/registry/kubernetes/go.mod
+++ b/contrib/registry/kubernetes/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/kubernetes/v2
 go 1.19
 
 require (
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 	github.com/json-iterator/go v1.1.12
 	k8s.io/api v0.24.3
 	k8s.io/apimachinery v0.24.3
diff --git a/contrib/registry/kubernetes/registry.go b/contrib/registry/kubernetes/registry.go
index 21562dc5..7379abf3 100644
--- a/contrib/registry/kubernetes/registry.go
+++ b/contrib/registry/kubernetes/registry.go
@@ -205,13 +205,13 @@ func (s *Registry) Watch(ctx context.Context, name string) (registry.Watcher, er
 			}
 		},
 		Handler: cache.ResourceEventHandlerFuncs{
-			AddFunc: func(obj interface{}) {
+			AddFunc: func(interface{}) {
 				s.sendLatestInstances(ctx, name, announcement)
 			},
-			UpdateFunc: func(oldObj, newObj interface{}) {
+			UpdateFunc: func(interface{}, interface{}) {
 				s.sendLatestInstances(ctx, name, announcement)
 			},
-			DeleteFunc: func(obj interface{}) {
+			DeleteFunc: func(interface{}) {
 				s.sendLatestInstances(ctx, name, announcement)
 			},
 		},
diff --git a/contrib/registry/nacos/go.mod b/contrib/registry/nacos/go.mod
index a7780041..e8c2d405 100644
--- a/contrib/registry/nacos/go.mod
+++ b/contrib/registry/nacos/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/nacos/v2
 go 1.19
 
 require (
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 	github.com/nacos-group/nacos-sdk-go v1.0.9
 )
 
diff --git a/contrib/registry/nacos/watcher.go b/contrib/registry/nacos/watcher.go
index 7f1dc846..16cec4ab 100644
--- a/contrib/registry/nacos/watcher.go
+++ b/contrib/registry/nacos/watcher.go
@@ -40,7 +40,7 @@ func newWatcher(ctx context.Context, cli naming_client.INamingClient, serviceNam
 		ServiceName: serviceName,
 		Clusters:    clusters,
 		GroupName:   groupName,
-		SubscribeCallback: func(services []model.SubscribeService, err error) {
+		SubscribeCallback: func([]model.SubscribeService, error) {
 			select {
 			case w.watchChan <- struct{}{}:
 			default:
diff --git a/contrib/registry/polaris/go.mod b/contrib/registry/polaris/go.mod
index e18c6cb6..e26b3a9e 100644
--- a/contrib/registry/polaris/go.mod
+++ b/contrib/registry/polaris/go.mod
@@ -3,7 +3,7 @@ module github.com/go-kratos/kratos/contrib/registry/polaris/v2
 go 1.19
 
 require (
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 	github.com/polarismesh/polaris-go v1.3.0
 )
 
diff --git a/contrib/registry/servicecomb/go.mod b/contrib/registry/servicecomb/go.mod
index 3a8761cb..f13aa051 100644
--- a/contrib/registry/servicecomb/go.mod
+++ b/contrib/registry/servicecomb/go.mod
@@ -5,7 +5,7 @@ go 1.19
 require (
 	github.com/go-chassis/cari v0.6.0
 	github.com/go-chassis/sc-client v0.6.1-0.20210615014358-a45e9090c751
-	github.com/go-kratos/kratos/v2 v2.3.1
+	github.com/go-kratos/kratos/v2 v2.8.1
 	github.com/gofrs/uuid v4.2.0+incompatible
 )
 
@@ -17,3 +17,5 @@ require (
 	github.com/gorilla/websocket v1.4.3-0.20210424162022-e8629af678b7 // indirect
 	golang.org/x/net v0.23.0 // indirect
 )
+
+replace github.com/go-kratos/kratos/v2 => ../../../
diff --git a/contrib/registry/servicecomb/go.sum b/contrib/registry/servicecomb/go.sum
index dfc28b92..e893de1a 100644
--- a/contrib/registry/servicecomb/go.sum
+++ b/contrib/registry/servicecomb/go.sum
@@ -1,30 +1,8 @@
-cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
-github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
-github.com/StackExchange/wmi v1.2.1/go.mod h1:rcmrprowKIVzvc+NUiLncP2uuArMWLCbu9SBzvHz7e8=
-github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
 github.com/cenkalti/backoff v2.0.0+incompatible h1:5IIPUHhlnUZbcHQsQou5k1Tn58nJkeJL9U+ig5CHJbY=
 github.com/cenkalti/backoff v2.0.0+incompatible/go.mod h1:90ReRw6GdpyfrHakVjL/QHaoyV4aDUVVkXQJJJ3NXXM=
-github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
-github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
-github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
-github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
-github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
-github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI=
-github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20211001041855-01bcc9b48dfe/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
-github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ=
-github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
-github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
-github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
-github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
-github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
-github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
 github.com/go-chassis/cari v0.4.0/go.mod h1:av/19fqwEP4eOC8unL/z67AAbFDwXUCko6SKa4Avrd8=
 github.com/go-chassis/cari v0.6.0 h1:cwBchwt9L8JOyO6QkzXFAsseMJ10zVSiVK8eDLD0HkA=
 github.com/go-chassis/cari v0.6.0/go.mod h1:mSDRCOQXGmlD69A6NG0hsv0UP1xbVPtL6HCGI6X1tqs=
@@ -36,15 +14,6 @@ github.com/go-chassis/openlog v1.1.3 h1:XqIOvZ8YPJ9o9lLtLBskQNNWolK5kC6a4Sv7r4s9
 github.com/go-chassis/openlog v1.1.3/go.mod h1:+eYCADVxWyJkwsFMUBrMxyQlNqW+UUsCxvR2LrYZUaA=
 github.com/go-chassis/sc-client v0.6.1-0.20210615014358-a45e9090c751 h1:hpWN/MZBMsnJqXdMkW7v0wsC+4rYulPsBFMrHCmZMQc=
 github.com/go-chassis/sc-client v0.6.1-0.20210615014358-a45e9090c751/go.mod h1:TBS9g7OaIeu1OR/9tVPJEl6BgHFcYEdbuJlgVDQczbc=
-github.com/go-kratos/aegis v0.1.2/go.mod h1:jYeSQ3Gesba478zEnujOiG5QdsyF3Xk/8owFUeKcHxw=
-github.com/go-kratos/kratos/v2 v2.3.1 h1:Qfx3JSEIrfZl0f8mXvbeGv3tRIZ2L/ArhcKwxAr3uMo=
-github.com/go-kratos/kratos/v2 v2.3.1/go.mod h1:5acyLj4EgY428AJnZl2EwCrMV1OVlttQFBum+SghMiA=
-github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/logr v1.2.3/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
-github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
-github.com/go-ole/go-ole v1.2.5/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
-github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
-github.com/go-playground/form/v4 v4.2.0/go.mod h1:q1a2BY+AQUUzhl6xA/6hBetay6dEIhMHjgvJiGo6K7U=
 github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
 github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
 github.com/go-playground/validator v9.31.0+incompatible/go.mod h1:yrEkQXlcI+PugkyDjY2bRrL/UBU4f3rvrgkN3V8JEig=
@@ -53,38 +22,9 @@ github.com/gofrs/uuid v4.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRx
 github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
 github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
 github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
-github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
-github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
-github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
-github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
-github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
-github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
-github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
-github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
-github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
-github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
-github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
-github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
-github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
-github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
-github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
-github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
-github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
-github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
-github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
 github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
 github.com/gorilla/websocket v1.4.3-0.20210424162022-e8629af678b7 h1:L89uC9ATI61/V2eNgZYtQHyjjyjEplemB+aky4HdyzQ=
 github.com/gorilla/websocket v1.4.3-0.20210424162022-e8629af678b7/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
-github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
-github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
 github.com/karlseguin/ccache/v2 v2.0.8/go.mod h1:2BDThcfQMf/c0jnZowt16eW405XIqZPavt+HoYEtcxQ=
 github.com/karlseguin/expect v1.0.2-0.20190806010014-778a5f0c6003/go.mod h1:zNBxMY8P21owkeogJELCLeHIt+voOSduHYTFUbwRAV8=
 github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
@@ -93,80 +33,38 @@ github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+o
 github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
-github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
-github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
-github.com/shirou/gopsutil/v3 v3.21.8/go.mod h1:YWp/H8Qs5fVmf17v7JNZzA0mPJ+mS2e9JdiUF9LlKzQ=
 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
-github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
 github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/stretchr/testify v1.7.1 h1:5TQK59W5E3v0r2duFAb7P95B6hEeOyEnHRa8MjYSMTY=
-github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
-github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ3LSFUzyeuhs=
-github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
+github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
 github.com/wsxiaoys/terminal v0.0.0-20160513160801-0940f3fc43a0/go.mod h1:IXCdmsXIht47RaVFLEdVnh1t+pgYtTAhQGj73kz+2DM=
 github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
-go.opentelemetry.io/otel v1.7.0/go.mod h1:5BdUoMIz5WEs0vt0CUEMtSSaTSHBBVwrhnz7+nrD5xk=
-go.opentelemetry.io/otel/sdk v1.7.0/go.mod h1:uTEOTwaqIVuTGiJN7ii13Ibp75wJmYUDe374q6cZwUU=
-go.opentelemetry.io/otel/trace v1.7.0/go.mod h1:fzLSB9nqR2eXzxPXb2JW9IKE+ScyXA48yyE4TNvoHqU=
-go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
 golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
-golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
-golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
-golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
 golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
-golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
 golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
-golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
 golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
 golang.org/x/net v0.0.0-20201209123823-ac852fbbde11/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
-golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
 golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
 golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
-golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
-golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
-golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
 golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20220513210516-0976fa681c29/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sync v0.5.0 h1:60k92dhOjHxJkrqnwsfl8KuaHbn/5dl0lUPUklKo3qE=
 golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
 golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
-golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
-golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
-golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
-golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
 golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
@@ -174,40 +72,6 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
 golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
-google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
-google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
-google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
-google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
-google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
-google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
-google.golang.org/genproto v0.0.0-20220519153652-3a47de7e79bd/go.mod h1:RAyBrSAP7Fh3Nc84ghnVLDPuV51xc9agzmm4Ph6i0Q4=
-google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
-google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
-google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
-google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
-google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
-google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
-google.golang.org/grpc v1.46.0/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/grpc v1.46.2/go.mod h1:vN9eftEi1UMyUsIF80+uQXhHjbXYbm0uXoFCACuMGWk=
-google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
-google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
-google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
-google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
-google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
-google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
-google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
-google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
-google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
-google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
-gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
-gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-gopkg.in/yaml.v3 v3.0.0 h1:hjy8E9ON/egN1tAYqKb61G10WtihqetD4sz2H+8nIeA=
-gopkg.in/yaml.v3 v3.0.0/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
-honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
-honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
+gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
diff --git a/contrib/registry/zookeeper/go.mod b/contrib/registry/zookeeper/go.mod
index 16c191bc..627454bc 100644
--- a/contrib/registry/zookeeper/go.mod
+++ b/contrib/registry/zookeeper/go.mod
@@ -3,9 +3,9 @@ module github.com/go-kratos/kratos/contrib/registry/zookeeper/v2
 go 1.19
 
 require (
-	github.com/go-kratos/kratos/v2 v2.8.0
+	github.com/go-kratos/kratos/v2 v2.8.1
 	github.com/go-zookeeper/zk v1.0.3
-	golang.org/x/sync v0.7.0
+	golang.org/x/sync v0.8.0
 )
 
 replace github.com/go-kratos/kratos/v2 => ../../../
diff --git a/contrib/registry/zookeeper/go.sum b/contrib/registry/zookeeper/go.sum
index 0261f031..789f61e0 100644
--- a/contrib/registry/zookeeper/go.sum
+++ b/contrib/registry/zookeeper/go.sum
@@ -1,4 +1,4 @@
 github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg=
 github.com/go-zookeeper/zk v1.0.3/go.mod h1:nOB03cncLtlp4t+UAkGSV+9beXP/akpekBwL+UX1Qcw=
-golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
-golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ=
+golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
diff --git a/encoding/form/proto_decode.go b/encoding/form/proto_decode.go
index 5b68b92e..cdd93108 100644
--- a/encoding/form/proto_decode.go
+++ b/encoding/form/proto_decode.go
@@ -172,7 +172,7 @@ func parseField(fd protoreflect.FieldDescriptor, value string) (protoreflect.Val
 		}
 		v := enum.Descriptor().Values().ByName(protoreflect.Name(value))
 		if v == nil {
-			i, err := strconv.ParseInt(value, 10, 32) //nolint:gomnd
+			i, err := strconv.ParseInt(value, 10, 32) //nolint:mnd
 			if err != nil {
 				return protoreflect.Value{}, fmt.Errorf("%q is not a valid value", value)
 			}
@@ -183,37 +183,37 @@ func parseField(fd protoreflect.FieldDescriptor, value string) (protoreflect.Val
 		}
 		return protoreflect.ValueOfEnum(v.Number()), nil
 	case protoreflect.Int32Kind, protoreflect.Sint32Kind, protoreflect.Sfixed32Kind:
-		v, err := strconv.ParseInt(value, 10, 32) //nolint:gomnd
+		v, err := strconv.ParseInt(value, 10, 32) //nolint:mnd
 		if err != nil {
 			return protoreflect.Value{}, err
 		}
 		return protoreflect.ValueOfInt32(int32(v)), nil
 	case protoreflect.Int64Kind, protoreflect.Sint64Kind, protoreflect.Sfixed64Kind:
-		v, err := strconv.ParseInt(value, 10, 64) //nolint:gomnd
+		v, err := strconv.ParseInt(value, 10, 64) //nolint:mnd
 		if err != nil {
 			return protoreflect.Value{}, err
 		}
 		return protoreflect.ValueOfInt64(v), nil
 	case protoreflect.Uint32Kind, protoreflect.Fixed32Kind:
-		v, err := strconv.ParseUint(value, 10, 32) //nolint:gomnd
+		v, err := strconv.ParseUint(value, 10, 32) //nolint:mnd
 		if err != nil {
 			return protoreflect.Value{}, err
 		}
 		return protoreflect.ValueOfUint32(uint32(v)), nil
 	case protoreflect.Uint64Kind, protoreflect.Fixed64Kind:
-		v, err := strconv.ParseUint(value, 10, 64) //nolint:gomnd
+		v, err := strconv.ParseUint(value, 10, 64) //nolint:mnd
 		if err != nil {
 			return protoreflect.Value{}, err
 		}
 		return protoreflect.ValueOfUint64(v), nil
 	case protoreflect.FloatKind:
-		v, err := strconv.ParseFloat(value, 32) //nolint:gomnd
+		v, err := strconv.ParseFloat(value, 32) //nolint:mnd
 		if err != nil {
 			return protoreflect.Value{}, err
 		}
 		return protoreflect.ValueOfFloat32(float32(v)), nil
 	case protoreflect.DoubleKind:
-		v, err := strconv.ParseFloat(value, 64) //nolint:gomnd
+		v, err := strconv.ParseFloat(value, 64) //nolint:mnd
 		if err != nil {
 			return protoreflect.Value{}, err
 		}
@@ -255,37 +255,37 @@ func parseMessage(md protoreflect.MessageDescriptor, value string) (protoreflect
 		}
 		msg = durationpb.New(d)
 	case "google.protobuf.DoubleValue":
-		v, err := strconv.ParseFloat(value, 64) //nolint:gomnd
+		v, err := strconv.ParseFloat(value, 64) //nolint:mnd
 		if err != nil {
 			return protoreflect.Value{}, err
 		}
 		msg = wrapperspb.Double(v)
 	case "google.protobuf.FloatValue":
-		v, err := strconv.ParseFloat(value, 32) //nolint:gomnd
+		v, err := strconv.ParseFloat(value, 32) //nolint:mnd
 		if err != nil {
 			return protoreflect.Value{}, err
 		}
 		msg = wrapperspb.Float(float32(v))
 	case "google.protobuf.Int64Value":
-		v, err := strconv.ParseInt(value, 10, 64) //nolint:gomnd
+		v, err := strconv.ParseInt(value, 10, 64) //nolint:mnd
 		if err != nil {
 			return protoreflect.Value{}, err
 		}
 		msg = wrapperspb.Int64(v)
 	case "google.protobuf.Int32Value":
-		v, err := strconv.ParseInt(value, 10, 32) //nolint:gomnd
+		v, err := strconv.ParseInt(value, 10, 32) //nolint:mnd
 		if err != nil {
 			return protoreflect.Value{}, err
 		}
 		msg = wrapperspb.Int32(int32(v))
 	case "google.protobuf.UInt64Value":
-		v, err := strconv.ParseUint(value, 10, 64) //nolint:gomnd
+		v, err := strconv.ParseUint(value, 10, 64) //nolint:mnd
 		if err != nil {
 			return protoreflect.Value{}, err
 		}
 		msg = wrapperspb.UInt64(v)
 	case "google.protobuf.UInt32Value":
-		v, err := strconv.ParseUint(value, 10, 32) //nolint:gomnd
+		v, err := strconv.ParseUint(value, 10, 32) //nolint:mnd
 		if err != nil {
 			return protoreflect.Value{}, err
 		}
@@ -358,9 +358,9 @@ func parseURLQueryMapKey(key string) (string, string, error) {
 		endIndex   = strings.IndexByte(key, ']')
 	)
 	if startIndex < 0 {
-		//nolint:gomnd
+		//nolint:mnd
 		values := strings.Split(key, fieldSeparater)
-		//nolint:gomnd
+		//nolint:mnd
 		if len(values) != 2 {
 			return "", "", errInvalidFormatMapKey
 		}
diff --git a/errors/errors.go b/errors/errors.go
index caf31cd3..ae0764f8 100644
--- a/errors/errors.go
+++ b/errors/errors.go
@@ -89,7 +89,7 @@ func Errorf(code int, reason, format string, a ...interface{}) error {
 // It supports wrapped errors.
 func Code(err error) int {
 	if err == nil {
-		return 200 //nolint:gomnd
+		return 200 //nolint:mnd
 	}
 	return int(FromError(err).Code)
 }
diff --git a/errors/types.go b/errors/types.go
index 6a57f32a..fbd2cb1f 100644
--- a/errors/types.go
+++ b/errors/types.go
@@ -1,4 +1,4 @@
-// nolint:gomnd
+// nolint:mnd
 package errors
 
 // BadRequest new BadRequest error that is mapped to a 400 response.
diff --git a/internal/host/host.go b/internal/host/host.go
index 774f7ae3..5a6caba0 100644
--- a/internal/host/host.go
+++ b/internal/host/host.go
@@ -13,7 +13,7 @@ func ExtractHostPort(addr string) (host string, port uint64, err error) {
 	if err != nil {
 		return
 	}
-	port, err = strconv.ParseUint(ports, 10, 16) //nolint:gomnd
+	port, err = strconv.ParseUint(ports, 10, 16) //nolint:mnd
 	return
 }
 
diff --git a/internal/httputil/http.go b/internal/httputil/http.go
index 81adf6ba..a2bdce26 100644
--- a/internal/httputil/http.go
+++ b/internal/httputil/http.go
@@ -10,7 +10,7 @@ const (
 
 // ContentType returns the content-type with base prefix.
 func ContentType(subtype string) string {
-	return strings.Join([]string{baseContentType, subtype}, "/")
+	return baseContentType + "/" + subtype
 }
 
 // ContentSubtype returns the content-subtype for the given content-type.  The
diff --git a/middleware/logging/logging.go b/middleware/logging/logging.go
index 8595750b..a4dff338 100644
--- a/middleware/logging/logging.go
+++ b/middleware/logging/logging.go
@@ -5,10 +5,13 @@ import (
 	"fmt"
 	"time"
 
+	"google.golang.org/grpc/codes"
+
 	"github.com/go-kratos/kratos/v2/errors"
 	"github.com/go-kratos/kratos/v2/log"
 	"github.com/go-kratos/kratos/v2/middleware"
 	"github.com/go-kratos/kratos/v2/transport"
+	"github.com/go-kratos/kratos/v2/transport/http/status"
 )
 
 // Redacter defines how to log an object
@@ -26,6 +29,10 @@ func Server(logger log.Logger) middleware.Middleware {
 				kind      string
 				operation string
 			)
+
+			// default code
+			code = int32(status.FromGRPCCode(codes.OK))
+
 			startTime := time.Now()
 			if info, ok := transport.FromServerContext(ctx); ok {
 				kind = info.Kind().String()
@@ -62,6 +69,10 @@ func Client(logger log.Logger) middleware.Middleware {
 				kind      string
 				operation string
 			)
+
+			// default code
+			code = int32(status.FromGRPCCode(codes.OK))
+
 			startTime := time.Now()
 			if info, ok := transport.FromClientContext(ctx); ok {
 				kind = info.Kind().String()
diff --git a/middleware/metrics/metrics.go b/middleware/metrics/metrics.go
index 4459cdee..7a76c57a 100644
--- a/middleware/metrics/metrics.go
+++ b/middleware/metrics/metrics.go
@@ -4,13 +4,15 @@ import (
 	"context"
 	"time"
 
-	"github.com/go-kratos/kratos/v2/errors"
-	"github.com/go-kratos/kratos/v2/middleware"
-	"github.com/go-kratos/kratos/v2/transport"
-
 	"go.opentelemetry.io/otel/attribute"
 	"go.opentelemetry.io/otel/metric"
 	metricsdk "go.opentelemetry.io/otel/sdk/metric"
+	"google.golang.org/grpc/codes"
+
+	"github.com/go-kratos/kratos/v2/errors"
+	"github.com/go-kratos/kratos/v2/middleware"
+	"github.com/go-kratos/kratos/v2/transport"
+	"github.com/go-kratos/kratos/v2/transport/http/status"
 )
 
 const (
@@ -56,7 +58,11 @@ func DefaultRequestsCounter(meter metric.Meter, histogramName string) (metric.In
 // return metric.Float64Histogram for WithSeconds
 // suggest histogramName = <client/server>_requests_seconds_bucket
 func DefaultSecondsHistogram(meter metric.Meter, histogramName string) (metric.Float64Histogram, error) {
-	return meter.Float64Histogram(histogramName, metric.WithUnit("s"))
+	return meter.Float64Histogram(
+		histogramName,
+		metric.WithUnit("s"),
+		metric.WithExplicitBucketBoundaries(0.005, 0.01, 0.025, 0.05, 0.1, 0.250, 0.5, 1),
+	)
 }
 
 // DefaultSecondsHistogramView
@@ -76,7 +82,7 @@ func DefaultSecondsHistogramView(histogramName string) metricsdk.View {
 					Boundaries: []float64{0.005, 0.01, 0.025, 0.05, 0.1, 0.250, 0.5, 1},
 					NoMinMax:   true,
 				},
-				AttributeFilter: func(value attribute.KeyValue) bool {
+				AttributeFilter: func(attribute.KeyValue) bool {
 					return true
 				},
 			}, true
@@ -111,6 +117,10 @@ func Server(opts ...Option) middleware.Middleware {
 				kind      string
 				operation string
 			)
+
+			// default code
+			code = status.FromGRPCCode(codes.OK)
+
 			startTime := time.Now()
 			if info, ok := transport.FromServerContext(ctx); ok {
 				kind = info.Kind().String()
@@ -160,6 +170,10 @@ func Client(opts ...Option) middleware.Middleware {
 				kind      string
 				operation string
 			)
+
+			// default code
+			code = status.FromGRPCCode(codes.OK)
+
 			startTime := time.Now()
 			if info, ok := transport.FromClientContext(ctx); ok {
 				kind = info.Kind().String()
diff --git a/middleware/recovery/recovery.go b/middleware/recovery/recovery.go
index 53e67f81..4c02820e 100644
--- a/middleware/recovery/recovery.go
+++ b/middleware/recovery/recovery.go
@@ -36,7 +36,7 @@ func WithHandler(h HandlerFunc) Option {
 // Recovery is a server middleware that recovers from any panics.
 func Recovery(opts ...Option) middleware.Middleware {
 	op := options{
-		handler: func(ctx context.Context, req, err interface{}) error {
+		handler: func(context.Context, any, any) error {
 			return ErrUnknownRequest
 		},
 	}
@@ -48,7 +48,7 @@ func Recovery(opts ...Option) middleware.Middleware {
 			startTime := time.Now()
 			defer func() {
 				if rerr := recover(); rerr != nil {
-					buf := make([]byte, 64<<10) //nolint:gomnd
+					buf := make([]byte, 64<<10) //nolint:mnd
 					n := runtime.Stack(buf, false)
 					buf = buf[:n]
 					log.Context(ctx).Errorf("%v: %+v\n%s\n", rerr, req, buf)
diff --git a/middleware/tracing/span.go b/middleware/tracing/span.go
index a0a9d462..1fa241ec 100644
--- a/middleware/tracing/span.go
+++ b/middleware/tracing/span.go
@@ -104,7 +104,7 @@ func setServerSpan(ctx context.Context, span trace.Span, m interface{}) {
 func parseFullMethod(fullMethod string) (string, []attribute.KeyValue) {
 	name := strings.TrimLeft(fullMethod, "/")
 	parts := strings.SplitN(name, "/", 2)
-	if len(parts) != 2 { //nolint:gomnd
+	if len(parts) != 2 { //nolint:mnd
 		// Invalid format, does not follow `/package.service/method`.
 		return name, []attribute.KeyValue{attribute.Key("rpc.operation").String(fullMethod)}
 	}
diff --git a/selector/node/direct/direct.go b/selector/node/direct/direct.go
index d32fc314..eeb6e219 100644
--- a/selector/node/direct/direct.go
+++ b/selector/node/direct/direct.go
@@ -36,7 +36,7 @@ func (*Builder) Build(n selector.Node) selector.WeightedNode {
 func (n *Node) Pick() selector.DoneFunc {
 	now := time.Now().UnixNano()
 	atomic.StoreInt64(&n.lastPick, now)
-	return func(ctx context.Context, di selector.DoneInfo) {}
+	return func(context.Context, selector.DoneInfo) {}
 }
 
 // Weight is node effective weight
diff --git a/selector/node/ewma/node.go b/selector/node/ewma/node.go
index 540a0bb3..b4daeaa6 100644
--- a/selector/node/ewma/node.go
+++ b/selector/node/ewma/node.go
@@ -121,7 +121,7 @@ func (n *Node) Pick() selector.DoneFunc {
 	reqs := atomic.AddInt64(&n.reqs, 1)
 	slot := reqs % 200
 	swapped := atomic.CompareAndSwapInt64(&n.inflights[slot], 0, start)
-	return func(ctx context.Context, di selector.DoneInfo) {
+	return func(_ context.Context, di selector.DoneInfo) {
 		if swapped {
 			atomic.CompareAndSwapInt64(&n.inflights[slot], start, 0)
 		}
diff --git a/transport/grpc/client.go b/transport/grpc/client.go
index edc57d3e..42ad5d72 100644
--- a/transport/grpc/client.go
+++ b/transport/grpc/client.go
@@ -11,6 +11,7 @@ import (
 	grpcinsecure "google.golang.org/grpc/credentials/insecure"
 	grpcmd "google.golang.org/grpc/metadata"
 
+	"github.com/go-kratos/kratos/v2/internal/matcher"
 	"github.com/go-kratos/kratos/v2/log"
 	"github.com/go-kratos/kratos/v2/middleware"
 	"github.com/go-kratos/kratos/v2/registry"
@@ -114,8 +115,8 @@ func WithHealthCheck(healthCheck bool) ClientOption {
 
 // WithLogger with logger
 // Deprecated: use global logger instead.
-func WithLogger(_ log.Logger) ClientOption {
-	return func(o *clientOptions) {}
+func WithLogger(log.Logger) ClientOption {
+	return func(*clientOptions) {}
 }
 
 func WithPrintDiscoveryDebugLog(p bool) ClientOption {
@@ -132,6 +133,7 @@ type clientOptions struct {
 	timeout                time.Duration
 	discovery              registry.Discovery
 	middleware             []middleware.Middleware
+	streamMiddleware       []middleware.Middleware
 	ints                   []grpc.UnaryClientInterceptor
 	streamInts             []grpc.StreamClientInterceptor
 	grpcOpts               []grpc.DialOption
@@ -166,7 +168,7 @@ func dial(ctx context.Context, insecure bool, opts ...ClientOption) (*grpc.Clien
 		unaryClientInterceptor(options.middleware, options.timeout, options.filters),
 	}
 	sints := []grpc.StreamClientInterceptor{
-		streamClientInterceptor(options.filters),
+		streamClientInterceptor(options.streamMiddleware, options.filters),
 	}
 
 	if len(options.ints) > 0 {
@@ -188,6 +190,7 @@ func dial(ctx context.Context, insecure bool, opts ...ClientOption) (*grpc.Clien
 				discovery.NewBuilder(
 					options.discovery,
 					discovery.WithInsecure(insecure),
+					discovery.WithTimeout(options.timeout),
 					discovery.WithSubset(options.subsetSize),
 					discovery.PrintDebugLog(options.printDiscoveryDebugLog),
 				)))
@@ -239,7 +242,54 @@ func unaryClientInterceptor(ms []middleware.Middleware, timeout time.Duration, f
 	}
 }
 
-func streamClientInterceptor(filters []selector.NodeFilter) grpc.StreamClientInterceptor {
+// wrappedClientStream wraps the grpc.ClientStream and applies middleware
+type wrappedClientStream struct {
+	grpc.ClientStream
+	ctx        context.Context
+	middleware matcher.Matcher
+}
+
+func (w *wrappedClientStream) Context() context.Context {
+	return w.ctx
+}
+
+func (w *wrappedClientStream) SendMsg(m interface{}) error {
+	h := func(_ context.Context, req interface{}) (interface{}, error) {
+		return req, w.ClientStream.SendMsg(m)
+	}
+
+	info, ok := transport.FromClientContext(w.ctx)
+	if !ok {
+		return fmt.Errorf("transport value stored in ctx returns: %v", ok)
+	}
+
+	if next := w.middleware.Match(info.Operation()); len(next) > 0 {
+		h = middleware.Chain(next...)(h)
+	}
+
+	_, err := h(w.ctx, m)
+	return err
+}
+
+func (w *wrappedClientStream) RecvMsg(m interface{}) error {
+	h := func(_ context.Context, req interface{}) (interface{}, error) {
+		return req, w.ClientStream.RecvMsg(m)
+	}
+
+	info, ok := transport.FromClientContext(w.ctx)
+	if !ok {
+		return fmt.Errorf("transport value stored in ctx returns: %v", ok)
+	}
+
+	if next := w.middleware.Match(info.Operation()); len(next) > 0 {
+		h = middleware.Chain(next...)(h)
+	}
+
+	_, err := h(w.ctx, m)
+	return err
+}
+
+func streamClientInterceptor(ms []middleware.Middleware, filters []selector.NodeFilter) grpc.StreamClientInterceptor {
 	return func(ctx context.Context, desc *grpc.StreamDesc, cc *grpc.ClientConn, method string, streamer grpc.Streamer, opts ...grpc.CallOption) (grpc.ClientStream, error) { // nolint
 		ctx = transport.NewClientContext(ctx, &Transport{
 			endpoint:    cc.Target(),
@@ -249,6 +299,28 @@ func streamClientInterceptor(filters []selector.NodeFilter) grpc.StreamClientInt
 		})
 		var p selector.Peer
 		ctx = selector.NewPeerContext(ctx, &p)
-		return streamer(ctx, desc, cc, method, opts...)
+
+		clientStream, err := streamer(ctx, desc, cc, method, opts...)
+		if err != nil {
+			return nil, err
+		}
+
+		h := func(_ context.Context, _ interface{}) (interface{}, error) {
+			return streamer, nil
+		}
+
+		m := matcher.New()
+		if len(ms) > 0 {
+			m.Use(ms...)
+			middleware.Chain(ms...)(h)
+		}
+
+		wrappedStream := &wrappedClientStream{
+			ClientStream: clientStream,
+			ctx:          ctx,
+			middleware:   m,
+		}
+
+		return wrappedStream, nil
 	}
 }
diff --git a/transport/grpc/interceptor.go b/transport/grpc/interceptor.go
index 6cc33154..f84b4bcf 100644
--- a/transport/grpc/interceptor.go
+++ b/transport/grpc/interceptor.go
@@ -2,11 +2,13 @@ package grpc
 
 import (
 	"context"
+	"fmt"
 
 	"google.golang.org/grpc"
 	grpcmd "google.golang.org/grpc/metadata"
 
 	ic "github.com/go-kratos/kratos/v2/internal/context"
+	"github.com/go-kratos/kratos/v2/internal/matcher"
 	"github.com/go-kratos/kratos/v2/middleware"
 	"github.com/go-kratos/kratos/v2/transport"
 )
@@ -48,13 +50,15 @@ func (s *Server) unaryServerInterceptor() grpc.UnaryServerInterceptor {
 // wrappedStream is rewrite grpc stream's context
 type wrappedStream struct {
 	grpc.ServerStream
-	ctx context.Context
+	ctx        context.Context
+	middleware matcher.Matcher
 }
 
-func NewWrappedStream(ctx context.Context, stream grpc.ServerStream) grpc.ServerStream {
+func NewWrappedStream(ctx context.Context, stream grpc.ServerStream, m matcher.Matcher) grpc.ServerStream {
 	return &wrappedStream{
 		ServerStream: stream,
 		ctx:          ctx,
+		middleware:   m,
 	}
 }
 
@@ -76,7 +80,19 @@ func (s *Server) streamServerInterceptor() grpc.StreamServerInterceptor {
 			replyHeader: headerCarrier(replyHeader),
 		})
 
-		ws := NewWrappedStream(ctx, ss)
+		h := func(_ context.Context, _ interface{}) (interface{}, error) {
+			return handler(srv, ss), nil
+		}
+
+		if next := s.streamMiddleware.Match(info.FullMethod); len(next) > 0 {
+			middleware.Chain(next...)(h)
+		}
+
+		ctx = context.WithValue(ctx, stream{
+			ServerStream:     ss,
+			streamMiddleware: s.streamMiddleware,
+		}, ss)
+		ws := NewWrappedStream(ctx, ss, s.streamMiddleware)
 
 		err := handler(srv, ws)
 		if len(replyHeader) > 0 {
@@ -85,3 +101,48 @@ func (s *Server) streamServerInterceptor() grpc.StreamServerInterceptor {
 		return err
 	}
 }
+
+type stream struct {
+	grpc.ServerStream
+	streamMiddleware matcher.Matcher
+}
+
+func GetStream(ctx context.Context) grpc.ServerStream {
+	return ctx.Value(stream{}).(grpc.ServerStream)
+}
+
+func (w *wrappedStream) SendMsg(m interface{}) error {
+	h := func(_ context.Context, req interface{}) (interface{}, error) {
+		return req, w.ServerStream.SendMsg(m)
+	}
+
+	info, ok := transport.FromServerContext(w.ctx)
+	if !ok {
+		return fmt.Errorf("transport value stored in ctx returns: %v", ok)
+	}
+
+	if next := w.middleware.Match(info.Operation()); len(next) > 0 {
+		h = middleware.Chain(next...)(h)
+	}
+
+	_, err := h(w.ctx, m)
+	return err
+}
+
+func (w *wrappedStream) RecvMsg(m interface{}) error {
+	h := func(_ context.Context, req interface{}) (interface{}, error) {
+		return req, w.ServerStream.RecvMsg(m)
+	}
+
+	info, ok := transport.FromServerContext(w.ctx)
+	if !ok {
+		return fmt.Errorf("transport value stored in ctx returns: %v", ok)
+	}
+
+	if next := w.middleware.Match(info.Operation()); len(next) > 0 {
+		h = middleware.Chain(next...)(h)
+	}
+
+	_, err := h(w.ctx, m)
+	return err
+}
diff --git a/transport/grpc/resolver/discovery/builder.go b/transport/grpc/resolver/discovery/builder.go
index 3d147cd8..5a084416 100644
--- a/transport/grpc/resolver/discovery/builder.go
+++ b/transport/grpc/resolver/discovery/builder.go
@@ -14,6 +14,8 @@ import (
 
 const name = "discovery"
 
+var ErrWatcherCreateTimeout = errors.New("discovery create watcher overtime")
+
 // Option is builder option.
 type Option func(o *builder)
 
@@ -96,7 +98,7 @@ func (b *builder) Build(target resolver.Target, cc resolver.ClientConn, _ resolv
 	case <-done:
 		err = watchRes.err
 	case <-time.After(b.timeout):
-		err = errors.New("discovery create watcher overtime")
+		err = ErrWatcherCreateTimeout
 	}
 	if err != nil {
 		cancel()
diff --git a/transport/grpc/server.go b/transport/grpc/server.go
index c8c3f4f3..2b260bf1 100644
--- a/transport/grpc/server.go
+++ b/transport/grpc/server.go
@@ -61,8 +61,8 @@ func Timeout(timeout time.Duration) ServerOption {
 
 // Logger with server logger.
 // Deprecated: use global logger instead.
-func Logger(_ log.Logger) ServerOption {
-	return func(s *Server) {}
+func Logger(log.Logger) ServerOption {
+	return func(*Server) {}
 }
 
 // Middleware with server middleware.
@@ -72,6 +72,12 @@ func Middleware(m ...middleware.Middleware) ServerOption {
 	}
 }
 
+func StreamMiddleware(m ...middleware.Middleware) ServerOption {
+	return func(s *Server) {
+		s.streamMiddleware.Use(m...)
+	}
+}
+
 // CustomHealth Checks server.
 func CustomHealth() ServerOption {
 	return func(s *Server) {
@@ -117,33 +123,35 @@ func Options(opts ...grpc.ServerOption) ServerOption {
 // Server is a gRPC server wrapper.
 type Server struct {
 	*grpc.Server
-	baseCtx      context.Context
-	tlsConf      *tls.Config
-	lis          net.Listener
-	err          error
-	network      string
-	address      string
-	endpoint     *url.URL
-	timeout      time.Duration
-	middleware   matcher.Matcher
-	unaryInts    []grpc.UnaryServerInterceptor
-	streamInts   []grpc.StreamServerInterceptor
-	grpcOpts     []grpc.ServerOption
-	health       *health.Server
-	customHealth bool
-	metadata     *apimd.Server
-	adminClean   func()
+	baseCtx          context.Context
+	tlsConf          *tls.Config
+	lis              net.Listener
+	err              error
+	network          string
+	address          string
+	endpoint         *url.URL
+	timeout          time.Duration
+	middleware       matcher.Matcher
+	streamMiddleware matcher.Matcher
+	unaryInts        []grpc.UnaryServerInterceptor
+	streamInts       []grpc.StreamServerInterceptor
+	grpcOpts         []grpc.ServerOption
+	health           *health.Server
+	customHealth     bool
+	metadata         *apimd.Server
+	adminClean       func()
 }
 
 // NewServer creates a gRPC server by options.
 func NewServer(opts ...ServerOption) *Server {
 	srv := &Server{
-		baseCtx:    context.Background(),
-		network:    "tcp",
-		address:    ":0",
-		timeout:    1 * time.Second,
-		health:     health.NewServer(),
-		middleware: matcher.New(),
+		baseCtx:          context.Background(),
+		network:          "tcp",
+		address:          ":0",
+		timeout:          1 * time.Second,
+		health:           health.NewServer(),
+		middleware:       matcher.New(),
+		streamMiddleware: matcher.New(),
 	}
 	for _, o := range opts {
 		o(srv)
diff --git a/transport/http/binding/encode.go b/transport/http/binding/encode.go
index 5f12cf37..2c1eda9c 100644
--- a/transport/http/binding/encode.go
+++ b/transport/http/binding/encode.go
@@ -20,7 +20,7 @@ func EncodeURL(pathTemplate string, msg interface{}, needQuery bool) string {
 	pathParams := make(map[string]struct{})
 	path := reg.ReplaceAllStringFunc(pathTemplate, func(in string) string {
 		// it's unreachable because the reg means that must have more than one char in {}
-		// if len(in) < 4 { //nolint:gomnd // **  explain the 4 number here :-) **
+		// if len(in) < 4 { //nolint:mnd // **  explain the 4 number here :-) **
 		//	return in
 		// }
 		key := in[1 : len(in)-1]
diff --git a/transport/http/client.go b/transport/http/client.go
index 1d74542d..d7efbcc8 100644
--- a/transport/http/client.go
+++ b/transport/http/client.go
@@ -252,7 +252,7 @@ func (client *Client) Invoke(ctx context.Context, method, path string, args inte
 }
 
 func (client *Client) invoke(ctx context.Context, req *http.Request, args interface{}, reply interface{}, c callInfo, opts ...CallOption) error {
-	h := func(ctx context.Context, in interface{}) (interface{}, error) {
+	h := func(ctx context.Context, _ interface{}) (interface{}, error) {
 		res, err := client.do(req.WithContext(ctx))
 		if res != nil {
 			cs := csAttempt{res: res}
diff --git a/transport/http/server.go b/transport/http/server.go
index 917b41e1..457fe724 100644
--- a/transport/http/server.go
+++ b/transport/http/server.go
@@ -58,8 +58,8 @@ func Timeout(timeout time.Duration) ServerOption {
 
 // Logger with server logger.
 // Deprecated: use global logger instead.
-func Logger(_ log.Logger) ServerOption {
-	return func(s *Server) {}
+func Logger(log.Logger) ServerOption {
+	return func(*Server) {}
 }
 
 // Middleware with service middleware option.
@@ -214,7 +214,7 @@ func (s *Server) Use(selector string, m ...middleware.Middleware) {
 
 // WalkRoute walks the router and all its sub-routers, calling walkFn for each route in the tree.
 func (s *Server) WalkRoute(fn WalkRouteFunc) error {
-	return s.router.Walk(func(route *mux.Route, router *mux.Router, ancestors []*mux.Route) error {
+	return s.router.Walk(func(route *mux.Route, _ *mux.Router, _ []*mux.Route) error {
 		methods, err := route.GetMethods()
 		if err != nil {
 			return nil // ignore no methods
diff --git a/version.go b/version.go
index 9db0048b..c6f87a57 100644
--- a/version.go
+++ b/version.go
@@ -1,4 +1,4 @@
 package kratos
 
 // Release is the current kratos version.
-const Release = "v2.8.0"
+const Release = "v2.8.1"


Test patch:
diff --git a/config/config_test.go b/config/config_test.go
index ab234dd4..ec7fc9f7 100644
--- a/config/config_test.go
+++ b/config/config_test.go
@@ -154,8 +154,7 @@ func TestConfig(t *testing.T) {
 		t.Fatal("databaseDriver is not equal to val")
 	}
 
-	err = cf.Watch("endpoints", func(key string, value Value) {
-	})
+	err = cf.Watch("endpoints", func(string, Value) {})
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/config/options_test.go b/config/options_test.go
index 83f62b85..348471d3 100644
--- a/config/options_test.go
+++ b/config/options_test.go
@@ -387,7 +387,7 @@ func TestExpand(t *testing.T) {
 
 func TestWithMergeFunc(t *testing.T) {
 	c := &options{}
-	a := func(dst, src interface{}) error {
+	a := func(any, any) error {
 		return nil
 	}
 	WithMergeFunc(a)(c)
diff --git a/contrib/config/nacos/config_test.go b/contrib/config/nacos/config_test.go
index 2d290803..1667e99d 100644
--- a/contrib/config/nacos/config_test.go
+++ b/contrib/config/nacos/config_test.go
@@ -166,13 +166,13 @@ func TestConfig_Watch(t *testing.T) {
 				source: source,
 			},
 			wantErr: false,
-			processFunc: func(t *testing.T, w config.Watcher) {
+			processFunc: func(t *testing.T, _ config.Watcher) {
 				_, pErr := client.PublishConfig(vo.ConfigParam{DataId: "test.yaml", Group: "test", Content: "test: test"})
 				if pErr != nil {
 					t.Error(pErr)
 				}
 			},
-			deferFunc: func(t *testing.T, w config.Watcher) {
+			deferFunc: func(t *testing.T, _ config.Watcher) {
 				_, dErr := client.DeleteConfig(vo.ConfigParam{DataId: "test.yaml", Group: "test"})
 				if dErr != nil {
 					t.Error(dErr)
diff --git a/contrib/opensergo/opensergo_test.go b/contrib/opensergo/opensergo_test.go
index 0a2165fb..322c2c7e 100644
--- a/contrib/opensergo/opensergo_test.go
+++ b/contrib/opensergo/opensergo_test.go
@@ -309,7 +309,7 @@ func TestOpenSergo(t *testing.T) {
 			args: args{
 				opts: []Option{},
 			},
-			preFunc: func(t *testing.T) {
+			preFunc: func(_ *testing.T) {
 				err := os.Setenv("OPENSERGO_ENDPOINT", "127.0.0.1:9090")
 				if err != nil {
 					panic(err)
@@ -322,7 +322,7 @@ func TestOpenSergo(t *testing.T) {
 			args: args{
 				opts: []Option{},
 			},
-			preFunc: func(t *testing.T) {
+			preFunc: func(_ *testing.T) {
 				err := os.Setenv("OPENSERGO_BOOTSTRAP", `{"endpoint": "127.0.0.1:9090"}`)
 				if err != nil {
 					panic(err)
diff --git a/contrib/polaris/registry_test.go b/contrib/polaris/registry_test.go
index a03f807e..2a4426ed 100644
--- a/contrib/polaris/registry_test.go
+++ b/contrib/polaris/registry_test.go
@@ -2,6 +2,7 @@ package polaris
 
 import (
 	"context"
+	"strconv"
 	"testing"
 	"time"
 
@@ -28,6 +29,9 @@ func TestRegistry(t *testing.T) {
 		WithRegistryTTL(1000),
 	)
 
+	mm := map[string]string{
+		"test1": "test1",
+	}
 	ins := &registry.ServiceInstance{
 		ID:      "test-ut",
 		Name:    "test-ut",
@@ -36,8 +40,19 @@ func TestRegistry(t *testing.T) {
 			"grpc://127.0.0.1:8080",
 			"http://127.0.0.1:9090",
 		},
+		Metadata: mm,
 	}
 
+	go func() {
+		for i := 0; true; i++ {
+			str := "test" + strconv.Itoa(i)
+			_ = mm[str]
+			if i > 100 {
+				i = 0
+			}
+		}
+	}()
+
 	err = r.Register(context.Background(), ins)
 
 	t.Cleanup(func() {
diff --git a/contrib/registry/consul/registry_test.go b/contrib/registry/consul/registry_test.go
index d6799b69..743e1dfb 100644
--- a/contrib/registry/consul/registry_test.go
+++ b/contrib/registry/consul/registry_test.go
@@ -117,8 +117,8 @@ func TestRegistry_Register(t *testing.T) {
 					t.Error(err)
 				}
 			}
-
-			watch, err := r.Watch(tt.args.ctx, tt.args.serverName)
+			watchCtx, watchCancel := context.WithCancel(context.Background())
+			watch, err := r.Watch(watchCtx, tt.args.serverName)
 			if err != nil {
 				t.Error(err)
 			}
@@ -127,6 +127,7 @@ func TestRegistry_Register(t *testing.T) {
 			if (err != nil) != tt.wantErr {
 				t.Errorf("GetService() error = %v, wantErr %v", err, tt.wantErr)
 				t.Errorf("GetService() got = %v", got)
+				watchCancel()
 				return
 			}
 			if !reflect.DeepEqual(got, tt.want) {
@@ -136,6 +137,11 @@ func TestRegistry_Register(t *testing.T) {
 			for _, instance := range tt.args.server {
 				_ = r.Deregister(tt.args.ctx, instance)
 			}
+			err = watch.Stop()
+			if err != nil {
+				t.Error(err)
+			}
+			watchCancel()
 		})
 	}
 }
@@ -204,7 +210,8 @@ func TestRegistry_GetService(t *testing.T) {
 				if err := r.Register(context.Background(), instance1); err != nil {
 					t.Error(err)
 				}
-				watch, err := r.Watch(context.Background(), instance1.Name)
+				watchCtx, watchCancel := context.WithCancel(context.Background())
+				watch, err := r.Watch(watchCtx, instance1.Name)
 				if err != nil {
 					t.Error(err)
 				}
@@ -212,6 +219,11 @@ func TestRegistry_GetService(t *testing.T) {
 				if err != nil {
 					t.Error(err)
 				}
+				err = watch.Stop()
+				if err != nil {
+					t.Error(err)
+				}
+				watchCancel()
 			},
 			deferFunc: func(t *testing.T) {
 				err := r.Deregister(context.Background(), instance1)
@@ -233,7 +245,8 @@ func TestRegistry_GetService(t *testing.T) {
 				if err := r.Register(context.Background(), instance2); err != nil {
 					t.Error(err)
 				}
-				watch, err := r.Watch(context.Background(), instance2.Name)
+				watchCtx, watchCancel := context.WithCancel(context.Background())
+				watch, err := r.Watch(watchCtx, instance2.Name)
 				if err != nil {
 					t.Error(err)
 				}
@@ -241,6 +254,11 @@ func TestRegistry_GetService(t *testing.T) {
 				if err != nil {
 					t.Error(err)
 				}
+				err = watch.Stop()
+				if err != nil {
+					t.Error(err)
+				}
+				watchCancel()
 			},
 			deferFunc: func(t *testing.T) {
 				err := r.Deregister(context.Background(), instance2)
@@ -329,8 +347,7 @@ func TestRegistry_Watch(t *testing.T) {
 			},
 			want:    []*registry.ServiceInstance{instance1},
 			wantErr: false,
-			preFunc: func(t *testing.T) {
-			},
+			preFunc: func(*testing.T) {},
 		},
 		{
 			name: "ctx has been canceled",
@@ -344,8 +361,7 @@ func TestRegistry_Watch(t *testing.T) {
 			},
 			want:    nil,
 			wantErr: true,
-			preFunc: func(t *testing.T) {
-			},
+			preFunc: func(*testing.T) {},
 		},
 		{
 			name: "register with healthCheck",
@@ -389,7 +405,6 @@ func TestRegistry_Watch(t *testing.T) {
 					t.Error(err)
 				}
 			}()
-
 			watch, err := r.Watch(tt.args.ctx, tt.args.instance.Name)
 			if err != nil {
 				t.Error(err)
@@ -409,6 +424,10 @@ func TestRegistry_Watch(t *testing.T) {
 			if !reflect.DeepEqual(service, tt.want) {
 				t.Errorf("GetService() got = %v, want %v", service, tt.want)
 			}
+			err = watch.Stop()
+			if err != nil {
+				t.Error(err)
+			}
 		})
 	}
 }
@@ -432,10 +451,17 @@ func TestRegistry_IdleAndWatch(t *testing.T) {
 		Version:   "v0.0.1",
 		Endpoints: []string{fmt.Sprintf("tcp://%s?isSecure=false", addr)},
 	}
+	instance2 := &registry.ServiceInstance{
+		ID:        "1",
+		Name:      "server-1",
+		Version:   "v0.0.2",
+		Endpoints: []string{fmt.Sprintf("tcp://%s?isSecure=false", addr)},
+	}
 
 	type args struct {
-		ctx      context.Context
-		instance *registry.ServiceInstance
+		ctx            context.Context
+		instance       *registry.ServiceInstance
+		changeInstance *registry.ServiceInstance
 	}
 
 	tests := []struct {
@@ -447,8 +473,9 @@ func TestRegistry_IdleAndWatch(t *testing.T) {
 		{
 			name: "many client, one idle",
 			args: args{
-				ctx:      context.Background(),
-				instance: instance1,
+				ctx:            context.Background(),
+				instance:       instance1,
+				changeInstance: instance2,
 			},
 			want:    []*registry.ServiceInstance{instance1},
 			wantErr: false,
@@ -469,46 +496,54 @@ func TestRegistry_IdleAndWatch(t *testing.T) {
 			}()
 
 			for i := 0; i < 10; i++ {
-				watch, err1 := r.Watch(context.Background(), tt.args.instance.Name)
+				watchCtx, watchCancel := context.WithCancel(context.Background())
+				watch, err1 := r.Watch(watchCtx, tt.args.instance.Name)
 				if err1 != nil {
 					t.Error(err1)
 				}
-				go func(i int) {
-					// first
-					service, err2 := watch.Next()
-					if (err2 != nil) != tt.wantErr {
-						t.Errorf("GetService() error = %v, wantErr %v", err, tt.wantErr)
-						t.Errorf("GetService() got = %v", service)
-						return
-					}
-					// instance changes
-					service, err2 = watch.Next()
-					if i == 9 {
-						return
-					}
-					if (err2 != nil) != tt.wantErr {
-						t.Errorf("GetService() error = %v, wantErr %v", err, tt.wantErr)
-						t.Errorf("GetService() got = %v", service)
-						return
-					}
-					if !reflect.DeepEqual(service, tt.want) {
-						t.Errorf("GetService() got = %v, want %v", service, tt.want)
-					}
-					// t.Logf("service:%v, i:%d", service, i)
-				}(i)
-				if i == 9 {
+				if i != 9 {
+					go func(i int) {
+						// first
+						service, err2 := watch.Next()
+						if (err2 != nil) != tt.wantErr {
+							t.Errorf("GetService() error = %v, wantErr %v", err, tt.wantErr)
+							t.Errorf("GetService() got = %v", service)
+							watchCancel()
+							return
+						}
+						// instance changes
+						service, err2 = watch.Next()
+						if i == 9 {
+							return
+						}
+						if (err2 != nil) != tt.wantErr {
+							t.Errorf("GetService() error = %v, wantErr %v", err, tt.wantErr)
+							t.Errorf("GetService() got = %v", service)
+							watchCancel()
+							return
+						}
+						if !reflect.DeepEqual(service, tt.want) {
+							t.Errorf("GetService() got = %v, want %v", service, tt.want)
+						}
+						err2 = watch.Stop()
+						if err2 != nil {
+							t.Error(err)
+						}
+						watchCancel()
+						// t.Logf("service:%v, i:%d", service, i)
+					}(i)
+				} else {
 					time.Sleep(time.Second * 3)
 					// become idle, close watcher
 					err1 = watch.Stop()
 					if err1 != nil {
 						t.Errorf("watch stop err:%v", err)
 					}
+					watchCancel()
 				}
 			}
 			time.Sleep(2 * time.Second)
-			change := tt.args.instance
-			change.Version = "v0.0.2"
-			err = r.Register(tt.args.ctx, change)
+			err = r.Register(tt.args.ctx, tt.args.changeInstance)
 			if err != nil {
 				t.Error(err)
 			}
@@ -576,11 +611,11 @@ func TestRegistry_IdleAndWatch2(t *testing.T) {
 			ctx, cancel := context.WithCancel(context.Background())
 			for i := 0; i < 10; i++ {
 				stopCtx, stopCancel := context.WithCancel(ctx)
-				watch, err1 := r.Watch(context.Background(), tt.args.instance.Name)
+				watch, err1 := r.Watch(stopCtx, tt.args.instance.Name)
 				if err1 != nil {
 					t.Error(err1)
 				}
-				go func(i int) {
+				go func(_ int) {
 					// first
 					service, err2 := watch.Next()
 					if (err2 != nil) != tt.wantErr {
@@ -588,10 +623,6 @@ func TestRegistry_IdleAndWatch2(t *testing.T) {
 						t.Errorf("GetService() got = %v", service)
 						return
 					}
-					_, err2 = watch.Next()
-					if err2 == nil {
-						t.Errorf("watch exit exception:%d ", i)
-					}
 				}(i)
 				go func() {
 					select {
@@ -615,7 +646,7 @@ func TestRegistry_IdleAndWatch2(t *testing.T) {
 			cancel()
 			time.Sleep(time.Second * 2)
 			// Everything is idle. Add new watch.
-			watchCtx := context.Background()
+			watchCtx, watchCancel := context.WithCancel(context.Background())
 			watch, err := r.Watch(watchCtx, tt.args.instance.Name)
 			if err != nil {
 				t.Error(err)
@@ -624,11 +655,143 @@ func TestRegistry_IdleAndWatch2(t *testing.T) {
 			if (err != nil) != tt.wantErr {
 				t.Errorf("GetService() error = %v, wantErr %v", err, tt.wantErr)
 				t.Errorf("GetService() got = %v", service)
+				watchCancel()
 				return
 			}
 			if !reflect.DeepEqual(service, tt.want) {
 				t.Errorf("GetService() got = %v, want %v", service, tt.want)
 			}
+			watchCancel()
+		})
+	}
+}
+
+func TestRegistry_ExitOldResolverAndReWatch(t *testing.T) {
+	addr := fmt.Sprintf("%s:9091", getIntranetIP())
+
+	time.Sleep(time.Millisecond * 100)
+	cli, err := api.NewClient(&api.Config{Address: "127.0.0.1:8500", WaitTime: 2 * time.Second})
+	if err != nil {
+		t.Fatalf("create consul client failed: %v", err)
+	}
+
+	instance1 := &registry.ServiceInstance{
+		ID:        "1",
+		Name:      "server-1",
+		Version:   "v0.0.1",
+		Endpoints: []string{fmt.Sprintf("tcp://%s?isSecure=false", addr)},
+	}
+	instance2 := &registry.ServiceInstance{
+		ID:        "2",
+		Name:      "server-1",
+		Version:   "v0.0.2",
+		Endpoints: []string{fmt.Sprintf("tcp://%s?isSecure=false", addr)},
+	}
+	type args struct {
+		ctx             context.Context
+		opts            []Option
+		instance        *registry.ServiceInstance
+		initialInstance *registry.ServiceInstance
+	}
+
+	tests := []struct {
+		name    string
+		args    args
+		want    []*registry.ServiceInstance
+		wantErr bool
+	}{
+		{
+			name: "When it has entered idle mode, but the old resolver has not completely exited, the watch will be re-established due to new requests coming in.",
+			args: args{
+				ctx:             context.Background(),
+				initialInstance: instance1,
+				instance:        instance2,
+				opts: []Option{
+					WithHealthCheck(false),
+					WithTimeout(time.Second * 2),
+				},
+			},
+			want:    []*registry.ServiceInstance{instance2},
+			wantErr: false,
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			r := New(cli, tt.args.opts...)
+
+			err = r.Register(tt.args.ctx, tt.args.initialInstance)
+			if err != nil {
+				t.Error(err)
+			}
+			// first watch
+			ctx, cancel := context.WithCancel(context.Background())
+			watch, err := r.Watch(ctx, tt.args.instance.Name)
+			if err != nil {
+				t.Error(err)
+			}
+			service, err := watch.Next()
+			if (err != nil) != tt.wantErr {
+				t.Errorf("GetService() error = %v, wantErr %v", err, tt.wantErr)
+				t.Errorf("GetService() got = %v", service)
+			}
+
+			time.Sleep(time.Second * 3)
+			// The simulation entered idle mode first, but the old resolver was not closed yet, and new requests triggered a new Watch.
+			watchCtx := context.Background()
+			// old resolver cancel
+			err = watch.Stop()
+			if err != nil {
+				t.Errorf("watch stop err:%v", err)
+			}
+			cancel()
+			// If it sleeps for a period of time, the old resolve goroutine will exit before the new Watch is processed, and there will be no problems at this time.
+			// time.Sleep(time.Second * 8)
+			newWatch, err := r.Watch(watchCtx, tt.args.instance.Name)
+			if err != nil {
+				t.Error(err)
+			}
+			service, err = newWatch.Next()
+			if (err != nil) != tt.wantErr {
+				t.Errorf("GetService() error = %v, wantErr %v", err, tt.wantErr)
+				t.Errorf("GetService() got = %v", service)
+			}
+			// change register info
+			time.Sleep(time.Second * 1)
+			err = r.Deregister(tt.args.ctx, tt.args.initialInstance)
+			if err != nil {
+				t.Error(err)
+			}
+			time.Sleep(time.Second * 5)
+			err = r.Register(tt.args.ctx, tt.args.instance)
+			if err != nil {
+				t.Error(err)
+			}
+
+			time.Sleep(time.Second * 2)
+
+			newWatchCtx, newWatchCancel := context.WithCancel(context.Background())
+			c := make(chan struct{}, 1)
+
+			go func() {
+				service, err = newWatch.Next()
+				if (err != nil) != tt.wantErr {
+					t.Errorf("GetService() error = %v, wantErr %v", err, tt.wantErr)
+					t.Errorf("GetService() got = %v", service)
+					return
+				}
+				if !reflect.DeepEqual(service, tt.want) {
+					t.Errorf("GetService() got = %v, want %v", service, tt.want)
+				}
+				c <- struct{}{}
+			}()
+			time.AfterFunc(time.Second*10, newWatchCancel)
+			select {
+			case <-newWatchCtx.Done():
+				t.Errorf("Timeout getservice. May be no new resolve goroutine to obtain the latest service information")
+			case <-c:
+				return
+			}
 		})
 	}
 }
diff --git a/contrib/registry/kubernetes/registry_test.go b/contrib/registry/kubernetes/registry_test.go
index 2363b1c3..6f9761a4 100644
--- a/contrib/registry/kubernetes/registry_test.go
+++ b/contrib/registry/kubernetes/registry_test.go
@@ -110,7 +110,6 @@ func TestRegistry(t *testing.T) {
 		Endpoints: []string{"http://127.0.0.1:80"},
 	}
 	_, err = clientSet.AppsV1().Deployments(namespace).Create(context.Background(), &deployment, metav1.CreateOptions{})
-
 	if err != nil {
 		t.Fatal(err)
 	}
diff --git a/contrib/registry/nacos/registry_test.go b/contrib/registry/nacos/registry_test.go
index 1910a68d..95768eea 100644
--- a/contrib/registry/nacos/registry_test.go
+++ b/contrib/registry/nacos/registry_test.go
@@ -530,7 +530,7 @@ func TestRegistry_Watch(t *testing.T) {
 			},
 			wantErr: true,
 			want:    nil,
-			processFunc: func(t *testing.T) {
+			processFunc: func(*testing.T) {
 				cancel()
 			},
 		},
diff --git a/contrib/registry/zookeeper/register_test.go b/contrib/registry/zookeeper/register_test.go
index a6f4515e..8ac9feec 100644
--- a/contrib/registry/zookeeper/register_test.go
+++ b/contrib/registry/zookeeper/register_test.go
@@ -80,7 +80,7 @@ func TestRegistry_GetService(t *testing.T) {
 		},
 		{
 			name: "conn close",
-			preFunc: func(t *testing.T) {
+			preFunc: func(*testing.T) {
 				conn.Close()
 			},
 			fields: fields{
@@ -339,7 +339,7 @@ func TestRegistry_Watch(t *testing.T) {
 					t.Error(err)
 				}
 			},
-			processFunc: func(t *testing.T, w registry.Watcher) {
+			processFunc: func(t *testing.T, _ registry.Watcher) {
 				err = r.Register(context.Background(), svrHello)
 				if err != nil {
 					t.Error(err)
@@ -357,7 +357,7 @@ func TestRegistry_Watch(t *testing.T) {
 			},
 			wantErr: true,
 			want:    nil,
-			processFunc: func(t *testing.T, w registry.Watcher) {
+			processFunc: func(*testing.T, registry.Watcher) {
 				cancel()
 			},
 		},
@@ -372,7 +372,7 @@ func TestRegistry_Watch(t *testing.T) {
 			},
 			wantErr: true,
 			want:    nil,
-			processFunc: func(t *testing.T, w registry.Watcher) {
+			processFunc: func(*testing.T, registry.Watcher) {
 				closeConn.Close()
 			},
 		},
diff --git a/encoding/encoding_test.go b/encoding/encoding_test.go
index 9746788a..98640ff4 100644
--- a/encoding/encoding_test.go
+++ b/encoding/encoding_test.go
@@ -2,7 +2,6 @@ package encoding
 
 import (
 	"encoding/xml"
-	"fmt"
 	"runtime/debug"
 	"testing"
 )
@@ -40,7 +39,7 @@ func TestRegisterCodec(t *testing.T) {
 	f := func() { RegisterCodec(nil) }
 	funcDidPanic, panicValue, _ := didPanic(f)
 	if !funcDidPanic {
-		t.Fatalf(fmt.Sprintf("func should panic\n\tPanic value:\t%#v", panicValue))
+		t.Fatalf("func should panic\n\tPanic value:\t%#v", panicValue)
 	}
 	if panicValue != "cannot register a nil Codec" {
 		t.Fatalf("panic error got %s want cannot register a nil Codec", panicValue)
@@ -50,7 +49,7 @@ func TestRegisterCodec(t *testing.T) {
 	}
 	funcDidPanic, panicValue, _ = didPanic(f)
 	if !funcDidPanic {
-		t.Fatalf(fmt.Sprintf("func should panic\n\tPanic value:\t%#v", panicValue))
+		t.Fatalf("func should panic\n\tPanic value:\t%#v", panicValue)
 	}
 	if panicValue != "cannot register Codec with empty string result for Name()" {
 		t.Fatalf("panic error got %s want cannot register Codec with empty string result for Name()", panicValue)
diff --git a/internal/matcher/middleware_test.go b/internal/matcher/middleware_test.go
index 9c948aeb..20575768 100644
--- a/internal/matcher/middleware_test.go
+++ b/internal/matcher/middleware_test.go
@@ -8,8 +8,8 @@ import (
 )
 
 func logging(module string) middleware.Middleware {
-	return func(handler middleware.Handler) middleware.Handler {
-		return func(ctx context.Context, req interface{}) (reply interface{}, err error) {
+	return func(middleware.Handler) middleware.Handler {
+		return func(context.Context, interface{}) (reply interface{}, err error) {
 			return module, nil
 		}
 	}
diff --git a/log/filter_test.go b/log/filter_test.go
index 8463a472..f95f4976 100644
--- a/log/filter_test.go
+++ b/log/filter_test.go
@@ -146,7 +146,10 @@ func testFilterFuncWithLoggerPrefix(level Level, keyvals ...interface{}) bool {
 }
 
 func TestFilterWithContext(t *testing.T) {
-	ctxKey := struct{}{}
+	type CtxKey struct {
+		Key string
+	}
+	ctxKey := CtxKey{Key: "context"}
 	ctxValue := "filter test value"
 
 	v1 := func() Valuer {
diff --git a/log/value_test.go b/log/value_test.go
index fd9167a6..defbbf74 100644
--- a/log/value_test.go
+++ b/log/value_test.go
@@ -19,7 +19,7 @@ func TestValue(t *testing.T) {
 	if got != v1 {
 		t.Errorf("Value() = %v, want %v", got, v1)
 	}
-	var v2 Valuer = func(ctx context.Context) interface{} {
+	var v2 Valuer = func(context.Context) interface{} {
 		return 3
 	}
 	got = Value(context.Background(), v2)
diff --git a/metadata/metadata_test.go b/metadata/metadata_test.go
index 9aa1c620..33f1b1a2 100644
--- a/metadata/metadata_test.go
+++ b/metadata/metadata_test.go
@@ -349,7 +349,7 @@ func TestMetadata_Range(t *testing.T) {
 		t.Errorf("metadata = %v, want %v", tmp, Metadata{"https://go-kratos.dev/": {"https://go-kratos.dev/"}, "kratos": {"kratos"}})
 	}
 	tmp = Metadata{}
-	md.Range(func(k string, v []string) bool {
+	md.Range(func(string, []string) bool {
 		return false
 	})
 	if !reflect.DeepEqual(tmp, Metadata{}) {
diff --git a/middleware/auth/jwt/jwt_test.go b/middleware/auth/jwt/jwt_test.go
index 5f2a3ba5..84a558e2 100644
--- a/middleware/auth/jwt/jwt_test.go
+++ b/middleware/auth/jwt/jwt_test.go
@@ -129,7 +129,7 @@ func TestJWTServerParse(t *testing.T) {
 		},
 	}
 
-	next := func(ctx context.Context, req interface{}) (interface{}, error) {
+	next := func(ctx context.Context, _ interface{}) (interface{}, error) {
 		testToken, _ := FromContext(ctx)
 		var name string
 		if customerClaims, ok := testToken.(*CustomerClaims); ok {
@@ -154,7 +154,7 @@ func TestJWTServerParse(t *testing.T) {
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
 			server := Server(
-				func(token *jwt.Token) (interface{}, error) { return []byte(testKey), nil },
+				func(*jwt.Token) (interface{}, error) { return []byte(testKey), nil },
 				WithClaims(test.claims),
 			)(next)
 			wg := sync.WaitGroup{}
@@ -247,11 +247,11 @@ func TestServer(t *testing.T) {
 			}
 			var server middleware.Handler
 			if test.signingMethod != nil {
-				server = Server(func(token *jwt.Token) (interface{}, error) {
+				server = Server(func(*jwt.Token) (interface{}, error) {
 					return []byte(test.key), nil
 				}, WithSigningMethod(test.signingMethod))(next)
 			} else {
-				server = Server(func(token *jwt.Token) (interface{}, error) {
+				server = Server(func(*jwt.Token) (interface{}, error) {
 					return []byte(test.key), nil
 				})(next)
 			}
@@ -301,7 +301,7 @@ func TestClient(t *testing.T) {
 	}
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
-			next := func(ctx context.Context, req interface{}) (interface{}, error) {
+			next := func(context.Context, any) (interface{}, error) {
 				return "reply", nil
 			}
 			handler := Client(test.tokenProvider)(next)
@@ -330,12 +330,12 @@ func TestTokenExpire(t *testing.T) {
 	}
 	token = fmt.Sprintf(bearerFormat, token)
 	time.Sleep(time.Second)
-	next := func(ctx context.Context, req interface{}) (interface{}, error) {
+	next := func(_ context.Context, req interface{}) (interface{}, error) {
 		t.Log(req)
 		return "reply", nil
 	}
 	ctx := transport.NewServerContext(context.Background(), &Transport{reqHeader: newTokenHeader(authorizationKey, token)})
-	server := Server(func(token *jwt.Token) (interface{}, error) {
+	server := Server(func(*jwt.Token) (interface{}, error) {
 		return []byte(testKey), nil
 	}, WithSigningMethod(jwt.SigningMethodHS256))(next)
 	_, err2 := server(ctx, "test expire token")
@@ -410,7 +410,7 @@ func TestClientWithClaims(t *testing.T) {
 	}
 
 	t.Run(test.name, func(t *testing.T) {
-		next := func(ctx context.Context, req interface{}) (interface{}, error) {
+		next := func(context.Context, interface{}) (interface{}, error) {
 			return "reply", nil
 		}
 		handler := Client(test.tokenProvider, WithClaims(mapClaimsFunc))(next)
@@ -446,7 +446,7 @@ func TestClientWithHeader(t *testing.T) {
 	tProvider := func(*jwt.Token) (interface{}, error) {
 		return []byte(testKey), nil
 	}
-	next := func(ctx context.Context, req interface{}) (interface{}, error) {
+	next := func(context.Context, interface{}) (interface{}, error) {
 		return "reply", nil
 	}
 	handler := Client(tProvider, WithClaims(mapClaimsFunc), WithTokenHeader(tokenHeader))(next)
@@ -484,7 +484,7 @@ func TestClientMissKey(t *testing.T) {
 	}
 
 	t.Run(test.name, func(t *testing.T) {
-		next := func(ctx context.Context, req interface{}) (interface{}, error) {
+		next := func(context.Context, interface{}) (interface{}, error) {
 			return "reply", nil
 		}
 		handler := Client(test.tokenProvider, WithClaims(mapClaimsFunc))(next)
diff --git a/middleware/circuitbreaker/circuitbreaker_test.go b/middleware/circuitbreaker/circuitbreaker_test.go
index 3b27da1a..3daca9f2 100644
--- a/middleware/circuitbreaker/circuitbreaker_test.go
+++ b/middleware/circuitbreaker/circuitbreaker_test.go
@@ -58,10 +58,10 @@ func Test_WithGroup(t *testing.T) {
 }
 
 func TestServer(_ *testing.T) {
-	nextValid := func(ctx context.Context, req interface{}) (interface{}, error) {
+	nextValid := func(context.Context, interface{}) (interface{}, error) {
 		return "Hello valid", nil
 	}
-	nextInvalid := func(ctx context.Context, req interface{}) (interface{}, error) {
+	nextInvalid := func(context.Context, interface{}) (interface{}, error) {
 		return nil, kratoserrors.InternalServer("", "")
 	}
 
diff --git a/middleware/logging/logging_test.go b/middleware/logging/logging_test.go
index 1e949518..87e3959a 100644
--- a/middleware/logging/logging_test.go
+++ b/middleware/logging/logging_test.go
@@ -87,7 +87,7 @@ func TestHTTP(t *testing.T) {
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
 			bf.Reset()
-			next := func(ctx context.Context, req interface{}) (interface{}, error) {
+			next := func(context.Context, interface{}) (interface{}, error) {
 				return "reply", test.err
 			}
 			next = test.kind(logger)(next)
diff --git a/middleware/metrics/metrics_test.go b/middleware/metrics/metrics_test.go
index 3f30ac1a..348fdaee 100644
--- a/middleware/metrics/metrics_test.go
+++ b/middleware/metrics/metrics_test.go
@@ -77,7 +77,7 @@ func init() {
 				Name:        instrument.Name,
 				Description: instrument.Description,
 				Unit:        instrument.Unit,
-				AttributeFilter: func(value attribute.KeyValue) bool {
+				AttributeFilter: func(attribute.KeyValue) bool {
 					return true
 				},
 			}, true
@@ -139,10 +139,10 @@ func TestServer(t *testing.T) {
 	defer span.End()
 
 	e := errors.New("got an error")
-	nextError := func(ctx context.Context, req interface{}) (interface{}, error) {
+	nextError := func(context.Context, interface{}) (interface{}, error) {
 		return nil, e
 	}
-	nextValid := func(ctx context.Context, req interface{}) (interface{}, error) {
+	nextValid := func(context.Context, interface{}) (interface{}, error) {
 		time.Sleep(time.Millisecond * time.Duration(rand.Int31n(100)))
 		return "Hello valid", nil
 	}
@@ -201,10 +201,10 @@ func TestClient(t *testing.T) {
 	defer span.End()
 
 	e := errors.New("got an error")
-	nextError := func(ctx context.Context, req interface{}) (interface{}, error) {
+	nextError := func(context.Context, interface{}) (interface{}, error) {
 		return nil, e
 	}
-	nextValid := func(ctx context.Context, req interface{}) (interface{}, error) {
+	nextValid := func(context.Context, interface{}) (interface{}, error) {
 		return "Hello valid", nil
 	}
 
diff --git a/middleware/middleware_test.go b/middleware/middleware_test.go
index 11986b0a..4714ff97 100644
--- a/middleware/middleware_test.go
+++ b/middleware/middleware_test.go
@@ -10,8 +10,10 @@ import (
 var i int
 
 func TestChain(t *testing.T) {
-	next := func(ctx context.Context, req interface{}) (interface{}, error) {
-		t.Log(req)
+	next := func(_ context.Context, req interface{}) (interface{}, error) {
+		if req != "hello kratos!" {
+			t.Errorf("expect %v, got %v", "hello kratos!", req)
+		}
 		i += 10
 		return "reply", nil
 	}
diff --git a/middleware/ratelimit/ratelimit_test.go b/middleware/ratelimit/ratelimit_test.go
index b1422347..20cf9934 100644
--- a/middleware/ratelimit/ratelimit_test.go
+++ b/middleware/ratelimit/ratelimit_test.go
@@ -41,7 +41,7 @@ func Test_WithLimiter(t *testing.T) {
 }
 
 func TestServer(t *testing.T) {
-	nextValid := func(ctx context.Context, req interface{}) (interface{}, error) {
+	nextValid := func(context.Context, interface{}) (interface{}, error) {
 		return "Hello valid", nil
 	}
 
diff --git a/middleware/recovery/recovery_test.go b/middleware/recovery/recovery_test.go
index b20b5652..915861a2 100644
--- a/middleware/recovery/recovery_test.go
+++ b/middleware/recovery/recovery_test.go
@@ -15,7 +15,7 @@ func TestOnce(t *testing.T) {
 		}
 	}()
 
-	next := func(ctx context.Context, req interface{}) (interface{}, error) {
+	next := func(context.Context, interface{}) (interface{}, error) {
 		panic("panic reason")
 	}
 	_, e := Recovery(WithHandler(func(ctx context.Context, _, err interface{}) error {
@@ -29,11 +29,11 @@ func TestOnce(t *testing.T) {
 }
 
 func TestNotPanic(t *testing.T) {
-	next := func(ctx context.Context, req interface{}) (interface{}, error) {
+	next := func(_ context.Context, req interface{}) (interface{}, error) {
 		return req.(string) + "https://go-kratos.dev", nil
 	}
 
-	_, e := Recovery(WithHandler(func(ctx context.Context, req, err interface{}) error {
+	_, e := Recovery(WithHandler(func(_ context.Context, _ any, err any) error {
 		return errors.InternalServer("RECOVERY", fmt.Sprintf("panic triggered: %v", err))
 	}))(next)(context.Background(), "notPanic")
 	if e != nil {
diff --git a/middleware/selector/selector_test.go b/middleware/selector/selector_test.go
index 0835ef84..1769f7c0 100644
--- a/middleware/selector/selector_test.go
+++ b/middleware/selector/selector_test.go
@@ -96,7 +96,7 @@ func TestMatch(t *testing.T) {
 	}
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
-			next := func(ctx context.Context, req interface{}) (interface{}, error) {
+			next := func(_ context.Context, req interface{}) (interface{}, error) {
 				t.Log(req)
 				return "reply", nil
 			}
@@ -132,7 +132,7 @@ func TestMatchClient(t *testing.T) {
 	}
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
-			next := func(ctx context.Context, req interface{}) (interface{}, error) {
+			next := func(_ context.Context, req interface{}) (interface{}, error) {
 				t.Log(req)
 				return "reply", nil
 			}
@@ -167,11 +167,11 @@ func TestFunc(t *testing.T) {
 	}
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
-			next := func(ctx context.Context, req interface{}) (interface{}, error) {
+			next := func(_ context.Context, req interface{}) (interface{}, error) {
 				t.Log(req)
 				return "reply", nil
 			}
-			next = Server(testMiddleware).Match(func(ctx context.Context, operation string) bool {
+			next = Server(testMiddleware).Match(func(_ context.Context, operation string) bool {
 				if strings.HasPrefix(operation, "/go-kratos.dev") || strings.HasSuffix(operation, "world") {
 					return true
 				}
@@ -224,11 +224,11 @@ func TestHeaderFunc(t *testing.T) {
 	}
 	for _, test := range tests {
 		t.Run(test.name, func(t *testing.T) {
-			next := func(ctx context.Context, req interface{}) (interface{}, error) {
+			next := func(_ context.Context, req interface{}) (interface{}, error) {
 				t.Log(req)
 				return "reply", nil
 			}
-			next = Server(testMiddleware).Match(func(ctx context.Context, operation string) bool {
+			next = Server(testMiddleware).Match(func(ctx context.Context, _ string) bool {
 				tr, ok := transport.FromServerContext(ctx)
 				if !ok {
 					return false
diff --git a/middleware/tracing/tracing_test.go b/middleware/tracing/tracing_test.go
index 72740baf..fe902802 100644
--- a/middleware/tracing/tracing_test.go
+++ b/middleware/tracing/tracing_test.go
@@ -166,7 +166,6 @@ func TestServer(t *testing.T) {
 		WithTracerProvider(tracesdk.NewTracerProvider()),
 		WithPropagator(propagation.NewCompositeTextMapPropagator(propagation.Baggage{}, propagation.TraceContext{})),
 	)(next)(context.Background(), "test server: ")
-
 	if err != nil {
 		t.Errorf("expected error, got nil")
 	}
diff --git a/middleware/validate/validate_test.go b/middleware/validate/validate_test.go
index 34fc3349..34bea301 100644
--- a/middleware/validate/validate_test.go
+++ b/middleware/validate/validate_test.go
@@ -24,7 +24,7 @@ func (v protoVali) Validate() error {
 }
 
 func TestTable(t *testing.T) {
-	var mock middleware.Handler = func(ctx context.Context, req interface{}) (interface{}, error) { return nil, nil }
+	var mock middleware.Handler = func(context.Context, interface{}) (interface{}, error) { return nil, nil }
 
 	tests := []protoVali{
 		{"v1", 365, false},
diff --git a/options_test.go b/options_test.go
index e1b7288b..03cf4f51 100644
--- a/options_test.go
+++ b/options_test.go
@@ -66,9 +66,11 @@ func TestEndpoint(t *testing.T) {
 }
 
 func TestContext(t *testing.T) {
-	type ctxKey = struct{}
+	type ctxKey struct {
+		Key string
+	}
 	o := &options{}
-	v := context.WithValue(context.TODO(), ctxKey{}, "b")
+	v := context.WithValue(context.TODO(), ctxKey{Key: "context"}, "b")
 	Context(v)(o)
 	if !reflect.DeepEqual(v, o.ctx) {
 		t.Fatalf("o.ctx:%s is not equal to v:%s", o.ctx, v)
diff --git a/selector/selector_test.go b/selector/selector_test.go
index b7b963f0..75d3887a 100644
--- a/selector/selector_test.go
+++ b/selector/selector_test.go
@@ -37,7 +37,7 @@ func (n *mockWeightedNode) Weight() float64 {
 func (n *mockWeightedNode) Pick() DoneFunc {
 	now := time.Now().UnixNano()
 	atomic.StoreInt64(&n.lastPick, now)
-	return func(ctx context.Context, di DoneInfo) {}
+	return func(context.Context, DoneInfo) {}
 }
 
 // PickElapsed is time elapsed since the latest pick
diff --git a/transport/grpc/client_test.go b/transport/grpc/client_test.go
index 2d88f95a..cdbee600 100644
--- a/transport/grpc/client_test.go
+++ b/transport/grpc/client_test.go
@@ -84,7 +84,7 @@ func TestUnaryClientInterceptor(t *testing.T) {
 	resp := &struct{}{}
 
 	err := f(context.TODO(), "hello", req, resp, &grpc.ClientConn{},
-		func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, opts ...grpc.CallOption) error {
+		func(context.Context, string, any, any, *grpc.ClientConn, ...grpc.CallOption) error {
 			return nil
 		})
 	if err != nil {
@@ -95,10 +95,10 @@ func TestUnaryClientInterceptor(t *testing.T) {
 func TestWithUnaryInterceptor(t *testing.T) {
 	o := &clientOptions{}
 	v := []grpc.UnaryClientInterceptor{
-		func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
+		func(context.Context, string, any, any, *grpc.ClientConn, grpc.UnaryInvoker, ...grpc.CallOption) error {
 			return nil
 		},
-		func(ctx context.Context, method string, req, reply interface{}, cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption) error {
+		func(context.Context, string, any, any, *grpc.ClientConn, grpc.UnaryInvoker, ...grpc.CallOption) error {
 			return nil
 		},
 	}
diff --git a/transport/grpc/resolver/discovery/builder_test.go b/transport/grpc/resolver/discovery/builder_test.go
index 64051051..0f27078a 100644
--- a/transport/grpc/resolver/discovery/builder_test.go
+++ b/transport/grpc/resolver/discovery/builder_test.go
@@ -81,7 +81,7 @@ func (m *mockConn) ParseServiceConfig(_ string) *serviceconfig.ParseResult {
 }
 
 func TestBuilder_Build(t *testing.T) {
-	b := NewBuilder(&mockDiscovery{}, DisableDebugLog())
+	b := NewBuilder(&mockDiscovery{}, PrintDebugLog(false))
 	_, err := b.Build(
 		resolver.Target{
 			URL: url.URL{
diff --git a/transport/grpc/server_test.go b/transport/grpc/server_test.go
index d9d2c7af..0117db9a 100644
--- a/transport/grpc/server_test.go
+++ b/transport/grpc/server_test.go
@@ -12,6 +12,7 @@ import (
 	"time"
 
 	"google.golang.org/grpc"
+	"google.golang.org/grpc/metadata"
 
 	"github.com/go-kratos/kratos/v2/errors"
 	"github.com/go-kratos/kratos/v2/internal/matcher"
@@ -83,7 +84,7 @@ func TestServer(t *testing.T) {
 					return handler(ctx, req)
 				}
 			}),
-		UnaryInterceptor(func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
+		UnaryInterceptor(func(ctx context.Context, req interface{}, _ *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
 			return handler(ctx, req)
 		}),
 		Options(grpc.InitialConnWindowSize(0)),
@@ -212,10 +213,10 @@ func TestTLSConfig(t *testing.T) {
 func TestUnaryInterceptor(t *testing.T) {
 	o := &Server{}
 	v := []grpc.UnaryServerInterceptor{
-		func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
+		func(context.Context, interface{}, *grpc.UnaryServerInfo, grpc.UnaryHandler) (resp interface{}, err error) {
 			return nil, nil
 		},
-		func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (resp interface{}, err error) {
+		func(context.Context, interface{}, *grpc.UnaryServerInfo, grpc.UnaryHandler) (resp interface{}, err error) {
 			return nil, nil
 		},
 	}
@@ -228,10 +229,10 @@ func TestUnaryInterceptor(t *testing.T) {
 func TestStreamInterceptor(t *testing.T) {
 	o := &Server{}
 	v := []grpc.StreamServerInterceptor{
-		func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
+		func(interface{}, grpc.ServerStream, *grpc.StreamServerInfo, grpc.StreamHandler) error {
 			return nil
 		},
-		func(srv interface{}, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
+		func(interface{}, grpc.ServerStream, *grpc.StreamServerInfo, grpc.StreamHandler) error {
 			return nil
 		},
 	}
@@ -269,7 +270,7 @@ func TestServer_unaryServerInterceptor(t *testing.T) {
 	}
 	srv.middleware.Use(EmptyMiddleware())
 	req := &struct{}{}
-	rv, err := srv.unaryServerInterceptor()(context.TODO(), req, &grpc.UnaryServerInfo{}, func(ctx context.Context, req interface{}) (i interface{}, e error) {
+	rv, err := srv.unaryServerInterceptor()(context.TODO(), req, &grpc.UnaryServerInfo{}, func(context.Context, interface{}) (interface{}, error) {
 		return &testResp{Data: "hi"}, nil
 	})
 	if err != nil {
@@ -280,6 +281,82 @@ func TestServer_unaryServerInterceptor(t *testing.T) {
 	}
 }
 
+type mockServerStream struct {
+	ctx      context.Context
+	sentMsg  interface{}
+	recvMsg  interface{}
+	metadata metadata.MD
+	grpc.ServerStream
+}
+
+func (m *mockServerStream) SetHeader(md metadata.MD) error {
+	m.metadata = md
+	return nil
+}
+
+func (m *mockServerStream) SendHeader(md metadata.MD) error {
+	m.metadata = md
+	return nil
+}
+
+func (m *mockServerStream) SetTrailer(md metadata.MD) {
+	m.metadata = md
+}
+
+func (m *mockServerStream) Context() context.Context {
+	return m.ctx
+}
+
+func (m *mockServerStream) SendMsg(msg interface{}) error {
+	m.sentMsg = msg
+	return nil
+}
+
+func (m *mockServerStream) RecvMsg(msg interface{}) error {
+	m.recvMsg = msg
+	return nil
+}
+
+func TestServer_streamServerInterceptor(t *testing.T) {
+	u, err := url.Parse("grpc://hello/world")
+	if err != nil {
+		t.Errorf("expect %v, got %v", nil, err)
+	}
+	srv := &Server{
+		baseCtx:          context.Background(),
+		endpoint:         u,
+		timeout:          time.Duration(10),
+		middleware:       matcher.New(),
+		streamMiddleware: matcher.New(),
+	}
+
+	srv.streamMiddleware.Use(EmptyMiddleware())
+
+	mockStream := &mockServerStream{
+		ctx: srv.baseCtx,
+	}
+
+	handler := func(_ interface{}, stream grpc.ServerStream) error {
+		resp := &testResp{Data: "stream hi"}
+		return stream.SendMsg(resp)
+	}
+
+	info := &grpc.StreamServerInfo{
+		FullMethod: "/grpc.reflection.v1.ServerReflection/ServerReflectionInfo",
+	}
+
+	err = srv.streamServerInterceptor()(nil, mockStream, info, handler)
+	if err != nil {
+		t.Errorf("expect %v, got %v", nil, err)
+	}
+
+	// Check response
+	resp := mockStream.sentMsg.(*testResp)
+	if !reflect.DeepEqual("stream hi", resp.Data) {
+		t.Errorf("expect %s, got %s", "stream hi", resp.Data)
+	}
+}
+
 func TestListener(t *testing.T) {
 	lis, err := net.Listen("tcp", ":0")
 	if err != nil {
diff --git a/transport/http/client_test.go b/transport/http/client_test.go
index 25ae9a8e..13bf4428 100644
--- a/transport/http/client_test.go
+++ b/transport/http/client_test.go
@@ -42,6 +42,15 @@ func (x *mockCallOption) after(_ *callInfo, _ *csAttempt) {
 	log.Println("run in mockCallOption.after")
 }
 
+func TestWithSubset(t *testing.T) {
+	co := &clientOptions{}
+	o := WithSubset(1)
+	o(co)
+	if co.subsetSize != 1 {
+		t.Error("expected subset size to be 1")
+	}
+}
+
 func TestWithTransport(t *testing.T) {
 	ov := &mockRoundTripper{}
 	o := WithTransport(ov)
@@ -71,10 +80,6 @@ func TestWithBlock(t *testing.T) {
 	}
 }
 
-func TestWithBalancer(_ *testing.T) {
-	// TODO
-}
-
 func TestWithTLSConfig(t *testing.T) {
 	ov := &tls.Config{}
 	o := WithTLSConfig(ov)
@@ -118,7 +123,7 @@ func TestWithEndpoint(t *testing.T) {
 
 func TestWithRequestEncoder(t *testing.T) {
 	o := &clientOptions{}
-	v := func(ctx context.Context, contentType string, in interface{}) (body []byte, err error) {
+	v := func(context.Context, string, interface{}) (body []byte, err error) {
 		return nil, nil
 	}
 	WithRequestEncoder(v)(o)
@@ -129,7 +134,7 @@ func TestWithRequestEncoder(t *testing.T) {
 
 func TestWithResponseDecoder(t *testing.T) {
 	o := &clientOptions{}
-	v := func(ctx context.Context, res *http.Response, out interface{}) error { return nil }
+	v := func(context.Context, *http.Response, interface{}) error { return nil }
 	WithResponseDecoder(v)(o)
 	if o.decoder == nil {
 		t.Errorf("expected encoder to be not nil")
@@ -138,7 +143,7 @@ func TestWithResponseDecoder(t *testing.T) {
 
 func TestWithErrorDecoder(t *testing.T) {
 	o := &clientOptions{}
-	v := func(ctx context.Context, res *http.Response) error { return nil }
+	v := func(context.Context, *http.Response) error { return nil }
 	WithErrorDecoder(v)(o)
 	if o.errorDecoder == nil {
 		t.Errorf("expected encoder to be not nil")
@@ -354,7 +359,7 @@ func TestNewClient(t *testing.T) {
 	if err == nil {
 		t.Error("err should be equal to callOption err")
 	}
-	client.opts.encoder = func(ctx context.Context, contentType string, in interface{}) (body []byte, err error) {
+	client.opts.encoder = func(context.Context, string, interface{}) (body []byte, err error) {
 		return nil, errors.New("mock test encoder error")
 	}
 	err = client.Invoke(context.Background(), http.MethodPost, "/go", map[string]string{"name": "kratos"}, nil, EmptyCallOption{})
diff --git a/transport/http/context_test.go b/transport/http/context_test.go
index 8cc79da0..b4949a02 100644
--- a/transport/http/context_test.go
+++ b/transport/http/context_test.go
@@ -102,7 +102,7 @@ func TestContextResponse(t *testing.T) {
 
 func TestResponseUnwrap(t *testing.T) {
 	res := httptest.NewRecorder()
-	f := func(rw http.ResponseWriter, r *http.Request, a interface{}) error {
+	f := func(rw http.ResponseWriter, _ *http.Request, _ interface{}) error {
 		u, ok := rw.(interface {
 			Unwrap() http.ResponseWriter
 		})
diff --git a/transport/http/router_test.go b/transport/http/router_test.go
index e6def62e..00b1a7dd 100644
--- a/transport/http/router_test.go
+++ b/transport/http/router_test.go
@@ -75,7 +75,7 @@ func TestRoute(t *testing.T) {
 		if err := ctx.Bind(u); err != nil {
 			return err
 		}
-		h := ctx.Middleware(func(ctx context.Context, in interface{}) (interface{}, error) {
+		h := ctx.Middleware(func(context.Context, interface{}) (interface{}, error) {
 			return u, nil
 		})
 		return ctx.Returns(h(ctx, u))
@@ -184,7 +184,7 @@ func TestRouter_Group(t *testing.T) {
 
 func TestHandle(_ *testing.T) {
 	r := newRouter("/", NewServer())
-	h := func(i Context) error {
+	h := func(Context) error {
 		return nil
 	}
 	r.GET("/get", h)
diff --git a/transport/http/server_test.go b/transport/http/server_test.go
index 44477504..c692a4ff 100644
--- a/transport/http/server_test.go
+++ b/transport/http/server_test.go
@@ -48,7 +48,7 @@ func TestServeHTTP(t *testing.T) {
 	}
 	mux := NewServer(Listener(ln))
 	mux.HandleFunc("/index", h)
-	mux.Route("/errors").GET("/cause", func(ctx Context) error {
+	mux.Route("/errors").GET("/cause", func(Context) error {
 		return kratoserrors.BadRequest("xxx", "zzz").
 			WithMetadata(map[string]string{"foo": "bar"}).
 			WithCause(errors.New("error cause"))
@@ -86,7 +86,7 @@ func TestServer(t *testing.T) {
 	srv.HandleHeader("content-type", "application/grpc-web+json", func(w http.ResponseWriter, r *http.Request) {
 		_ = json.NewEncoder(w).Encode(testData{Path: r.RequestURI})
 	})
-	srv.Route("/errors").GET("/cause", func(ctx Context) error {
+	srv.Route("/errors").GET("/cause", func(Context) error {
 		return kratoserrors.BadRequest("xxx", "zzz").
 			WithMetadata(map[string]string{"foo": "bar"}).
 			WithCause(errors.New("error cause"))
@@ -153,8 +153,7 @@ func testHeader(t *testing.T, srv *Server) {
 	if err != nil {
 		t.Errorf("expected nil got %v", err)
 	}
-	reqURL := fmt.Sprintf(e.String() + "/index")
-	req, err := http.NewRequest(http.MethodGet, reqURL, nil)
+	req, err := http.NewRequest(http.MethodGet, e.String()+"/index", nil)
 	if err != nil {
 		t.Errorf("expected nil got %v", err)
 	}
@@ -199,7 +198,7 @@ func testClient(t *testing.T, srv *Server) {
 	defer client.Close()
 	for _, test := range tests {
 		var res testData
-		reqURL := fmt.Sprintf(e.String() + test.path)
+		reqURL := e.String() + test.path
 		req, err := http.NewRequest(test.method, reqURL, nil)
 		if err != nil {
 			t.Fatal(err)
@@ -308,10 +307,6 @@ func TestTimeout(t *testing.T) {
 	}
 }
 
-func TestLogger(_ *testing.T) {
-	// TODO
-}
-
 func TestRequestDecoder(t *testing.T) {
 	o := &Server{}
 	v := func(*http.Request, interface{}) error { return nil }