Repository: dragonflyoss/Dragonfly2
Pull request #1137 (2022-03-08 11:55:26)

optimize proxy performance
<!--- Provide a general summary of your changes in the Title above -->

## Description

1. optimize back source trace and logic
2. fix keepalive performance
3. optimize generate peer id and transport performance
4. fix io.Copy call superfluous sendfile, then increase network latency

## Related Issue

<!--- This project only accepts pull requests related to open issues -->
<!--- If suggesting a new feature or change, please discuss it in an issue first -->
<!--- If fixing a bug, there should be an issue describing it with steps to reproduce -->
<!--- Please link to the issue here: -->

## Motivation and Context

<!--- Why is this change required? What problem does it solve? -->

## Screenshots (if appropriate)

## Types of changes

<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->

- [ ] Bug fix (non-breaking change which fixes an issue)
- [ ] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Documentation Update (if none of the other choices apply)

## Checklist

<!--- Go over all the following points, and put an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->

- [ ] Code compiles correctly.
- [ ] My code follows the code style of this project.
- [ ] My change requires a change to the documentation.
- [ ] I have updated the documentation accordingly.
- [ ] I have read the **CONTRIBUTING** document.
- [ ] I have added tests to cover my changes.
- [ ] All new and existing tests passed.



Patch:
diff --git a/Makefile b/Makefile
index a5c5199c..f86a3bf9 100644
--- a/Makefile
+++ b/Makefile
@@ -196,6 +196,7 @@ build-dfget-man-page:
 	@pandoc -s -t man ./docs/en/cli-reference/dfget.1.md -o ./docs/en/cli-reference/dfget.1
 .PHONY: build-dfget-man-page
 
+# Generate e2e sha256sum
 build-e2e-sha256sum:
 	@GOOS=linux GOARCH=amd64 go build -o /tmp/sha256sum-offset test/tools/sha256sum-offset/main.go
 .PHONY: build-e2e-sha256sum
@@ -236,6 +237,8 @@ e2e-test-coverage: install-e2e-test build-e2e-sha256sum
 # Clean E2E tests
 clean-e2e-test: 
 	@kind delete cluster
+	@echo "cleaning log file"
+	@rm -rf test/e2e/*.log
 .PHONY: clean-e2e-test
 
 # Kind load dragonlfy
@@ -285,6 +288,7 @@ generate:
 	@go generate ${PKG_LIST}
 .PHONY: generate
 
+# Generate swagger files
 swag:
 	@swag init --parseDependency --parseInternal -g cmd/manager/main.go -o api/manager
 
@@ -293,6 +297,7 @@ changelog:
 	@git-chglog -o CHANGELOG.md
 .PHONY: changelog
 
+# Clear compiled files
 clean:
 	@go clean
 	@rm -rf bin .go .cache
diff --git a/api/manager/docs.go b/api/manager/docs.go
index e72ce9a0..e1bbc3fb 100644
--- a/api/manager/docs.go
+++ b/api/manager/docs.go
@@ -2,16 +2,9 @@
 // This file was generated by swaggo/swag
 package manager
 
-import (
-	"bytes"
-	"encoding/json"
-	"strings"
-	"text/template"
+import "github.com/swaggo/swag"
 
-	"github.com/swaggo/swag"
-)
-
-var doc = `{
+const docTemplate = `{
     "schemes": {{ marshal .Schemes }},
     "swagger": "2.0",
     "info": {
@@ -3299,6 +3292,54 @@ var doc = `{
                         "description": ""
                     }
                 }
+            },
+            "patch": {
+                "description": "Update by json config",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "User"
+                ],
+                "summary": "Update User",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "id",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "User",
+                        "name": "User",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/types.UpdateUserRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/model.User"
+                        }
+                    },
+                    "400": {
+                        "description": ""
+                    },
+                    "404": {
+                        "description": ""
+                    },
+                    "500": {
+                        "description": ""
+                    }
+                }
             }
         },
         "/users/{id}/reset_password": {
@@ -3887,7 +3928,11 @@ var doc = `{
             ],
             "properties": {
                 "action": {
-                    "type": "string"
+                    "type": "string",
+                    "enum": [
+                        "read",
+                        "*"
+                    ]
                 },
                 "object": {
                     "type": "string"
@@ -3902,7 +3947,11 @@ var doc = `{
             ],
             "properties": {
                 "action": {
-                    "type": "string"
+                    "type": "string",
+                    "enum": [
+                        "read",
+                        "*"
+                    ]
                 },
                 "object": {
                     "type": "string"
@@ -3913,7 +3962,9 @@ var doc = `{
             "type": "object",
             "properties": {
                 "load_limit": {
-                    "type": "integer"
+                    "type": "integer",
+                    "maximum": 10000,
+                    "minimum": 1
                 },
                 "net_topology": {
                     "type": "string"
@@ -3937,7 +3988,11 @@ var doc = `{
                     "type": "string"
                 },
                 "state": {
-                    "type": "string"
+                    "type": "string",
+                    "enum": [
+                        "enable",
+                        "disable"
+                    ]
                 },
                 "url": {
                     "type": "string"
@@ -4079,7 +4134,11 @@ var doc = `{
                     "type": "string"
                 },
                 "name": {
-                    "type": "string"
+                    "type": "string",
+                    "enum": [
+                        "github",
+                        "google"
+                    ]
                 },
                 "redirect_url": {
                     "type": "string"
@@ -4224,7 +4283,11 @@ var doc = `{
                     }
                 },
                 "type": {
-                    "type": "string"
+                    "type": "string",
+                    "enum": [
+                        "image",
+                        "file"
+                    ]
                 },
                 "url": {
                     "type": "string"
@@ -4247,7 +4310,11 @@ var doc = `{
             ],
             "properties": {
                 "action": {
-                    "type": "string"
+                    "type": "string",
+                    "enum": [
+                        "read",
+                        "*"
+                    ]
                 },
                 "object": {
                     "type": "string"
@@ -4279,10 +4346,14 @@ var doc = `{
             ],
             "properties": {
                 "new_password": {
-                    "type": "string"
+                    "type": "string",
+                    "maxLength": 20,
+                    "minLength": 8
                 },
                 "old_password": {
-                    "type": "string"
+                    "type": "string",
+                    "maxLength": 20,
+                    "minLength": 8
                 }
             }
         },
@@ -4290,12 +4361,26 @@ var doc = `{
             "type": "object",
             "properties": {
                 "load_limit": {
-                    "type": "integer"
+                    "type": "integer",
+                    "maximum": 10000,
+                    "minimum": 1
+                },
+                "parallel_count": {
+                    "type": "integer",
+                    "maximum": 50,
+                    "minimum": 1
                 }
             }
         },
         "types.SchedulerClusterConfig": {
-            "type": "object"
+            "type": "object",
+            "properties": {
+                "filter_parent_limit": {
+                    "type": "integer",
+                    "maximum": 100,
+                    "minimum": 1
+                }
+            }
         },
         "types.SchedulerClusterScopes": {
             "type": "object",
@@ -4332,10 +4417,14 @@ var doc = `{
                     "type": "string"
                 },
                 "name": {
-                    "type": "string"
+                    "type": "string",
+                    "maxLength": 10,
+                    "minLength": 3
                 },
                 "password": {
-                    "type": "string"
+                    "type": "string",
+                    "maxLength": 20,
+                    "minLength": 8
                 },
                 "phone": {
                     "type": "string"
@@ -4358,7 +4447,11 @@ var doc = `{
                     "type": "string"
                 },
                 "state": {
-                    "type": "string"
+                    "type": "string",
+                    "enum": [
+                        "enable",
+                        "disable"
+                    ]
                 },
                 "url": {
                     "type": "string"
@@ -4449,7 +4542,11 @@ var doc = `{
                     "type": "string"
                 },
                 "name": {
-                    "type": "string"
+                    "type": "string",
+                    "enum": [
+                        "github",
+                        "google"
+                    ]
                 },
                 "redirect_url": {
                     "type": "string"
@@ -4539,60 +4636,42 @@ var doc = `{
                     "type": "string"
                 }
             }
+        },
+        "types.UpdateUserRequest": {
+            "type": "object",
+            "properties": {
+                "avatar": {
+                    "type": "string"
+                },
+                "bio": {
+                    "type": "string"
+                },
+                "email": {
+                    "type": "string"
+                },
+                "location": {
+                    "type": "string"
+                },
+                "phone": {
+                    "type": "string"
+                }
+            }
         }
     }
 }`
 
-type swaggerInfo struct {
-	Version     string
-	Host        string
-	BasePath    string
-	Schemes     []string
-	Title       string
-	Description string
-}
-
 // SwaggerInfo holds exported Swagger Info so clients can modify it
-var SwaggerInfo = swaggerInfo{
-	Version:     "1.0.0",
-	Host:        "localhost:8080",
-	BasePath:    "/api/v1",
-	Schemes:     []string{},
-	Title:       "Dragonfly Manager",
-	Description: "Dragonfly Manager Server",
-}
-
-type s struct{}
-
-func (s *s) ReadDoc() string {
-	sInfo := SwaggerInfo
-	sInfo.Description = strings.Replace(sInfo.Description, "\n", "\\n", -1)
-
-	t, err := template.New("swagger_info").Funcs(template.FuncMap{
-		"marshal": func(v interface{}) string {
-			a, _ := json.Marshal(v)
-			return string(a)
-		},
-		"escape": func(v interface{}) string {
-			// escape tabs
-			str := strings.Replace(v.(string), "\t", "\\t", -1)
-			// replace " with \", and if that results in \\", replace that with \\\"
-			str = strings.Replace(str, "\"", "\\\"", -1)
-			return strings.Replace(str, "\\\\\"", "\\\\\\\"", -1)
-		},
-	}).Parse(doc)
-	if err != nil {
-		return doc
-	}
-
-	var tpl bytes.Buffer
-	if err := t.Execute(&tpl, sInfo); err != nil {
-		return doc
-	}
-
-	return tpl.String()
+var SwaggerInfo = &swag.Spec{
+	Version:          "1.0.0",
+	Host:             "localhost:8080",
+	BasePath:         "/api/v1",
+	Schemes:          []string{},
+	Title:            "Dragonfly Manager",
+	Description:      "Dragonfly Manager Server",
+	InfoInstanceName: "swagger",
+	SwaggerTemplate:  docTemplate,
 }
 
 func init() {
-	swag.Register("swagger", &s{})
+	swag.Register(SwaggerInfo.InstanceName(), SwaggerInfo)
 }
diff --git a/api/manager/swagger.json b/api/manager/swagger.json
index 955e4808..fff95002 100644
--- a/api/manager/swagger.json
+++ b/api/manager/swagger.json
@@ -3285,6 +3285,54 @@
                         "description": ""
                     }
                 }
+            },
+            "patch": {
+                "description": "Update by json config",
+                "consumes": [
+                    "application/json"
+                ],
+                "produces": [
+                    "application/json"
+                ],
+                "tags": [
+                    "User"
+                ],
+                "summary": "Update User",
+                "parameters": [
+                    {
+                        "type": "string",
+                        "description": "id",
+                        "name": "id",
+                        "in": "path",
+                        "required": true
+                    },
+                    {
+                        "description": "User",
+                        "name": "User",
+                        "in": "body",
+                        "required": true,
+                        "schema": {
+                            "$ref": "#/definitions/types.UpdateUserRequest"
+                        }
+                    }
+                ],
+                "responses": {
+                    "200": {
+                        "description": "OK",
+                        "schema": {
+                            "$ref": "#/definitions/model.User"
+                        }
+                    },
+                    "400": {
+                        "description": ""
+                    },
+                    "404": {
+                        "description": ""
+                    },
+                    "500": {
+                        "description": ""
+                    }
+                }
             }
         },
         "/users/{id}/reset_password": {
@@ -3873,7 +3921,11 @@
             ],
             "properties": {
                 "action": {
-                    "type": "string"
+                    "type": "string",
+                    "enum": [
+                        "read",
+                        "*"
+                    ]
                 },
                 "object": {
                     "type": "string"
@@ -3888,7 +3940,11 @@
             ],
             "properties": {
                 "action": {
-                    "type": "string"
+                    "type": "string",
+                    "enum": [
+                        "read",
+                        "*"
+                    ]
                 },
                 "object": {
                     "type": "string"
@@ -3899,7 +3955,9 @@
             "type": "object",
             "properties": {
                 "load_limit": {
-                    "type": "integer"
+                    "type": "integer",
+                    "maximum": 10000,
+                    "minimum": 1
                 },
                 "net_topology": {
                     "type": "string"
@@ -3923,7 +3981,11 @@
                     "type": "string"
                 },
                 "state": {
-                    "type": "string"
+                    "type": "string",
+                    "enum": [
+                        "enable",
+                        "disable"
+                    ]
                 },
                 "url": {
                     "type": "string"
@@ -4065,7 +4127,11 @@
                     "type": "string"
                 },
                 "name": {
-                    "type": "string"
+                    "type": "string",
+                    "enum": [
+                        "github",
+                        "google"
+                    ]
                 },
                 "redirect_url": {
                     "type": "string"
@@ -4210,7 +4276,11 @@
                     }
                 },
                 "type": {
-                    "type": "string"
+                    "type": "string",
+                    "enum": [
+                        "image",
+                        "file"
+                    ]
                 },
                 "url": {
                     "type": "string"
@@ -4233,7 +4303,11 @@
             ],
             "properties": {
                 "action": {
-                    "type": "string"
+                    "type": "string",
+                    "enum": [
+                        "read",
+                        "*"
+                    ]
                 },
                 "object": {
                     "type": "string"
@@ -4265,10 +4339,14 @@
             ],
             "properties": {
                 "new_password": {
-                    "type": "string"
+                    "type": "string",
+                    "maxLength": 20,
+                    "minLength": 8
                 },
                 "old_password": {
-                    "type": "string"
+                    "type": "string",
+                    "maxLength": 20,
+                    "minLength": 8
                 }
             }
         },
@@ -4276,12 +4354,26 @@
             "type": "object",
             "properties": {
                 "load_limit": {
-                    "type": "integer"
+                    "type": "integer",
+                    "maximum": 10000,
+                    "minimum": 1
+                },
+                "parallel_count": {
+                    "type": "integer",
+                    "maximum": 50,
+                    "minimum": 1
                 }
             }
         },
         "types.SchedulerClusterConfig": {
-            "type": "object"
+            "type": "object",
+            "properties": {
+                "filter_parent_limit": {
+                    "type": "integer",
+                    "maximum": 100,
+                    "minimum": 1
+                }
+            }
         },
         "types.SchedulerClusterScopes": {
             "type": "object",
@@ -4318,10 +4410,14 @@
                     "type": "string"
                 },
                 "name": {
-                    "type": "string"
+                    "type": "string",
+                    "maxLength": 10,
+                    "minLength": 3
                 },
                 "password": {
-                    "type": "string"
+                    "type": "string",
+                    "maxLength": 20,
+                    "minLength": 8
                 },
                 "phone": {
                     "type": "string"
@@ -4344,7 +4440,11 @@
                     "type": "string"
                 },
                 "state": {
-                    "type": "string"
+                    "type": "string",
+                    "enum": [
+                        "enable",
+                        "disable"
+                    ]
                 },
                 "url": {
                     "type": "string"
@@ -4435,7 +4535,11 @@
                     "type": "string"
                 },
                 "name": {
-                    "type": "string"
+                    "type": "string",
+                    "enum": [
+                        "github",
+                        "google"
+                    ]
                 },
                 "redirect_url": {
                     "type": "string"
@@ -4525,6 +4629,26 @@
                     "type": "string"
                 }
             }
+        },
+        "types.UpdateUserRequest": {
+            "type": "object",
+            "properties": {
+                "avatar": {
+                    "type": "string"
+                },
+                "bio": {
+                    "type": "string"
+                },
+                "email": {
+                    "type": "string"
+                },
+                "location": {
+                    "type": "string"
+                },
+                "phone": {
+                    "type": "string"
+                }
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/api/manager/swagger.yaml b/api/manager/swagger.yaml
index 3d20e07f..1b3b1c6a 100644
--- a/api/manager/swagger.yaml
+++ b/api/manager/swagger.yaml
@@ -279,6 +279,9 @@ definitions:
   rbac.Permission:
     properties:
       action:
+        enum:
+        - read
+        - '*'
         type: string
       object:
         type: string
@@ -289,6 +292,9 @@ definitions:
   types.AddPermissionForRoleRequest:
     properties:
       action:
+        enum:
+        - read
+        - '*'
         type: string
       object:
         type: string
@@ -299,6 +305,8 @@ definitions:
   types.CDNClusterConfig:
     properties:
       load_limit:
+        maximum: 10000
+        minimum: 1
         type: integer
       net_topology:
         type: string
@@ -312,6 +320,9 @@ definitions:
       name:
         type: string
       state:
+        enum:
+        - enable
+        - disable
         type: string
       url:
         type: string
@@ -408,6 +419,9 @@ definitions:
       client_secret:
         type: string
       name:
+        enum:
+        - github
+        - google
         type: string
       redirect_url:
         type: string
@@ -507,6 +521,9 @@ definitions:
           type: string
         type: object
       type:
+        enum:
+        - image
+        - file
         type: string
       url:
         type: string
@@ -522,6 +539,9 @@ definitions:
   types.DeletePermissionForRoleRequest:
     properties:
       action:
+        enum:
+        - read
+        - '*'
         type: string
       object:
         type: string
@@ -543,8 +563,12 @@ definitions:
   types.ResetPasswordRequest:
     properties:
       new_password:
+        maxLength: 20
+        minLength: 8
         type: string
       old_password:
+        maxLength: 20
+        minLength: 8
         type: string
     required:
     - new_password
@@ -553,9 +577,20 @@ definitions:
   types.SchedulerClusterClientConfig:
     properties:
       load_limit:
+        maximum: 10000
+        minimum: 1
+        type: integer
+      parallel_count:
+        maximum: 50
+        minimum: 1
         type: integer
     type: object
   types.SchedulerClusterConfig:
+    properties:
+      filter_parent_limit:
+        maximum: 100
+        minimum: 1
+        type: integer
     type: object
   types.SchedulerClusterScopes:
     properties:
@@ -577,8 +612,12 @@ definitions:
       location:
         type: string
       name:
+        maxLength: 10
+        minLength: 3
         type: string
       password:
+        maxLength: 20
+        minLength: 8
         type: string
       phone:
         type: string
@@ -596,6 +635,9 @@ definitions:
       name:
         type: string
       state:
+        enum:
+        - enable
+        - disable
         type: string
       url:
         type: string
@@ -657,6 +699,9 @@ definitions:
       client_secret:
         type: string
       name:
+        enum:
+        - github
+        - google
         type: string
       redirect_url:
         type: string
@@ -716,6 +761,19 @@ definitions:
       proxy_domain:
         type: string
     type: object
+  types.UpdateUserRequest:
+    properties:
+      avatar:
+        type: string
+      bio:
+        type: string
+      email:
+        type: string
+      location:
+        type: string
+      phone:
+        type: string
+    type: object
 host: localhost:8080
 info:
   contact:
@@ -2912,6 +2970,38 @@ paths:
       summary: Get User
       tags:
       - User
+    patch:
+      consumes:
+      - application/json
+      description: Update by json config
+      parameters:
+      - description: id
+        in: path
+        name: id
+        required: true
+        type: string
+      - description: User
+        in: body
+        name: User
+        required: true
+        schema:
+          $ref: '#/definitions/types.UpdateUserRequest'
+      produces:
+      - application/json
+      responses:
+        "200":
+          description: OK
+          schema:
+            $ref: '#/definitions/model.User'
+        "400":
+          description: ""
+        "404":
+          description: ""
+        "500":
+          description: ""
+      summary: Update User
+      tags:
+      - User
   /users/{id}/reset_password:
     post:
       consumes:
diff --git a/cdn/supervisor/cdn/storage/disk/config.go b/cdn/supervisor/cdn/storage/disk/config.go
index d59d0ee7..8a8873a6 100644
--- a/cdn/supervisor/cdn/storage/disk/config.go
+++ b/cdn/supervisor/cdn/storage/disk/config.go
@@ -65,7 +65,7 @@ func getDiskDriverConfig(diskDriver storedriver.Driver) (*storage.DriverConfig,
 		BaseDir: diskDriver.GetBaseDir(),
 		DriverGCConfig: &storage.DriverGCConfig{
 			YoungGCThreshold:  yongGCThreshold,
-			FullGCThreshold:   25 * unit.GB,
+			FullGCThreshold:   5 * unit.GB,
 			IntervalThreshold: 2 * time.Hour,
 			CleanRatio:        1,
 		},
diff --git a/cdn/supervisor/cdn/storage/disk/disk.go b/cdn/supervisor/cdn/storage/disk/disk.go
index 2b74ec40..12565dc2 100644
--- a/cdn/supervisor/cdn/storage/disk/disk.go
+++ b/cdn/supervisor/cdn/storage/disk/disk.go
@@ -26,7 +26,6 @@ import (
 	"strings"
 
 	"github.com/pkg/errors"
-	"github.com/sirupsen/logrus"
 	"go.uber.org/atomic"
 
 	"d7y.io/dragonfly/v2/cdn/gc"
@@ -203,6 +202,12 @@ func (s *diskStorageManager) ResetRepo(seedTask *task.SeedTask) error {
 }
 
 func (s *diskStorageManager) DeleteTask(taskID string) error {
+	if err := s.diskDriver.Remove(storage.GetUploadRaw(taskID)); err != nil && !os.IsNotExist(err) {
+		return err
+	}
+	if err := s.diskDriver.Remove(storage.GetUploadParentRaw(taskID)); err != nil && !os.IsNotExist(err) {
+		logger.StorageGCLogger.Warnf("taskID: %s failed remove upload parent bucket: %v", taskID, err)
+	}
 	if err := s.diskDriver.Remove(storage.GetTaskMetadataRaw(taskID)); err != nil && !os.IsNotExist(err) {
 		return err
 	}
@@ -212,12 +217,9 @@ func (s *diskStorageManager) DeleteTask(taskID string) error {
 	if err := s.diskDriver.Remove(storage.GetDownloadRaw(taskID)); err != nil && !os.IsNotExist(err) {
 		return err
 	}
-	if err := s.diskDriver.Remove(storage.GetUploadRaw(taskID)); err != nil && !os.IsNotExist(err) {
-		return err
-	}
 	// try to clean the parent bucket
-	if err := s.diskDriver.Remove(storage.GetParentRaw(taskID)); err != nil && !os.IsNotExist(err) {
-		logrus.Warnf("taskID: %s failed remove parent bucket: %v", taskID, err)
+	if err := s.diskDriver.Remove(storage.GetDownloadParentRaw(taskID)); err != nil && !os.IsNotExist(err) {
+		logger.StorageGCLogger.Warnf("taskID: %s failed remove download parent bucket: %v", taskID, err)
 	}
 	return nil
 }
@@ -280,22 +282,22 @@ func (s *diskStorageManager) TryFreeSpace(fileLength int64) (bool, error) {
 }
 
 func (s *diskStorageManager) GC() error {
-	logger.StorageGCLogger.With("type", "disk").Info("start the disk storage gc job")
+	logger.StorageGCLogger.With("type", "disk").Debug("start the disk storage gc job")
 	gcTaskIDs, err := s.diskCleaner.GC("disk", false)
 	if err != nil {
 		logger.StorageGCLogger.With("type", "disk").Error("failed to get gcTaskIDs")
 	}
-	var gcTasks []string
+	var actualGCTasks []string
 	var remainingTasks []string
 	for _, taskID := range gcTaskIDs {
 		synclock.Lock(taskID, false)
 		// try to ensure the taskID is not using again
 		if _, exist := s.taskManager.Exist(taskID); exist {
-			synclock.UnLock(taskID, false)
 			remainingTasks = append(remainingTasks, taskID)
+			synclock.UnLock(taskID, false)
 			continue
 		}
-		gcTasks = append(gcTasks, taskID)
+		actualGCTasks = append(actualGCTasks, taskID)
 		if err := s.DeleteTask(taskID); err != nil {
 			logger.StorageGCLogger.With("type", "disk").Errorf("failed to delete disk files with taskID(%s): %v", taskID, err)
 			synclock.UnLock(taskID, false)
@@ -303,7 +305,8 @@ func (s *diskStorageManager) GC() error {
 		}
 		synclock.UnLock(taskID, false)
 	}
-	logger.StorageGCLogger.With("type", "disk").Infof("at most %d tasks can be cleaned up, actual gc %d tasks", len(gcTaskIDs), len(remainingTasks))
-	logger.StorageGCLogger.With("type", "disk").Debugf("tasks %s were successfully cleared, leaving tasks %s remaining", gcTasks, remainingTasks)
+	logger.StorageGCLogger.With("type", "disk").Infof("at most %d tasks can be cleaned up, actual gc %d tasks, remaining %d tasks", len(gcTaskIDs),
+		len(actualGCTasks), len(remainingTasks))
+	logger.StorageGCLogger.With("type", "disk").Debugf("tasks %s were successfully cleared, leaving tasks %s remaining", actualGCTasks, remainingTasks)
 	return nil
 }
diff --git a/cdn/supervisor/cdn/storage/hybrid/config.go b/cdn/supervisor/cdn/storage/hybrid/config.go
index e9958619..71fa9685 100644
--- a/cdn/supervisor/cdn/storage/hybrid/config.go
+++ b/cdn/supervisor/cdn/storage/hybrid/config.go
@@ -70,7 +70,7 @@ func getDiskDriverConfig(diskDriver storedriver.Driver) (*storage.DriverConfig,
 		BaseDir: diskDriver.GetBaseDir(),
 		DriverGCConfig: &storage.DriverGCConfig{
 			YoungGCThreshold:  yongGCThreshold,
-			FullGCThreshold:   25 * unit.GB,
+			FullGCThreshold:   5 * unit.GB,
 			IntervalThreshold: 2 * time.Hour,
 			CleanRatio:        1,
 		},
diff --git a/cdn/supervisor/cdn/storage/hybrid/hybrid.go b/cdn/supervisor/cdn/storage/hybrid/hybrid.go
index 77d2484a..2e6cf0eb 100644
--- a/cdn/supervisor/cdn/storage/hybrid/hybrid.go
+++ b/cdn/supervisor/cdn/storage/hybrid/hybrid.go
@@ -291,6 +291,14 @@ func (h *hybridStorageManager) deleteMemoryFiles(taskID string) error {
 }
 
 func (h *hybridStorageManager) deleteTaskFiles(taskID string, deleteHardLink bool) error {
+	// delete upload file
+	if err := h.diskDriver.Remove(storage.GetUploadRaw(taskID)); err != nil && !os.IsNotExist(err) {
+		return err
+	}
+	if err := h.diskDriver.Remove(storage.GetUploadParentRaw(taskID)); err != nil &&
+		!os.IsNotExist(err) {
+		logger.WithTaskID(taskID).Warnf("failed to remove upload parent bucket: %v", err)
+	}
 	// delete task file data
 	if err := h.diskDriver.Remove(storage.GetDownloadRaw(taskID)); err != nil && !os.IsNotExist(err) {
 		return err
@@ -299,10 +307,6 @@ func (h *hybridStorageManager) deleteTaskFiles(taskID string, deleteHardLink boo
 	if err := h.memoryDriver.Remove(storage.GetDownloadRaw(taskID)); err != nil && !os.IsNotExist(err) {
 		return err
 	}
-	// delete upload file
-	if err := h.diskDriver.Remove(storage.GetUploadRaw(taskID)); err != nil && !os.IsNotExist(err) {
-		return err
-	}
 	exists := h.diskDriver.Exits(getHardLinkRaw(taskID))
 	if !deleteHardLink && exists {
 		if err := h.diskDriver.MoveFile(h.diskDriver.GetPath(getHardLinkRaw(taskID)), h.diskDriver.GetPath(storage.GetDownloadRaw(taskID))); err != nil {
@@ -322,9 +326,9 @@ func (h *hybridStorageManager) deleteTaskFiles(taskID string, deleteHardLink boo
 		}
 	}
 	// try to clean the parent bucket
-	if err := h.diskDriver.Remove(storage.GetParentRaw(taskID)); err != nil &&
+	if err := h.diskDriver.Remove(storage.GetDownloadParentRaw(taskID)); err != nil &&
 		!os.IsNotExist(err) {
-		logger.WithTaskID(taskID).Warnf("failed to remove parent bucket: %v", err)
+		logger.WithTaskID(taskID).Warnf("failed to remove download parent bucket: %v", err)
 	}
 	return nil
 }
@@ -378,7 +382,7 @@ func (h *hybridStorageManager) tryShmSpace(url, taskID string, fileLength int64)
 }
 
 func (h *hybridStorageManager) GC() error {
-	logger.StorageGCLogger.With("type", "hybrid").Info("start the hybrid storage gc job")
+	logger.StorageGCLogger.With("type", "hybrid").Debug("start the hybrid storage gc job")
 	var wg sync.WaitGroup
 	wg.Add(1)
 	go func() {
diff --git a/cdn/supervisor/cdn/storage/path_util.go b/cdn/supervisor/cdn/storage/path_util.go
index 9c10e8f4..d91074b2 100644
--- a/cdn/supervisor/cdn/storage/path_util.go
+++ b/cdn/supervisor/cdn/storage/path_util.go
@@ -86,13 +86,20 @@ func GetAppendPieceMetadataRaw(taskID string) *storedriver.Raw {
 	}
 }
 
-func GetParentRaw(taskID string) *storedriver.Raw {
+func GetDownloadParentRaw(taskID string) *storedriver.Raw {
 	return &storedriver.Raw{
 		Bucket: DownloadHome,
 		Key:    getParentKey(taskID),
 	}
 }
 
+func GetUploadParentRaw(taskID string) *storedriver.Raw {
+	return &storedriver.Raw{
+		Bucket: UploadHome,
+		Key:    getParentKey(taskID),
+	}
+}
+
 func GetDownloadHomeRaw() *storedriver.Raw {
 	return &storedriver.Raw{
 		Bucket: DownloadHome,
diff --git a/cdn/supervisor/cdn/storage/storage_gc.go b/cdn/supervisor/cdn/storage/storage_gc.go
index dc0395f9..e69bda72 100644
--- a/cdn/supervisor/cdn/storage/storage_gc.go
+++ b/cdn/supervisor/cdn/storage/storage_gc.go
@@ -87,8 +87,6 @@ func (cleaner *cleaner) GC(storagePattern string, force bool) ([]string, error)
 	walkTaskIds := make(map[string]bool)
 	var gcTaskIDs []string
 	walkFn := func(path string, info os.FileInfo, err error) error {
-		logger.StorageGCLogger.With("type", storagePattern).Debugf("start to walk path(%s)", path)
-
 		if err != nil {
 			logger.StorageGCLogger.With("type", storagePattern).Errorf("failed to access path(%s): %v", path, err)
 			return err
diff --git a/cdn/supervisor/service.go b/cdn/supervisor/service.go
index be53bd3b..ef0bb0ee 100644
--- a/cdn/supervisor/service.go
+++ b/cdn/supervisor/service.go
@@ -88,6 +88,7 @@ func (service *cdnService) triggerCdnSyncAction(ctx context.Context, taskID stri
 		if ok, err := service.cdnManager.TryFreeSpace(seedTask.SourceFileLength); err != nil {
 			seedTask.Log().Errorf("failed to try free space: %v", err)
 		} else if !ok {
+			synclock.UnLock(taskID, true)
 			return errResourcesLacked
 		}
 	}
diff --git a/client/clientutil/keepalive.go b/client/clientutil/keepalive.go
index 6053f12d..bf5cb22a 100644
--- a/client/clientutil/keepalive.go
+++ b/client/clientutil/keepalive.go
@@ -19,6 +19,8 @@ package clientutil
 import (
 	"time"
 
+	"go.uber.org/atomic"
+
 	logger "d7y.io/dragonfly/v2/internal/dflog"
 )
 
@@ -31,26 +33,28 @@ type KeepAlive interface {
 
 type keepAlive struct {
 	name   string
-	access time.Time
+	access atomic.Int64
 }
 
 var _ KeepAlive = (*keepAlive)(nil)
 
 func NewKeepAlive(name string) KeepAlive {
 	return &keepAlive{
-		name:   name,
-		access: time.Now(),
+		name: name,
 	}
 }
 
-func (k keepAlive) Keep() {
-	k.access = time.Now()
-	logger.Debugf("update %s keepalive access time: %s", k.name, k.access.Format(time.RFC3339))
+func (k *keepAlive) Keep() {
+	k.access.Store(time.Now().UnixNano())
 }
 
-func (k keepAlive) Alive(alive time.Duration) bool {
-	var now = time.Now()
+func (k *keepAlive) Alive(alive time.Duration) bool {
+	var (
+		now    = time.Now()
+		access = time.Unix(0, k.access.Load())
+	)
+
 	logger.Debugf("%s keepalive check, last access: %s, alive time: %f seconds, current time: %s",
-		k.name, k.access.Format(time.RFC3339), alive.Seconds(), now)
-	return k.access.Add(alive).After(now)
+		k.name, access.Format(time.RFC3339), alive.Seconds(), now)
+	return access.Add(alive).After(now)
 }
diff --git a/client/config/peerhost.go b/client/config/peerhost.go
index be187a41..29e79879 100644
--- a/client/config/peerhost.go
+++ b/client/config/peerhost.go
@@ -38,7 +38,6 @@ import (
 	"d7y.io/dragonfly/v2/internal/dfnet"
 	"d7y.io/dragonfly/v2/pkg/unit"
 	"d7y.io/dragonfly/v2/pkg/util/net/iputils"
-	"d7y.io/dragonfly/v2/pkg/util/stringutils"
 )
 
 type DaemonConfig = DaemonOption
@@ -57,14 +56,13 @@ type DaemonOption struct {
 	DataDir     string `mapstructure:"dataDir" yaml:"dataDir"`
 	KeepStorage bool   `mapstructure:"keepStorage" yaml:"keepStorage"`
 
-	Scheduler    SchedulerOption `mapstructure:"scheduler" yaml:"scheduler"`
-	Host         HostOption      `mapstructure:"host" yaml:"host"`
-	Download     DownloadOption  `mapstructure:"download" yaml:"download"`
-	Proxy        *ProxyOption    `mapstructure:"proxy" yaml:"proxy"`
-	Upload       UploadOption    `mapstructure:"upload" yaml:"upload"`
-	Storage      StorageOption   `mapstructure:"storage" yaml:"storage"`
-	ConfigServer string          `mapstructure:"configServer" yaml:"configServer"`
-	Health       *HealthOption   `mapstructure:"health" yaml:"health"`
+	Scheduler SchedulerOption `mapstructure:"scheduler" yaml:"scheduler"`
+	Host      HostOption      `mapstructure:"host" yaml:"host"`
+	Download  DownloadOption  `mapstructure:"download" yaml:"download"`
+	Proxy     *ProxyOption    `mapstructure:"proxy" yaml:"proxy"`
+	Upload    UploadOption    `mapstructure:"upload" yaml:"upload"`
+	Storage   StorageOption   `mapstructure:"storage" yaml:"storage"`
+	Health    *HealthOption   `mapstructure:"health" yaml:"health"`
 	// TODO WIP, did not use
 	Reload ReloadOption `mapstructure:"reloadOption" yaml:"reloadOption"`
 }
@@ -115,20 +113,19 @@ func (p *DaemonOption) Convert() error {
 }
 
 func (p *DaemonOption) Validate() error {
-	if len(p.Scheduler.NetAddrs) == 0 && stringutils.IsBlank(p.ConfigServer) {
-		return errors.New("empty schedulers and config server is not specified")
-	}
-
 	if p.Scheduler.Manager.Enable {
-		if len(p.Scheduler.NetAddrs) == 0 {
+		if len(p.Scheduler.Manager.NetAddrs) == 0 {
 			return errors.New("manager addr is not specified")
 		}
 
 		if p.Scheduler.Manager.RefreshInterval == 0 {
 			return errors.New("manager refreshInterval is not specified")
 		}
+		return nil
+	}
+	if len(p.Scheduler.NetAddrs) == 0 {
+		return errors.New("empty schedulers and config server is not specified")
 	}
-
 	return nil
 }
 
diff --git a/client/daemon/daemon.go b/client/daemon/daemon.go
index bb47b24d..3c1512df 100644
--- a/client/daemon/daemon.go
+++ b/client/daemon/daemon.go
@@ -161,7 +161,7 @@ func New(opt *config.DaemonOption, d dfpath.Dfpath) (Daemon, error) {
 		return nil, err
 	}
 
-	pieceManager, err := peer.NewPieceManager(storageManager,
+	pieceManager, err := peer.NewPieceManager(
 		opt.Download.PieceDownloadTimeout,
 		peer.WithLimiter(rate.NewLimiter(opt.Download.TotalRateLimit.Limit, int(opt.Download.TotalRateLimit.Limit))),
 		peer.WithCalculateDigest(opt.Download.CalculateDigest), peer.WithTransportOption(opt.Download.TransportOption),
diff --git a/client/daemon/peer/peerid_generator.go b/client/daemon/peer/peerid_generator.go
new file mode 100644
index 00000000..8c00cee1
--- /dev/null
+++ b/client/daemon/peer/peerid_generator.go
@@ -0,0 +1,51 @@
+/*
+ *     Copyright 2020 The Dragonfly Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package peer
+
+import "d7y.io/dragonfly/v2/pkg/idgen"
+
+const (
+	defaultPeerIDBufferSize = 1024
+)
+
+type IDGenerator interface {
+	PeerID() string
+}
+
+type peerIDGenerator struct {
+	ip string
+	ch chan string
+}
+
+func NewPeerIDGenerator(ip string) IDGenerator {
+	p := &peerIDGenerator{
+		ip: ip,
+		ch: make(chan string, defaultPeerIDBufferSize),
+	}
+	go p.run()
+	return p
+}
+
+func (p *peerIDGenerator) PeerID() string {
+	return <-p.ch
+}
+
+func (p *peerIDGenerator) run() {
+	for {
+		p.ch <- idgen.PeerID(p.ip)
+	}
+}
diff --git a/client/daemon/peer/peertask_conductor.go b/client/daemon/peer/peertask_conductor.go
index 89c4e2c0..fd52e057 100644
--- a/client/daemon/peer/peertask_conductor.go
+++ b/client/daemon/peer/peertask_conductor.go
@@ -26,7 +26,7 @@ import (
 	"time"
 
 	"github.com/pkg/errors"
-	"go.opentelemetry.io/otel/semconv"
+	semconv "go.opentelemetry.io/otel/semconv/v1.7.0"
 	"go.opentelemetry.io/otel/trace"
 	"go.uber.org/atomic"
 	"golang.org/x/time/rate"
@@ -382,20 +382,21 @@ func (pt *peerTaskConductor) cancel(code base.Code, reason string) {
 }
 
 func (pt *peerTaskConductor) backSource() {
-	backSourceCtx, backSourceSpan := tracer.Start(pt.ctx, config.SpanBackSource)
-	defer backSourceSpan.End()
+	ctx, span := tracer.Start(pt.ctx, config.SpanBackSource)
 	pt.contentLength.Store(-1)
-	err := pt.pieceManager.DownloadSource(backSourceCtx, pt, pt.request)
+	err := pt.pieceManager.DownloadSource(ctx, pt, pt.request)
 	if err != nil {
 		pt.Errorf("download from source error: %s", err)
-		backSourceSpan.SetAttributes(config.AttributePeerTaskSuccess.Bool(false))
-		backSourceSpan.RecordError(err)
+		span.SetAttributes(config.AttributePeerTaskSuccess.Bool(false))
+		span.RecordError(err)
 		pt.cancel(base.Code_ClientError, err.Error())
+		span.End()
 		return
 	}
 	pt.Done()
 	pt.Infof("download from source ok")
-	backSourceSpan.SetAttributes(config.AttributePeerTaskSuccess.Bool(true))
+	span.SetAttributes(config.AttributePeerTaskSuccess.Bool(true))
+	span.End()
 	return
 }
 
@@ -675,6 +676,7 @@ func (pt *peerTaskConductor) pullSinglePiece() {
 		pt.Infof("single piece download success")
 	} else {
 		// fallback to download from other peers
+		span.RecordError(err)
 		span.SetAttributes(config.AttributePieceSuccess.Bool(false))
 		span.End()
 
@@ -1075,6 +1077,7 @@ func (pt *peerTaskConductor) reportSuccessResult(request *DownloadPieceRequest,
 		})
 	if err != nil {
 		pt.Errorf("report piece task error: %v", err)
+		span.RecordError(err)
 	}
 
 	span.End()
diff --git a/client/daemon/peer/peertask_reuse.go b/client/daemon/peer/peertask_reuse.go
index 330f77b9..2b4267a7 100644
--- a/client/daemon/peer/peertask_reuse.go
+++ b/client/daemon/peer/peertask_reuse.go
@@ -24,7 +24,7 @@ import (
 	"time"
 
 	"github.com/go-http-utils/headers"
-	"go.opentelemetry.io/otel/semconv"
+	semconv "go.opentelemetry.io/otel/semconv/v1.7.0"
 	"go.opentelemetry.io/otel/trace"
 
 	"d7y.io/dragonfly/v2/client/clientutil"
diff --git a/client/daemon/peer/piece_downloader.go b/client/daemon/peer/piece_downloader.go
index dd2d1b1e..c7c07b0c 100644
--- a/client/daemon/peer/piece_downloader.go
+++ b/client/daemon/peer/piece_downloader.go
@@ -135,16 +135,27 @@ func WithTransport(rt http.RoundTripper) func(*pieceDownloader) error {
 }
 
 func (p *pieceDownloader) DownloadPiece(ctx context.Context, req *DownloadPieceRequest) (io.Reader, io.Closer, error) {
-	resp, err := p.httpClient.Do(buildDownloadPieceHTTPRequest(ctx, req))
+	httpRequest := buildDownloadPieceHTTPRequest(ctx, req)
+	resp, err := p.httpClient.Do(httpRequest)
 	if err != nil {
 		logger.Errorf("task id: %s, piece num: %d, dst: %s, download piece failed: %s",
 			req.TaskID, req.piece.PieceNum, req.DstAddr, err)
-		return nil, nil, &pieceDownloadError{err: err, connectionError: true}
+		return nil, nil, &pieceDownloadError{
+			target:          httpRequest.URL.String(),
+			err:             err,
+			connectionError: true,
+		}
 	}
 	if resp.StatusCode > 299 {
 		_, _ = io.Copy(io.Discard, resp.Body)
 		_ = resp.Body.Close()
-		return nil, nil, &pieceDownloadError{err: err, connectionError: false, status: resp.Status, statusCode: resp.StatusCode}
+		return nil, nil, &pieceDownloadError{
+			target:          httpRequest.URL.String(),
+			err:             err,
+			connectionError: false,
+			status:          resp.Status,
+			statusCode:      resp.StatusCode,
+		}
 	}
 	reader, closer := resp.Body.(io.Reader), resp.Body.(io.Closer)
 	if req.CalcDigest {
diff --git a/client/daemon/peer/piece_manager.go b/client/daemon/peer/piece_manager.go
index d8e8ac42..60876fa1 100644
--- a/client/daemon/peer/piece_manager.go
+++ b/client/daemon/peer/piece_manager.go
@@ -53,7 +53,7 @@ type pieceManager struct {
 
 var _ PieceManager = (*pieceManager)(nil)
 
-func NewPieceManager(s storage.TaskStorageDriver, pieceDownloadTimeout time.Duration, opts ...func(*pieceManager)) (PieceManager, error) {
+func NewPieceManager(pieceDownloadTimeout time.Duration, opts ...func(*pieceManager)) (PieceManager, error) {
 	pm := &pieceManager{
 		computePieceSize: util.ComputePieceSize,
 		calculateDigest:  true,
@@ -253,17 +253,22 @@ func (pm *pieceManager) DownloadSource(ctx context.Context, pt Task, request *sc
 	}
 	log := pt.Log()
 	log.Infof("start to download from source")
-	contentLengthRequest, err := source.NewRequestWithContext(ctx, request.Url, request.UrlMeta.Header)
+
+	// 1. download pieces from source
+	downloadRequest, err := source.NewRequestWithContext(ctx, request.Url, request.UrlMeta.Header)
 	if err != nil {
 		return err
 	}
-	contentLength, err := source.GetContentLength(contentLengthRequest)
+	response, err := source.Download(downloadRequest)
+	// TODO update expire info
 	if err != nil {
-		log.Warnf("get content length error: %s for %s", err, request.Url)
+		return err
 	}
+	contentLength := response.ContentLength
 	if contentLength < 0 {
 		log.Warnf("can not get content length for %s", request.Url)
 	} else {
+		log.Debugf("back source content length: %d", contentLength)
 		err = pt.GetStorage().UpdateTask(ctx,
 			&storage.UpdateTaskRequest{
 				PeerTaskMetadata: storage.PeerTaskMetadata{
@@ -276,17 +281,6 @@ func (pm *pieceManager) DownloadSource(ctx context.Context, pt Task, request *sc
 			return err
 		}
 	}
-	log.Debugf("get content length: %d", contentLength)
-	// 1. download piece from source
-	downloadRequest, err := source.NewRequestWithContext(ctx, request.Url, request.UrlMeta.Header)
-	if err != nil {
-		return err
-	}
-	response, err := source.Download(downloadRequest)
-	// TODO update expire info
-	if err != nil {
-		return err
-	}
 	defer response.Body.Close()
 	reader := response.Body.(io.Reader)
 
diff --git a/client/daemon/proxy/proxy.go b/client/daemon/proxy/proxy.go
index 7d80467d..885d3e5b 100644
--- a/client/daemon/proxy/proxy.go
+++ b/client/daemon/proxy/proxy.go
@@ -34,7 +34,7 @@ import (
 	"github.com/pkg/errors"
 	"go.opentelemetry.io/otel"
 	"go.opentelemetry.io/otel/propagation"
-	"go.opentelemetry.io/otel/semconv"
+	semconv "go.opentelemetry.io/otel/semconv/v1.7.0"
 	"go.opentelemetry.io/otel/trace"
 	"golang.org/x/sync/semaphore"
 
@@ -79,6 +79,9 @@ type Proxy struct {
 	// directHandler are used to handle non-proxy requests
 	directHandler http.Handler
 
+	// transport is used to handle http proxy requests
+	transport http.RoundTripper
+
 	// peerTaskManager is the peer task manager
 	peerTaskManager peer.TaskManager
 
@@ -101,6 +104,8 @@ type Proxy struct {
 
 	// dumpHTTPContent indicates to dump http request header and response header
 	dumpHTTPContent bool
+
+	peerIDGenerator peer.IDGenerator
 }
 
 // Option is a functional option for configuring the proxy
@@ -114,6 +119,14 @@ func WithPeerHost(peerHost *scheduler.PeerHost) Option {
 	}
 }
 
+// WithPeerIDGenerator sets the *transport.PeerIDGenerator
+func WithPeerIDGenerator(peerIDGenerator peer.IDGenerator) Option {
+	return func(p *Proxy) *Proxy {
+		p.peerIDGenerator = peerIDGenerator
+		return p
+	}
+}
+
 // WithPeerTaskManager sets the peer.PeerTaskManager
 func WithPeerTaskManager(peerTaskManager peer.TaskManager) Option {
 	return func(p *Proxy) *Proxy {
@@ -230,6 +243,9 @@ func NewProxyWithOptions(options ...Option) (*Proxy, error) {
 		opt(proxy)
 	}
 
+	if proxy.transport == nil {
+		proxy.transport = proxy.newTransport(nil)
+	}
 	return proxy, nil
 }
 
@@ -246,9 +262,7 @@ func (proxy *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	span.SetAttributes(semconv.HTTPHostKey.String(r.Host))
 	span.SetAttributes(semconv.HTTPURLKey.String(r.URL.String()))
 	span.SetAttributes(semconv.HTTPMethodKey.String(r.Method))
-	defer func() {
-		span.End()
-	}()
+	defer span.End()
 
 	// update ctx to transfer trace id
 	r = r.WithContext(ctx)
@@ -258,6 +272,7 @@ func (proxy *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 		user, pass, ok := proxyBasicAuth(r)
 		if !ok {
 			status := http.StatusProxyAuthRequired
+			span.SetAttributes(semconv.HTTPStatusCodeKey.Int(status))
 			http.Error(w, http.StatusText(status), status)
 			logger.Debugf("empty auth info: %s, url：%s", r.Host, r.URL.String())
 			return
@@ -265,6 +280,7 @@ func (proxy *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 		// TODO dynamic auth config via manager
 		if user != proxy.basicAuth.Username || pass != proxy.basicAuth.Password {
 			status := http.StatusUnauthorized
+			span.SetAttributes(semconv.HTTPStatusCodeKey.Int(status))
 			http.Error(w, http.StatusText(status), status)
 			logger.Debugf("mismatch auth info (%s/%s): %s, url：%s", user, pass, r.Host, r.URL.String())
 			return
@@ -277,6 +293,7 @@ func (proxy *Proxy) ServeHTTP(w http.ResponseWriter, r *http.Request) {
 	// check whiteList
 	if !directRequest && !proxy.checkWhiteList(r) {
 		status := http.StatusUnauthorized
+		span.SetAttributes(semconv.HTTPStatusCodeKey.Int(status))
 		http.Error(w, http.StatusText(status), status)
 		logger.Debugf("not in whitelist: %s, url：%s", r.Host, r.URL.String())
 		return
@@ -334,9 +351,9 @@ func parseBasicAuth(auth string) (username, password string, ok bool) {
 }
 
 func (proxy *Proxy) handleHTTP(span trace.Span, w http.ResponseWriter, req *http.Request) {
-	// FIXME did not need create a transport per request
-	resp, err := proxy.newTransport(nil).RoundTrip(req)
+	resp, err := proxy.transport.RoundTrip(req)
 	if err != nil {
+		span.RecordError(err)
 		http.Error(w, err.Error(), http.StatusServiceUnavailable)
 		return
 	}
@@ -458,7 +475,7 @@ func (proxy *Proxy) handleHTTPS(w http.ResponseWriter, r *http.Request) {
 
 func (proxy *Proxy) newTransport(tlsConfig *tls.Config) http.RoundTripper {
 	rt, _ := transport.New(
-		transport.WithPeerHost(proxy.peerHost),
+		transport.WithPeerIDGenerator(proxy.peerIDGenerator),
 		transport.WithPeerTaskManager(proxy.peerTaskManager),
 		transport.WithTLS(tlsConfig),
 		transport.WithCondition(proxy.shouldUseDragonfly),
@@ -472,7 +489,7 @@ func (proxy *Proxy) newTransport(tlsConfig *tls.Config) http.RoundTripper {
 func (proxy *Proxy) mirrorRegistry(w http.ResponseWriter, r *http.Request) {
 	reverseProxy := newReverseProxy(proxy.registry)
 	t, err := transport.New(
-		transport.WithPeerHost(proxy.peerHost),
+		transport.WithPeerIDGenerator(proxy.peerIDGenerator),
 		transport.WithPeerTaskManager(proxy.peerTaskManager),
 		transport.WithTLS(proxy.registry.TLSConfig()),
 		transport.WithCondition(proxy.shouldUseDragonflyForMirror),
diff --git a/client/daemon/proxy/proxy_manager.go b/client/daemon/proxy/proxy_manager.go
index 5c9cba65..8731515f 100644
--- a/client/daemon/proxy/proxy_manager.go
+++ b/client/daemon/proxy/proxy_manager.go
@@ -64,6 +64,7 @@ func NewProxyManager(peerHost *scheduler.PeerHost, peerTaskManager peer.TaskMana
 
 	options := []Option{
 		WithPeerHost(peerHost),
+		WithPeerIDGenerator(peer.NewPeerIDGenerator(peerHost.Ip)),
 		WithPeerTaskManager(peerTaskManager),
 		WithRules(proxies),
 		WithWhiteList(whiteList),
diff --git a/client/daemon/storage/local_storage.go b/client/daemon/storage/local_storage.go
index 58d13bf3..c8a119da 100644
--- a/client/daemon/storage/local_storage.go
+++ b/client/daemon/storage/local_storage.go
@@ -294,7 +294,12 @@ func (t *localTaskStore) ReadAllPieces(ctx context.Context, req *ReadAllPiecesRe
 	}
 
 	if req.Range == nil {
-		return file, nil
+		// by jim: for some corner case, avoid the io.Copy call superfluous sendfile syscall
+		// then increase network latency
+		return &limitedReadFile{
+			reader: io.LimitReader(file, t.ContentLength),
+			closer: file,
+		}, nil
 	}
 
 	if _, err = file.Seek(req.Range.Start, io.SeekStart); err != nil {
diff --git a/client/daemon/transport/transport.go b/client/daemon/transport/transport.go
index 2cbfd923..771a1dd7 100644
--- a/client/daemon/transport/transport.go
+++ b/client/daemon/transport/transport.go
@@ -39,9 +39,7 @@ import (
 	"d7y.io/dragonfly/v2/client/daemon/metrics"
 	"d7y.io/dragonfly/v2/client/daemon/peer"
 	logger "d7y.io/dragonfly/v2/internal/dflog"
-	"d7y.io/dragonfly/v2/pkg/idgen"
 	"d7y.io/dragonfly/v2/pkg/rpc/base"
-	"d7y.io/dragonfly/v2/pkg/rpc/scheduler"
 	"d7y.io/dragonfly/v2/pkg/util/net/httputils"
 )
 
@@ -66,9 +64,6 @@ type transport struct {
 	// peerTaskManager is the peer task manager
 	peerTaskManager peer.TaskManager
 
-	// peerHost is the peer host info
-	peerHost *scheduler.PeerHost
-
 	// defaultFilter is used when http request without X-Dragonfly-Filter Header
 	defaultFilter string
 
@@ -77,15 +72,17 @@ type transport struct {
 
 	// dumpHTTPContent indicates to dump http request header and response header
 	dumpHTTPContent bool
+
+	peerIDGenerator peer.IDGenerator
 }
 
 // Option is functional config for transport.
 type Option func(rt *transport) *transport
 
-// WithPeerHost sets the peerHost for transport
-func WithPeerHost(peerHost *scheduler.PeerHost) Option {
+// WithPeerIDGenerator sets the peerIDGenerator for transport
+func WithPeerIDGenerator(peerIDGenerator peer.IDGenerator) Option {
 	return func(rt *transport) *transport {
-		rt.peerHost = peerHost
+		rt.peerIDGenerator = peerIDGenerator
 		return rt
 	}
 }
@@ -200,7 +197,7 @@ func NeedUseDragonfly(req *http.Request) bool {
 // the ctx has span info from transport, did not use the ctx from request
 func (rt *transport) download(ctx context.Context, req *http.Request) (*http.Response, error) {
 	url := req.URL.String()
-	peerID := idgen.PeerID(rt.peerHost.Ip)
+	peerID := rt.peerIDGenerator.PeerID()
 	log := logger.With("peer", peerID, "component", "transport")
 	log.Infof("start download with url: %s", url)
 
diff --git a/cmd/dependency/dependency.go b/cmd/dependency/dependency.go
index 31d24f32..87ea74b3 100644
--- a/cmd/dependency/dependency.go
+++ b/cmd/dependency/dependency.go
@@ -35,11 +35,11 @@ import (
 	"github.com/spf13/cobra"
 	"github.com/spf13/viper"
 	"go.opentelemetry.io/otel"
-	"go.opentelemetry.io/otel/exporters/trace/jaeger"
+	"go.opentelemetry.io/otel/exporters/jaeger"
 	"go.opentelemetry.io/otel/propagation"
 	"go.opentelemetry.io/otel/sdk/resource"
 	sdktrace "go.opentelemetry.io/otel/sdk/trace"
-	"go.opentelemetry.io/otel/semconv"
+	semconv "go.opentelemetry.io/otel/semconv/v1.7.0"
 	"go.uber.org/zap/zapcore"
 	"gopkg.in/yaml.v3"
 
@@ -221,7 +221,7 @@ func initDecoderConfig(dc *mapstructure.DecoderConfig) {
 
 // initTracer creates a new trace provider instance and registers it as global trace provider.
 func initJaegerTracer(otelOption base.TelemetryOption) (func(), error) {
-	exp, err := jaeger.NewRawExporter(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(otelOption.Jaeger)))
+	exp, err := jaeger.New(jaeger.WithCollectorEndpoint(jaeger.WithEndpoint(otelOption.Jaeger)))
 	if err != nil {
 		return nil, err
 	}
@@ -232,6 +232,7 @@ func initJaegerTracer(otelOption base.TelemetryOption) (func(), error) {
 		sdktrace.WithSampler(sdktrace.AlwaysSample()),
 		// Record information about this application in an Resource.
 		sdktrace.WithResource(resource.NewWithAttributes(
+			semconv.SchemaURL,
 			semconv.ServiceNameKey.String(otelOption.ServiceName),
 			semconv.ServiceInstanceIDKey.String(fmt.Sprintf("%s|%s", hostutils.FQDNHostname, iputils.IPv4)),
 			semconv.ServiceNamespaceKey.String("dragonfly"),
diff --git a/deploy/docker-compose/docker-compose.yaml b/deploy/docker-compose/docker-compose.yaml
index e08868cd..d0dd306b 100644
--- a/deploy/docker-compose/docker-compose.yaml
+++ b/deploy/docker-compose/docker-compose.yaml
@@ -28,7 +28,7 @@ services:
       retries: 30
 
   manager:
-    image: dragonflyoss/manager:v2.0.2-rc.9
+    image: dragonflyoss/manager:v2.0.2-rc.20
     container_name: manager
     network_mode: host
     depends_on:
@@ -45,7 +45,7 @@ services:
       retries: 30
 
   dfdaemon:
-    image: dragonflyoss/dfdaemon:v2.0.2-rc.9
+    image: dragonflyoss/dfdaemon:v2.0.2-rc.20
     depends_on:
       - scheduler
       - cdn
@@ -62,7 +62,7 @@ services:
       - ./config/dfget.yaml:/etc/dragonfly/dfget.yaml
 
   scheduler:
-    image: dragonflyoss/scheduler:v2.0.2-rc.9
+    image: dragonflyoss/scheduler:v2.0.2-rc.20
     depends_on:
       - cdn
       - manager
@@ -77,10 +77,9 @@ services:
     volumes:
       - /tmp/log/dragonfly:/var/log/dragonfly
       - ./config/scheduler.yaml:/etc/dragonfly/scheduler.yaml
-      - ./config/cdn.json:/opt/dragonfly/scheduler-cdn/cdn.json
 
   cdn:
-    image: dragonflyoss/cdn:v2.0.2-rc.9
+    image: dragonflyoss/cdn:v2.0.2-rc.20
     container_name: cdn
     network_mode: host
     restart: always
diff --git a/deploy/docker-compose/run.sh b/deploy/docker-compose/run.sh
index e0f5eee5..285726af 100755
--- a/deploy/docker-compose/run.sh
+++ b/deploy/docker-compose/run.sh
@@ -11,22 +11,17 @@ cd $DIR
 prepare(){
     mkdir -p config
 
-    cat template/cdn.template.json > config/cdn.json
     cat template/cdn.template.yaml > config/cdn.yaml
     cat template/dfget.template.yaml > config/dfget.yaml
     cat template/scheduler.template.yaml > config/scheduler.yaml
     cat template/manager.template.yaml > config/manager.yaml
 
     ip=${IP:-$(hostname -i)}
-    hostname=$(hostname)
 
-    sed -i "s,__IP__,$ip," config/cdn.json
     sed -i "s,__IP__,$ip," config/dfget.yaml
     sed -i "s,__IP__,$ip," config/cdn.yaml
     sed -i "s,__IP__,$ip," config/scheduler.yaml
     sed -i "s,__IP__,$ip," config/manager.yaml
-
-    sed -i "s,__HOSTNAME__,$hostname," config/cdn.json
 }
 
 run_container(){
@@ -36,6 +31,12 @@ run_container(){
     echo try to clean old containers
     ${RUNTIME} rm -f dragonfly-cdn dragonfly-scheduler dragonfly-dfdaemon
 
+    printf "create dragonfly-manager "
+    ${RUNTIME} run -d --name dragonfly-cdn --net=host \
+        -v /tmp/log/dragonfly:/var/log/dragonfly \
+        -v ${DIR}/config/manager.yaml:/etc/dragonfly/manager.yaml \
+        ${REPO}/manager:${TAG}
+
     printf "create dragonfly-cdn "
     ${RUNTIME} run -d --name dragonfly-cdn --net=host \
         -v /tmp/log/dragonfly:/var/log/dragonfly \
@@ -47,7 +48,6 @@ run_container(){
     ${RUNTIME} run -d --name dragonfly-scheduler --net=host \
         -v /tmp/log/dragonfly:/var/log/dragonfly \
         -v ${DIR}/config/scheduler.yaml:/etc/dragonfly/scheduler.yaml \
-        -v ${DIR}/config/cdn.json:/opt/dragonfly/scheduler-cdn/cdn.json \
         ${REPO}/scheduler:${TAG}
 
     printf "create dragonfly-dfdaemon "
diff --git a/deploy/docker-compose/template/cdn.template.json b/deploy/docker-compose/template/cdn.template.json
deleted file mode 100644
index b5bf7164..00000000
--- a/deploy/docker-compose/template/cdn.template.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
-    "host_name": "__HOSTNAME__",
-    "ip": "__IP__",
-    "port": 8003,
-    "download_port": 8001,
-    "status": "active"
-}
\ No newline at end of file
diff --git a/deploy/helm-charts b/deploy/helm-charts
index 00a2ec43..b78964e1 160000
--- a/deploy/helm-charts
+++ b/deploy/helm-charts
@@ -1,1 +1,1 @@
-Subproject commit 00a2ec437075a00dc752358064f4f6fe6f28c382
+Subproject commit b78964e1e625d31d5cbb6810da9012f6b37c95cc
diff --git a/docs/en/api-reference/api-reference.md b/docs/en/api-reference/api-reference.md
index 625f59ea..d8541fe3 100644
--- a/docs/en/api-reference/api-reference.md
+++ b/docs/en/api-reference/api-reference.md
@@ -3284,6 +3284,50 @@ Get User by id
 * User
 
 
+<a name="api-v1-users-id-patch"></a>
+### Update User
+```
+PATCH /api/v1/users/{id}
+```
+
+
+#### Description
+Update by json config
+
+
+#### Parameters
+
+|Type|Name|Description|Schema|
+|---|---|---|---|
+|**Path**|**id**  <br>*required*|id|string|
+|**Body**|**User**  <br>*required*|User|[types.UpdateUserRequest](#types-updateuserrequest)|
+
+
+#### Responses
+
+|HTTP Code|Description|Schema|
+|---|---|---|
+|**200**|OK|[model.User](#model-user)|
+|**400**||No Content|
+|**404**||No Content|
+|**500**||No Content|
+
+
+#### Consumes
+
+* `application/json`
+
+
+#### Produces
+
+* `application/json`
+
+
+#### Tags
+
+* User
+
+
 <a name="api-v1-users-id-reset_password-post"></a>
 ### Reset Password For User
 ```
@@ -3651,7 +3695,7 @@ delete role by uri config
 
 |Name|Schema|
 |---|---|
-|**action**  <br>*required*|string|
+|**action**  <br>*required*|enum (read, *)|
 |**object**  <br>*required*|string|
 
 
@@ -3660,17 +3704,17 @@ delete role by uri config
 
 |Name|Schema|
 |---|---|
-|**action**  <br>*required*|string|
+|**action**  <br>*required*|enum (read, *)|
 |**object**  <br>*required*|string|
 
 
 <a name="types-cdnclusterconfig"></a>
 ### types.CDNClusterConfig
 
-|Name|Schema|
-|---|---|
-|**load_limit**  <br>*optional*|integer|
-|**net_topology**  <br>*optional*|string|
+|Name|Description|Schema|
+|---|---|---|
+|**load_limit**  <br>*optional*|**Minimum value** : `1`  <br>**Maximum value** : `10000`|integer|
+|**net_topology**  <br>*optional*||string|
 
 
 <a name="types-createapplicationrequest"></a>
@@ -3681,7 +3725,7 @@ delete role by uri config
 |**bio**  <br>*optional*|string|
 |**download_rate_limit**  <br>*optional*|integer|
 |**name**  <br>*required*|string|
-|**state**  <br>*optional*|string|
+|**state**  <br>*optional*|enum (enable, disable)|
 |**url**  <br>*optional*|string|
 |**user_id**  <br>*required*|integer|
 
@@ -3744,7 +3788,7 @@ delete role by uri config
 |**bio**  <br>*optional*|string|
 |**client_id**  <br>*required*|string|
 |**client_secret**  <br>*required*|string|
-|**name**  <br>*required*|string|
+|**name**  <br>*required*|enum (github, google)|
 |**redirect_url**  <br>*optional*|string|
 
 
@@ -3813,7 +3857,7 @@ delete role by uri config
 |---|---|
 |**filter**  <br>*optional*|string|
 |**headers**  <br>*optional*|< string, string > map|
-|**type**  <br>*required*|string|
+|**type**  <br>*required*|enum (image, file)|
 |**url**  <br>*required*|string|
 
 
@@ -3830,7 +3874,7 @@ delete role by uri config
 
 |Name|Schema|
 |---|---|
-|**action**  <br>*required*|string|
+|**action**  <br>*required*|enum (read, *)|
 |**object**  <br>*required*|string|
 
 
@@ -3848,23 +3892,27 @@ delete role by uri config
 <a name="types-resetpasswordrequest"></a>
 ### types.ResetPasswordRequest
 
-|Name|Schema|
-|---|---|
-|**new_password**  <br>*required*|string|
-|**old_password**  <br>*required*|string|
+|Name|Description|Schema|
+|---|---|---|
+|**new_password**  <br>*required*|**Length** : `8 - 20`|string|
+|**old_password**  <br>*required*|**Length** : `8 - 20`|string|
 
 
 <a name="types-schedulerclusterclientconfig"></a>
 ### types.SchedulerClusterClientConfig
 
-|Name|Schema|
-|---|---|
-|**load_limit**  <br>*optional*|integer|
+|Name|Description|Schema|
+|---|---|---|
+|**load_limit**  <br>*optional*|**Minimum value** : `1`  <br>**Maximum value** : `10000`|integer|
+|**parallel_count**  <br>*optional*|**Minimum value** : `1`  <br>**Maximum value** : `50`|integer|
 
 
 <a name="types-schedulerclusterconfig"></a>
 ### types.SchedulerClusterConfig
-*Type* : object
+
+|Name|Description|Schema|
+|---|---|---|
+|**filter_parent_limit**  <br>*optional*|**Minimum value** : `1`  <br>**Maximum value** : `100`|integer|
 
 
 <a name="types-schedulerclusterscopes"></a>
@@ -3880,15 +3928,15 @@ delete role by uri config
 <a name="types-signuprequest"></a>
 ### types.SignUpRequest
 
-|Name|Schema|
-|---|---|
-|**avatar**  <br>*optional*|string|
-|**bio**  <br>*optional*|string|
-|**email**  <br>*required*|string|
-|**location**  <br>*optional*|string|
-|**name**  <br>*required*|string|
-|**password**  <br>*required*|string|
-|**phone**  <br>*optional*|string|
+|Name|Description|Schema|
+|---|---|---|
+|**avatar**  <br>*optional*||string|
+|**bio**  <br>*optional*||string|
+|**email**  <br>*required*||string|
+|**location**  <br>*optional*||string|
+|**name**  <br>*required*|**Length** : `3 - 10`|string|
+|**password**  <br>*required*|**Length** : `8 - 20`|string|
+|**phone**  <br>*optional*||string|
 
 
 <a name="types-updateapplicationrequest"></a>
@@ -3899,7 +3947,7 @@ delete role by uri config
 |**bio**  <br>*optional*|string|
 |**download_rate_limit**  <br>*optional*|integer|
 |**name**  <br>*optional*|string|
-|**state**  <br>*optional*|string|
+|**state**  <br>*optional*|enum (enable, disable)|
 |**url**  <br>*optional*|string|
 |**user_id**  <br>*required*|integer|
 
@@ -3956,7 +4004,7 @@ delete role by uri config
 |**bio**  <br>*optional*|string|
 |**client_id**  <br>*optional*|string|
 |**client_secret**  <br>*optional*|string|
-|**name**  <br>*optional*|string|
+|**name**  <br>*optional*|enum (github, google)|
 |**redirect_url**  <br>*optional*|string|
 
 
@@ -4009,6 +4057,18 @@ delete role by uri config
 |**proxy_domain**  <br>*optional*|string|
 
 
+<a name="types-updateuserrequest"></a>
+### types.UpdateUserRequest
+
+|Name|Schema|
+|---|---|
+|**avatar**  <br>*optional*|string|
+|**bio**  <br>*optional*|string|
+|**email**  <br>*optional*|string|
+|**location**  <br>*optional*|string|
+|**phone**  <br>*optional*|string|
+
+
 
 
 
diff --git a/docs/en/deployment/configuration/scheduler.yaml b/docs/en/deployment/configuration/scheduler.yaml
index 61ebdf47..897014f8 100644
--- a/docs/en/deployment/configuration/scheduler.yaml
+++ b/docs/en/deployment/configuration/scheduler.yaml
@@ -31,9 +31,9 @@ scheduler:
   # retry scheduling back-to-source limit times
   retryBackSourceLimit: 5
   # retry scheduling limit times
-  retryLimit: 20
+  retryLimit: 10
   # retry scheduling interval
-  retryInterval: 200ms
+  retryInterval: 50ms
   # gc metadata configuration
   gc:
     # peerGCInterval is peer's gc interval
diff --git a/docs/zh-CN/api-reference/api-reference.md b/docs/zh-CN/api-reference/api-reference.md
index 035e03cf..b2a3aa78 100644
--- a/docs/zh-CN/api-reference/api-reference.md
+++ b/docs/zh-CN/api-reference/api-reference.md
@@ -3284,6 +3284,50 @@ Get User by id
 * User
 
 
+<a name="api-v1-users-id-patch"></a>
+### Update User
+```
+PATCH /api/v1/users/{id}
+```
+
+
+#### 说明
+Update by json config
+
+
+#### 参数
+
+|类型|名称|说明|类型|
+|---|---|---|---|
+|**Path**|**id**  <br>*必填*|id|string|
+|**Body**|**User**  <br>*必填*|User|[types.UpdateUserRequest](#types-updateuserrequest)|
+
+
+#### 响应
+
+|HTTP代码|说明|类型|
+|---|---|---|
+|**200**|OK|[model.User](#model-user)|
+|**400**||无内容|
+|**404**||无内容|
+|**500**||无内容|
+
+
+#### 消耗
+
+* `application/json`
+
+
+#### 生成
+
+* `application/json`
+
+
+#### 标签
+
+* User
+
+
 <a name="api-v1-users-id-reset_password-post"></a>
 ### Reset Password For User
 ```
@@ -3651,7 +3695,7 @@ delete role by uri config
 
 |名称|类型|
 |---|---|
-|**action**  <br>*必填*|string|
+|**action**  <br>*必填*|enum (read, *)|
 |**object**  <br>*必填*|string|
 
 
@@ -3660,17 +3704,17 @@ delete role by uri config
 
 |名称|类型|
 |---|---|
-|**action**  <br>*必填*|string|
+|**action**  <br>*必填*|enum (read, *)|
 |**object**  <br>*必填*|string|
 
 
 <a name="types-cdnclusterconfig"></a>
 ### types.CDNClusterConfig
 
-|名称|类型|
-|---|---|
-|**load_limit**  <br>*可选*|integer|
-|**net_topology**  <br>*可选*|string|
+|名称|说明|类型|
+|---|---|---|
+|**load_limit**  <br>*可选*|**最小值** : `1`  <br>**最大值** : `10000`|integer|
+|**net_topology**  <br>*可选*||string|
 
 
 <a name="types-createapplicationrequest"></a>
@@ -3681,7 +3725,7 @@ delete role by uri config
 |**bio**  <br>*可选*|string|
 |**download_rate_limit**  <br>*可选*|integer|
 |**name**  <br>*必填*|string|
-|**state**  <br>*可选*|string|
+|**state**  <br>*可选*|enum (enable, disable)|
 |**url**  <br>*可选*|string|
 |**user_id**  <br>*必填*|integer|
 
@@ -3744,7 +3788,7 @@ delete role by uri config
 |**bio**  <br>*可选*|string|
 |**client_id**  <br>*必填*|string|
 |**client_secret**  <br>*必填*|string|
-|**name**  <br>*必填*|string|
+|**name**  <br>*必填*|enum (github, google)|
 |**redirect_url**  <br>*可选*|string|
 
 
@@ -3813,7 +3857,7 @@ delete role by uri config
 |---|---|
 |**filter**  <br>*可选*|string|
 |**headers**  <br>*可选*|< string, string > map|
-|**type**  <br>*必填*|string|
+|**type**  <br>*必填*|enum (image, file)|
 |**url**  <br>*必填*|string|
 
 
@@ -3830,7 +3874,7 @@ delete role by uri config
 
 |名称|类型|
 |---|---|
-|**action**  <br>*必填*|string|
+|**action**  <br>*必填*|enum (read, *)|
 |**object**  <br>*必填*|string|
 
 
@@ -3848,23 +3892,27 @@ delete role by uri config
 <a name="types-resetpasswordrequest"></a>
 ### types.ResetPasswordRequest
 
-|名称|类型|
-|---|---|
-|**new_password**  <br>*必填*|string|
-|**old_password**  <br>*必填*|string|
+|名称|说明|类型|
+|---|---|---|
+|**new_password**  <br>*必填*|**长度** : `8 - 20`|string|
+|**old_password**  <br>*必填*|**长度** : `8 - 20`|string|
 
 
 <a name="types-schedulerclusterclientconfig"></a>
 ### types.SchedulerClusterClientConfig
 
-|名称|类型|
-|---|---|
-|**load_limit**  <br>*可选*|integer|
+|名称|说明|类型|
+|---|---|---|
+|**load_limit**  <br>*可选*|**最小值** : `1`  <br>**最大值** : `10000`|integer|
+|**parallel_count**  <br>*可选*|**最小值** : `1`  <br>**最大值** : `50`|integer|
 
 
 <a name="types-schedulerclusterconfig"></a>
 ### types.SchedulerClusterConfig
-*类型* : object
+
+|名称|说明|类型|
+|---|---|---|
+|**filter_parent_limit**  <br>*可选*|**最小值** : `1`  <br>**最大值** : `100`|integer|
 
 
 <a name="types-schedulerclusterscopes"></a>
@@ -3880,15 +3928,15 @@ delete role by uri config
 <a name="types-signuprequest"></a>
 ### types.SignUpRequest
 
-|名称|类型|
-|---|---|
-|**avatar**  <br>*可选*|string|
-|**bio**  <br>*可选*|string|
-|**email**  <br>*必填*|string|
-|**location**  <br>*可选*|string|
-|**name**  <br>*必填*|string|
-|**password**  <br>*必填*|string|
-|**phone**  <br>*可选*|string|
+|名称|说明|类型|
+|---|---|---|
+|**avatar**  <br>*可选*||string|
+|**bio**  <br>*可选*||string|
+|**email**  <br>*必填*||string|
+|**location**  <br>*可选*||string|
+|**name**  <br>*必填*|**长度** : `3 - 10`|string|
+|**password**  <br>*必填*|**长度** : `8 - 20`|string|
+|**phone**  <br>*可选*||string|
 
 
 <a name="types-updateapplicationrequest"></a>
@@ -3899,7 +3947,7 @@ delete role by uri config
 |**bio**  <br>*可选*|string|
 |**download_rate_limit**  <br>*可选*|integer|
 |**name**  <br>*可选*|string|
-|**state**  <br>*可选*|string|
+|**state**  <br>*可选*|enum (enable, disable)|
 |**url**  <br>*可选*|string|
 |**user_id**  <br>*必填*|integer|
 
@@ -3956,7 +4004,7 @@ delete role by uri config
 |**bio**  <br>*可选*|string|
 |**client_id**  <br>*可选*|string|
 |**client_secret**  <br>*可选*|string|
-|**name**  <br>*可选*|string|
+|**name**  <br>*可选*|enum (github, google)|
 |**redirect_url**  <br>*可选*|string|
 
 
@@ -4009,6 +4057,18 @@ delete role by uri config
 |**proxy_domain**  <br>*可选*|string|
 
 
+<a name="types-updateuserrequest"></a>
+### types.UpdateUserRequest
+
+|名称|类型|
+|---|---|
+|**avatar**  <br>*可选*|string|
+|**bio**  <br>*可选*|string|
+|**email**  <br>*可选*|string|
+|**location**  <br>*可选*|string|
+|**phone**  <br>*可选*|string|
+
+
 
 
 
diff --git a/docs/zh-CN/deployment/configuration/scheduler.yaml b/docs/zh-CN/deployment/configuration/scheduler.yaml
index a3301888..ed9b4e57 100644
--- a/docs/zh-CN/deployment/configuration/scheduler.yaml
+++ b/docs/zh-CN/deployment/configuration/scheduler.yaml
@@ -27,9 +27,9 @@ scheduler:
   # 调度回源重试次数限制
   retryBackSourceLimit: 5
   # 调度重试次数限制
-  retryLimit: 20
+  retryLimit: 10
   # 调度重试时间间隔
-  retryInterval: 200ms
+  retryInterval: 50ms
   # 数据回收策略
   gc:
     # peer 的回收间隔
diff --git a/docs/zh-CN/deployment/installation/executable-files/dfdaemon.md b/docs/zh-CN/deployment/installation/executable-files/dfdaemon.md
index 9ab54709..b0d68479 100644
--- a/docs/zh-CN/deployment/installation/executable-files/dfdaemon.md
+++ b/docs/zh-CN/deployment/installation/executable-files/dfdaemon.md
@@ -56,7 +56,7 @@
 ### 启动 dfdaemon
 
 ```sh
-dfget dfdaemon --options
+dfget daemon --options
 ```
 
 dfget 部署完成之后，运行以下命令以检查 **dfdaemon** 是否正在运行，以及 `65000`, `65001` 和 `65002` 端口是否可用。
diff --git a/go.mod b/go.mod
index 777ff633..0583cb78 100644
--- a/go.mod
+++ b/go.mod
@@ -6,7 +6,7 @@ require (
 	github.com/RichardKnop/machinery v1.10.6
 	github.com/Showmax/go-fqdn v1.0.0
 	github.com/VividCortex/mysqlerr v1.0.0
-	github.com/agiledragon/gomonkey/v2 v2.3.0
+	github.com/agiledragon/gomonkey/v2 v2.3.1
 	github.com/aliyun/aliyun-oss-go-sdk v2.1.6+incompatible
 	github.com/appleboy/gin-jwt/v2 v2.6.5-0.20210827121450-79689222c755
 	github.com/bits-and-blooms/bitset v1.2.1
@@ -23,7 +23,7 @@ require (
 	github.com/gin-gonic/gin v1.7.7
 	github.com/go-echarts/statsview v0.3.4
 	github.com/go-http-utils/headers v0.0.0-20181008091004-fed159eddc2a
-	github.com/go-playground/validator/v10 v10.9.0
+	github.com/go-playground/validator/v10 v10.10.1
 	github.com/go-redis/cache/v8 v8.4.1
 	github.com/go-redis/redis/v8 v8.10.0
 	github.com/go-sql-driver/mysql v1.5.0
@@ -31,7 +31,7 @@ require (
 	github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da
 	github.com/golang/mock v1.6.0
 	github.com/gomodule/redigo v2.0.0+incompatible
-	github.com/google/go-cmp v0.5.6
+	github.com/google/go-cmp v0.5.7
 	github.com/google/go-github v17.0.0+incompatible
 	github.com/google/uuid v1.2.0
 	github.com/gorilla/mux v1.8.0
@@ -57,22 +57,22 @@ require (
 	github.com/stretchr/testify v1.7.0
 	github.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2
 	github.com/swaggo/gin-swagger v1.3.1
-	github.com/swaggo/swag v1.7.1
-	go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.20.0
-	go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0
-	go.opentelemetry.io/otel v0.20.0
-	go.opentelemetry.io/otel/exporters/trace/jaeger v0.20.0
-	go.opentelemetry.io/otel/sdk v0.20.0
-	go.opentelemetry.io/otel/trace v0.20.0
+	github.com/swaggo/swag v1.8.0
+	go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.29.0
+	go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.29.0
+	go.opentelemetry.io/otel v1.4.1
+	go.opentelemetry.io/otel/exporters/jaeger v1.4.1
+	go.opentelemetry.io/otel/sdk v1.4.1
+	go.opentelemetry.io/otel/trace v1.4.1
 	go.uber.org/atomic v1.9.0
 	go.uber.org/zap v1.19.0
-	golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871
+	golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70
 	golang.org/x/oauth2 v0.0.0-20210819190943-2bc19b11175f
 	golang.org/x/sync v0.0.0-20210220032951-036812b2e83c
-	golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e
+	golang.org/x/sys v0.0.0-20220307203707-22a9840ba4d7
 	golang.org/x/time v0.0.0-20210723032227-1f47c861a9ac
 	google.golang.org/api v0.44.0
-	google.golang.org/grpc v1.40.0
+	google.golang.org/grpc v1.44.0
 	google.golang.org/protobuf v1.27.1
 	gopkg.in/natefinch/lumberjack.v2 v2.0.0
 	gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b
@@ -97,19 +97,20 @@ require (
 	github.com/beorn7/perks v1.0.1 // indirect
 	github.com/bradfitz/gomemcache v0.0.0-20190913173617-a41fca850d0b // indirect
 	github.com/cespare/xxhash/v2 v2.1.2 // indirect
-	github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
+	github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect
 	github.com/davecgh/go-spew v1.1.1 // indirect
 	github.com/denisenkom/go-mssqldb v0.0.0-20200428022330-06a60b6afbbc // indirect
 	github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
 	github.com/fsnotify/fsnotify v1.4.9 // indirect
 	github.com/gin-contrib/sse v0.1.0 // indirect
 	github.com/go-echarts/go-echarts/v2 v2.2.3 // indirect
-	github.com/go-logr/logr v1.2.0 // indirect
+	github.com/go-logr/logr v1.2.2 // indirect
+	github.com/go-logr/stdr v1.2.2 // indirect
 	github.com/go-ole/go-ole v1.2.6 // indirect
 	github.com/go-openapi/jsonpointer v0.19.5 // indirect
-	github.com/go-openapi/jsonreference v0.19.5 // indirect
-	github.com/go-openapi/spec v0.20.3 // indirect
-	github.com/go-openapi/swag v0.19.14 // indirect
+	github.com/go-openapi/jsonreference v0.19.6 // indirect
+	github.com/go-openapi/spec v0.20.4 // indirect
+	github.com/go-openapi/swag v0.21.1 // indirect
 	github.com/go-playground/locales v0.14.0 // indirect
 	github.com/go-playground/universal-translator v0.18.0 // indirect
 	github.com/go-redsync/redsync/v4 v4.0.4 // indirect
@@ -149,7 +150,7 @@ require (
 	github.com/klauspost/compress v1.13.1 // indirect
 	github.com/leodido/go-urn v1.2.1 // indirect
 	github.com/magiconair/properties v1.8.5 // indirect
-	github.com/mailru/easyjson v0.7.6 // indirect
+	github.com/mailru/easyjson v0.7.7 // indirect
 	github.com/mattn/go-isatty v0.0.14 // indirect
 	github.com/mattn/go-runewidth v0.0.13 // indirect
 	github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
@@ -174,7 +175,7 @@ require (
 	github.com/spf13/pflag v1.0.5 // indirect
 	github.com/streadway/amqp v1.0.0 // indirect
 	github.com/subosito/gotenv v1.2.0 // indirect
-	github.com/ugorji/go/codec v1.2.6 // indirect
+	github.com/ugorji/go/codec v1.2.7 // indirect
 	github.com/vmihailenco/bufpool v0.1.11 // indirect
 	github.com/vmihailenco/go-tinylfu v0.2.0 // indirect
 	github.com/vmihailenco/msgpack/v5 v5.1.0 // indirect
@@ -186,19 +187,19 @@ require (
 	github.com/yusufpapurcu/wmi v1.2.2 // indirect
 	go.mongodb.org/mongo-driver v1.7.2 // indirect
 	go.opencensus.io v0.23.0 // indirect
-	go.opentelemetry.io/contrib v0.20.0 // indirect
-	go.opentelemetry.io/otel/metric v0.20.0 // indirect
+	go.opentelemetry.io/otel/internal/metric v0.27.0 // indirect
+	go.opentelemetry.io/otel/metric v0.27.0 // indirect
 	go.uber.org/multierr v1.6.0 // indirect
 	golang.org/x/exp v0.0.0-20201221025956-e89b829e73ea // indirect
 	golang.org/x/lint v0.0.0-20210508222113-6edffad5e616 // indirect
-	golang.org/x/mod v0.4.2 // indirect
-	golang.org/x/net v0.0.0-20211209124913-491a49abca63 // indirect
-	golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b // indirect
+	golang.org/x/mod v0.5.1 // indirect
+	golang.org/x/net v0.0.0-20220225172249-27dd8689420f // indirect
+	golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 // indirect
 	golang.org/x/text v0.3.7 // indirect
-	golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff // indirect
+	golang.org/x/tools v0.1.9 // indirect
 	golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
 	google.golang.org/appengine v1.6.7 // indirect
-	google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2 // indirect
+	google.golang.org/genproto v0.0.0-20220308174144-ae0e22291548 // indirect
 	gopkg.in/ini.v1 v1.62.0 // indirect
 	gopkg.in/yaml.v2 v2.4.0 // indirect
 	gorm.io/driver/postgres v1.0.8 // indirect
diff --git a/go.sum b/go.sum
index 8ea1d930..f5ad301a 100644
--- a/go.sum
+++ b/go.sum
@@ -77,8 +77,8 @@ github.com/Showmax/go-fqdn v1.0.0 h1:0rG5IbmVliNT5O19Mfuvna9LL7zlHyRfsSvBPZmF9tM
 github.com/Showmax/go-fqdn v1.0.0/go.mod h1:SfrFBzmDCtCGrnHhoDjuvFnKsWjEQX/Q9ARZvOrJAko=
 github.com/VividCortex/mysqlerr v1.0.0 h1:5pZ2TZA+YnzPgzBfiUWGqWmKDVNBdrkf9g+DNe1Tiq8=
 github.com/VividCortex/mysqlerr v1.0.0/go.mod h1:xERx8E4tBhLvpjzdUyQiSfUxeMcATEQrflDAfXsqcAE=
-github.com/agiledragon/gomonkey/v2 v2.3.0 h1:olsJjnSDpvqWl4FHByeMUs/r54/az+gQitU3VeEbC98=
-github.com/agiledragon/gomonkey/v2 v2.3.0/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
+github.com/agiledragon/gomonkey/v2 v2.3.1 h1:k+UnUY0EMNYUFUAQVETGY9uUTxjMdnUkP0ARyJS1zzs=
+github.com/agiledragon/gomonkey/v2 v2.3.1/go.mod h1:ap1AmDzcVOAz1YpeJ3TCzIgstoaWLA6jbbgxfB4w2iY=
 github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
 github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
@@ -139,7 +139,11 @@ github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDk
 github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
 github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
 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-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
+github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
 github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I=
 github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
 github.com/colinmarc/hdfs/v2 v2.2.0 h1:4AaIlTq+/sWmeqYhI0dX8bD4YrMQM990tRjm636FkGM=
@@ -149,8 +153,9 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
 github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
 github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
 github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
-github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
 github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
+github.com/cpuguy83/go-md2man/v2 v2.0.1 h1:r/myEWzV9lfsM1tFLgDyu0atFtJ1fXn261LKYj/3DxU=
+github.com/cpuguy83/go-md2man/v2 v2.0.1/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o=
 github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
 github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
 github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
@@ -185,6 +190,7 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y
 github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
 github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
 github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
+github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
 github.com/envoyproxy/protoc-gen-validate v0.6.1 h1:4CF52PCseTFt4bE+Yk3dIpdVi7XWuPVMhPtm4FaIJPM=
 github.com/envoyproxy/protoc-gen-validate v0.6.1/go.mod h1:txg5va2Qkip90uYoSKH+nkAAmXrb2j3iq4FLwdrCbXQ=
@@ -211,7 +217,6 @@ github.com/gin-gonic/gin v1.3.0/go.mod h1:7cKuhb5qV2ggCFctp2fJQ+ErvciLZrIeoOSOm6
 github.com/gin-gonic/gin v1.5.0/go.mod h1:Nd6IXA8m5kNZdNEHMBd93KT+mdY3+bewLgRvmCsR2Do=
 github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
 github.com/gin-gonic/gin v1.7.0/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
-github.com/gin-gonic/gin v1.7.1/go.mod h1:jD2toBW3GZUr5UMcdrwQA10I7RuaFOl/SGeDjXkfUtY=
 github.com/gin-gonic/gin v1.7.7 h1:3DoBmSbJbZAWqXJC3SLjAPfutPJJRN1U5pALB7EeTTs=
 github.com/gin-gonic/gin v1.7.7/go.mod h1:axIBovoeJpVj8S3BwE0uPMTeReE4+AfFtqpqaZ1qq1U=
 github.com/go-echarts/go-echarts/v2 v2.2.3 h1:H8oPdUpzuiV2K8S4xYZa1JRNjP3U0h7HVqvhPrmCk1A=
@@ -231,8 +236,11 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V
 github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A=
 github.com/go-logr/logr v0.1.0/go.mod h1:ixOQHD9gLJUVQQ2ZOR7zLEifBX6tGkNJF4QyIY7sIas=
 github.com/go-logr/logr v0.2.0/go.mod h1:z6/tIYblkpsD+a4lm/fGIIU9mZ+XfAiaFtq7xTgseGU=
-github.com/go-logr/logr v1.2.0 h1:QK40JKJyMdUDz+h+xvCsru/bJhvG0UxvePV0ufL/AcE=
 github.com/go-logr/logr v1.2.0/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/logr v1.2.2 h1:ahHml/yUpnlb96Rp8HCvtYVPY8ZYpxq3g7UYchIYwbs=
+github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
+github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
+github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
 github.com/go-logr/zapr v1.2.0/go.mod h1:Qa4Bsj2Vb+FAVeAKsLD8RLQ+YRJB8YDmOAKxaBQf7Ro=
 github.com/go-ole/go-ole v1.2.6 h1:/Fpf6oFPoeFik9ty7siob0G6Ke8QvQEuVcuChpwXzpY=
 github.com/go-ole/go-ole v1.2.6/go.mod h1:pprOEPIfldk/42T2oK7lQ4v4JSDwmV0As9GaiUsvbm0=
@@ -243,15 +251,16 @@ github.com/go-openapi/jsonpointer v0.19.5/go.mod h1:Pl9vOtqEWErmShwVjC8pYs9cog34
 github.com/go-openapi/jsonreference v0.17.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
 github.com/go-openapi/jsonreference v0.19.0/go.mod h1:g4xxGn04lDIRh0GJb5QlpE3HfopLOL6uZrK/VgnsK9I=
 github.com/go-openapi/jsonreference v0.19.3/go.mod h1:rjx6GuL8TTa9VaixXglHmQmIL98+wF9xc8zWvFonSJ8=
-github.com/go-openapi/jsonreference v0.19.5 h1:1WJP/wi4OjB4iV8KVbH73rQaoialJrqv8gitZLxGLtM=
-github.com/go-openapi/jsonreference v0.19.5/go.mod h1:RdybgQwPxbL4UEjuAruzK1x3nE69AqPYEJeo/TWfEeg=
+github.com/go-openapi/jsonreference v0.19.6 h1:UBIxjkht+AWIgYzCDSv2GN+E/togfwXUJFRTWhl2Jjs=
+github.com/go-openapi/jsonreference v0.19.6/go.mod h1:diGHMEHg2IqXZGKxqyvWdfWU/aim5Dprw5bqpKkTvns=
 github.com/go-openapi/spec v0.19.0/go.mod h1:XkF/MOi14NmjsfZ8VtAKf8pIlbZzyoTvZsdfssdxcBI=
-github.com/go-openapi/spec v0.20.3 h1:uH9RQ6vdyPSs2pSy9fL8QPspDF2AMIMPtmK5coSSjtQ=
-github.com/go-openapi/spec v0.20.3/go.mod h1:gG4F8wdEDN+YPBMVnzE85Rbhf+Th2DTvA9nFPQ5AYEg=
+github.com/go-openapi/spec v0.20.4 h1:O8hJrt0UMnhHcluhIdUgCLRWyM2x7QkBXRvOs7m+O1M=
+github.com/go-openapi/spec v0.20.4/go.mod h1:faYFR1CvsJZ0mNsmsphTMSoRrNV3TEDoAM7FOEWeq8I=
 github.com/go-openapi/swag v0.17.0/go.mod h1:AByQ+nYG6gQg71GINrmuDXCPWdL640yX49/kXLo40Tg=
 github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
-github.com/go-openapi/swag v0.19.14 h1:gm3vOOXfiuw5i9p5N9xJvfjvuofpyvLA9Wr6QfK5Fng=
-github.com/go-openapi/swag v0.19.14/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
+github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
+github.com/go-openapi/swag v0.21.1 h1:wm0rhTb5z7qpJRHBdPOMuY4QjVUMbF6/kwoYeRAOrKU=
+github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
 github.com/go-playground/assert/v2 v2.0.1 h1:MsBgLAaY856+nPRTKrp3/OZK38U/wa0CcBYNjji3q3A=
 github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
 github.com/go-playground/locales v0.12.1/go.mod h1:IUMDtCfWo/w/mtMfIE/IG2K+Ey3ygWanZIBtBW0W2TM=
@@ -264,8 +273,8 @@ github.com/go-playground/universal-translator v0.18.0 h1:82dyy6p4OuJq4/CByFNOn/j
 github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
 github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
 github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4=
-github.com/go-playground/validator/v10 v10.9.0 h1:NgTtmN58D0m8+UuxtYmGztBJB7VnPgjj221I1QHci2A=
-github.com/go-playground/validator/v10 v10.9.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
+github.com/go-playground/validator/v10 v10.10.1 h1:uA0+amWMiglNZKZ9FJRKUAe9U3RX91eVn1JYXMWt7ig=
+github.com/go-playground/validator/v10 v10.10.1/go.mod h1:i+3WkQ1FvaUjjxh1kSvIA4dMGDBiPU55YFDl0WbKdWU=
 github.com/go-redis/cache/v8 v8.4.1 h1:jq0fw7hcUJzsoS9qPYjXzcAT/rm19TRMB1vEMG3m950=
 github.com/go-redis/cache/v8 v8.4.1/go.mod h1:iyYQNUxMsz6cPfTX3h4sT4lUmDXV0mDuEyeAn2o1btI=
 github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
@@ -376,8 +385,9 @@ github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/
 github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
 github.com/google/go-cmp v0.5.4/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 h1:BKbKCqvP6I+rmFHt06ZmyQtvB8xAkWdhFyr0ZUNZcxQ=
 github.com/google/go-cmp v0.5.6/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
+github.com/google/go-cmp v0.5.7 h1:81/ik6ipDQS2aGcBfIN5dHDB36BwrStyeAQquSYCV4o=
+github.com/google/go-cmp v0.5.7/go.mod h1:n+brtR0CgQNWTVd5ZUFpTBC8YFBDLK/h/bpaJ8/DtOE=
 github.com/google/go-github v17.0.0+incompatible h1:N0LgJ1j65A7kfXrZnUDaYCs/Sf4rEjNlfyDHW9dolSY=
 github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
 github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8=
@@ -601,8 +611,9 @@ github.com/magiconair/properties v1.8.5/go.mod h1:y3VJvCyxH9uVvJTWEGAELF3aiYNyPK
 github.com/mailru/easyjson v0.0.0-20180823135443-60711f1a8329/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.0.0-20190614124828-94de47d64c63/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
 github.com/mailru/easyjson v0.0.0-20190626092158-b2ccc519800e/go.mod h1:C1wdFJiN94OJF2b5HbByQZoLdCWB1Yqtg26g4irojpc=
-github.com/mailru/easyjson v0.7.6 h1:8yTIVnZgCoiM1TgqoeTl+LfU5Jg6/xL3QhGQnimLYnA=
 github.com/mailru/easyjson v0.7.6/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
+github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0=
+github.com/mailru/easyjson v0.7.7/go.mod h1:xzfreul335JAWq5oZzymOObrkdz5UnU4kGfJJLY9Nlc=
 github.com/markbates/oncer v0.0.0-20181203154359-bf2de49a0be2/go.mod h1:Ld9puTsIW75CHf65OeIOkyKbteujpZVXDpWK6YGZbxE=
 github.com/markbates/safe v1.0.1/go.mod h1:nAqgmRi7cY2nqMc92/bSEeQA+R4OheNU2T1kNSCBdG0=
 github.com/marstr/guid v1.1.0/go.mod h1:74gB1z2wpxxInTG6yaqA7KrtM0NZ+RbrcqDvYHefzho=
@@ -694,6 +705,12 @@ github.com/opencontainers/image-spec v1.0.2/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zM
 github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
 github.com/opentracing/opentracing-go v1.2.0 h1:uEJPy/1a5RIPAJ0Ov+OIO8OxWu77jEv+1B0VhjKrZUs=
 github.com/opentracing/opentracing-go v1.2.0/go.mod h1:GxEUsuufX4nBwe+T+Wl9TAgYrxe9dPLANfrWvHYVTgc=
+github.com/otiai10/copy v1.7.0 h1:hVoPiN+t+7d2nzzwMiDHPSOogsWAStewq3TwU05+clE=
+github.com/otiai10/copy v1.7.0/go.mod h1:rmRl6QPdJj6EiUqXQ/4Nn2lLXoNQjFCQbbNrxgc/t3U=
+github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
+github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
+github.com/otiai10/mint v1.3.0/go.mod h1:F5AjcsTsWUqX+Na9fpHb52P8pcRX2CI6A3ctIT91xUo=
+github.com/otiai10/mint v1.3.3/go.mod h1:/yxELlJQ0ufhjUwhshSj+wFjZ78CnZ48/1wtmBH1OTc=
 github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
 github.com/pborman/getopt v0.0.0-20180729010549-6fdd0a2c7117/go.mod h1:85jBQOZwpVEaDAr341tbn15RS4fCAsIst0qp7i8ex1o=
 github.com/pelletier/go-toml v1.7.0/go.mod h1:vwGMzjaWMwyfHwgIBhI2YUM4fB6nL6lVAvS1LBMMhTE=
@@ -823,8 +840,8 @@ github.com/swaggo/files v0.0.0-20210815190702-a29dd2bc99b2/go.mod h1:lKJPbtWzJ9J
 github.com/swaggo/gin-swagger v1.3.1 h1:mO9MU8O99WX+RM3jekzOV54g9Fo+Nbkk7rgrN1u9irM=
 github.com/swaggo/gin-swagger v1.3.1/go.mod h1:Z6NtRBK2PRig0EUmy1Xu75CnCEs6vGYu9QZd/QWRYKU=
 github.com/swaggo/swag v1.5.1/go.mod h1:1Bl9F/ZBpVWh22nY0zmYyASPO1lI/zIwRDrpZU+tv8Y=
-github.com/swaggo/swag v1.7.1 h1:gY9ZakXlNWg/i/v5bQBic7VMZ4teq4m89lpiao74p/s=
-github.com/swaggo/swag v1.7.1/go.mod h1:gAiHxNTb9cIpNmA/VEGUP+CyZMCP/EW7mdtc8Bny+p8=
+github.com/swaggo/swag v1.8.0 h1:80NNhvpJcuItNpBDqgJwDuKlMmaZ/OATOzhG3bhcM3w=
+github.com/swaggo/swag v1.8.0/go.mod h1:gZ+TJ2w/Ve1RwQsA2IRoSOTidHz6DX+PIG8GWvbnoLU=
 github.com/tidwall/gjson v1.6.0 h1:9VEQWz6LLMUsUl6PueE49ir4Ka6CzLymOAZDxpFsTDc=
 github.com/tidwall/gjson v1.6.0/go.mod h1:P256ACg0Mn+j1RXIDXoss50DeIABTYK1PULOJHhxOls=
 github.com/tidwall/match v1.0.1 h1:PnKP62LPNxHKTwvHHZZzdOAOCtsJTjo6dZLCwpKm5xc=
@@ -835,13 +852,13 @@ github.com/tklauser/go-sysconf v0.3.9/go.mod h1:11DU/5sG7UexIrp/O6g35hrWzu0JxlwQ
 github.com/tklauser/numcpus v0.3.0/go.mod h1:yFGUr7TUHQRAhyqBcEg0Ge34zDBAsIvJJcyE6boqnA8=
 github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
 github.com/ugorji/go v1.1.13/go.mod h1:jxau1n+/wyTGLQoCkjok9r5zFa/FxT6eI5HiHKQszjc=
-github.com/ugorji/go v1.2.6 h1:tGiWC9HENWE2tqYycIqFTNorMmFRVhNwCpDOpWqnk8E=
-github.com/ugorji/go v1.2.6/go.mod h1:anCg0y61KIhDlPZmnH+so+RQbysYVyDko0IMgJv0Nn0=
+github.com/ugorji/go v1.2.7 h1:qYhyWUUd6WbiM+C6JZAUkIJt/1WrjzNHY9+KCIjVqTo=
+github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
 github.com/ugorji/go/codec v0.0.0-20181022190402-e5e69e061d4f/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
 github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
 github.com/ugorji/go/codec v1.1.13/go.mod h1:oNVt3Dq+FO91WNQ/9JnHKQP2QJxTzoN7wCBFCq1OeuU=
-github.com/ugorji/go/codec v1.2.6 h1:7kbGefxLoDBuYXOms4yD7223OpNMMPNPZxXk5TvFcyQ=
-github.com/ugorji/go/codec v1.2.6/go.mod h1:V6TCNZ4PHqoHGFZuSG1W8nrCzzdgA2DozYxWFFpvxTw=
+github.com/ugorji/go/codec v1.2.7 h1:YPXUKf7fYbp/y8xloBqZOw2qaVggbfwMlI8WM3wZUJ0=
+github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
 github.com/urfave/cli v1.20.0/go.mod h1:70zkFmudgCuE/ngEzBv17Jvp/497gISqfk5gWijbERA=
 github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
 github.com/urfave/cli/v2 v2.3.0/go.mod h1:LJmUH05zAU44vOAcrfzZQKsZbVcdbOG8rtL3/XcUArI=
@@ -870,6 +887,7 @@ github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
 github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
 github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
 github.com/yusufpapurcu/wmi v1.2.2 h1:KBNDSne4vP5mbSWnJbO+51IMOXJB67QiYCSBrubbPRg=
 github.com/yusufpapurcu/wmi v1.2.2/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0=
 github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43/go.mod h1:aX5oPXxHm3bOH+xeAttToC8pqch2ScQN/JoXYupl6xs=
@@ -893,34 +911,41 @@ go.opencensus.io v0.23.0 h1:gqCw0LfLxScz8irSi8exQc7fyQ0fKQU/qnC/X8+V/1M=
 go.opencensus.io v0.23.0/go.mod h1:XItmlyltB5F7CS4xOC1DcqMoFqwtC6OG2xF7mCv7P7E=
 go.opentelemetry.io/contrib v0.20.0 h1:ubFQUn0VCZ0gPwIoJfBJVpeBlyRMxu8Mm/huKWYd9p0=
 go.opentelemetry.io/contrib v0.20.0/go.mod h1:G/EtFaa6qaN7+LxqfIAT3GiZa7Wv5DTBUzl5H4LY0Kc=
-go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.20.0 h1:R6rfVN+8Eqzd+E5L/i8rWpgZeWen/m6y4hSgn3avdf8=
-go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.20.0/go.mod h1:npLhGl0PxPw3jya83ffJ/CfZ8BPwyKUHHZsbgTdpvCs=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0 h1:sO4WKdPAudZGKPcpZT4MJn6JaDmpyLrMPDGGyA1SttE=
-go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.20.0/go.mod h1:oVGt1LRbBOBq1A5BQLlUg9UaU/54aiHw8cgjV3aWZ/E=
+go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.29.0 h1:FXxrtpB3DEL2UNJw7CVx+riiHyfAOZibsgRPePNL/W0=
+go.opentelemetry.io/contrib/instrumentation/github.com/gin-gonic/gin/otelgin v0.29.0/go.mod h1:iHyT9pMs/8+wDgXFIckl62cF9Ea2AiX4mN4jt+40rmI=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.29.0 h1:n9b7AAdbQtQ0k9dm0Dm2/KUcUqtG8i2O15KzNaDze8c=
+go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.29.0/go.mod h1:LsankqVDx4W+RhZNA5uWarULII/MBhF5qwCYxTuyXjs=
 go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.20.0/go.mod h1:2AboqHi0CiIZU0qwhtUfCYD1GeUzvvIXWNkhDt7ZMG4=
-go.opentelemetry.io/contrib/propagators v0.20.0 h1:IrLQng5Z7AfzkS4sEsYaj2ejkO4FCkgKdAr1aYKOfNc=
-go.opentelemetry.io/contrib/propagators v0.20.0/go.mod h1:yLmt93MeSiARUwrK57bOZ4FBruRN4taLiW1lcGfnOes=
+go.opentelemetry.io/contrib/propagators/b3 v1.4.0 h1:wDb2ct7xMzossYpx44w81skxkEyeT2IRnBgYKqyEork=
+go.opentelemetry.io/contrib/propagators/b3 v1.4.0/go.mod h1:K399DN23drp0RQGXCbSPOt9075HopQigMgUL99oR8hc=
 go.opentelemetry.io/otel v0.11.0/go.mod h1:G8UCk+KooF2HLkgo8RHX9epABH/aRGYET7gQOqBVdB0=
 go.opentelemetry.io/otel v0.15.0/go.mod h1:e4GKElweB8W2gWUqbghw0B8t5MCTccc9212eNHnOHwA=
 go.opentelemetry.io/otel v0.17.0/go.mod h1:Oqtdxmf7UtEvL037ohlgnaYa1h7GtMh0NcSd9eqkC9s=
-go.opentelemetry.io/otel v0.20.0 h1:eaP0Fqu7SXHwvjiqDq83zImeehOHX8doTvU9AwXON8g=
 go.opentelemetry.io/otel v0.20.0/go.mod h1:Y3ugLH2oa81t5QO+Lty+zXf8zC9L26ax4Nzoxm/dooo=
+go.opentelemetry.io/otel v1.4.0/go.mod h1:jeAqMFKy2uLIxCtKxoFj0FAL5zAPKQagc3+GtBWakzk=
+go.opentelemetry.io/otel v1.4.1 h1:QbINgGDDcoQUoMJa2mMaWno49lja9sHwp6aoa2n3a4g=
+go.opentelemetry.io/otel v1.4.1/go.mod h1:StM6F/0fSwpd8dKWDCdRr7uRvEPYdW0hBSlbdTiUde4=
+go.opentelemetry.io/otel/exporters/jaeger v1.4.1 h1:VHCK+2yTZDqDaVXj7JH2Z/khptuydo6C0ttBh2bxAbc=
+go.opentelemetry.io/otel/exporters/jaeger v1.4.1/go.mod h1:ZW7vkOu9nC1CxsD8bHNHCia5JUbwP39vxgd1q4Z5rCI=
 go.opentelemetry.io/otel/exporters/otlp v0.20.0/go.mod h1:YIieizyaN77rtLJra0buKiNBOm9XQfkPEKBeuhoMwAM=
-go.opentelemetry.io/otel/exporters/trace/jaeger v0.20.0 h1:FoclOadJNul1vUiKnZU0sKFWOZtZQq3jUzSbrX2jwNM=
-go.opentelemetry.io/otel/exporters/trace/jaeger v0.20.0/go.mod h1:10qwvAmKpvwRO5lL3KQ8EWznPp89uGfhcbK152LFWsQ=
+go.opentelemetry.io/otel/internal/metric v0.27.0 h1:9dAVGAfFiiEq5NVB9FUJ5et+btbDQAUIJehJ+ikyryk=
+go.opentelemetry.io/otel/internal/metric v0.27.0/go.mod h1:n1CVxRqKqYZtqyTh9U/onvKapPGv7y/rpyOTI+LFNzw=
 go.opentelemetry.io/otel/metric v0.17.0/go.mod h1:hUz9lH1rNXyEwWAhIWCMFWKhYtpASgSnObJFnU26dJ0=
-go.opentelemetry.io/otel/metric v0.20.0 h1:4kzhXFP+btKm4jwxpjIqjs41A7MakRFUS86bqLHTIw8=
 go.opentelemetry.io/otel/metric v0.20.0/go.mod h1:598I5tYlH1vzBjn+BTuhzTCSb/9debfNp6R3s7Pr1eU=
+go.opentelemetry.io/otel/metric v0.27.0 h1:HhJPsGhJoKRSegPQILFbODU56NS/L1UE4fS1sC5kIwQ=
+go.opentelemetry.io/otel/metric v0.27.0/go.mod h1:raXDJ7uP2/Jc0nVZWQjJtzoyssOYWu/+pjZqRzfvZ7g=
 go.opentelemetry.io/otel/oteltest v0.17.0/go.mod h1:JT/LGFxPwpN+nlsTiinSYjdIx3hZIGqHCpChcIZmdoE=
-go.opentelemetry.io/otel/oteltest v0.20.0 h1:HiITxCawalo5vQzdHfKeZurV8x7ljcqAgiWzF6Vaeaw=
 go.opentelemetry.io/otel/oteltest v0.20.0/go.mod h1:L7bgKf9ZB7qCwT9Up7i9/pn0PWIa9FqQ2IQ8LoxiGnw=
-go.opentelemetry.io/otel/sdk v0.20.0 h1:JsxtGXd06J8jrnya7fdI/U/MR6yXA5DtbZy+qoHQlr8=
 go.opentelemetry.io/otel/sdk v0.20.0/go.mod h1:g/IcepuwNsoiX5Byy2nNV0ySUF1em498m7hBWC279Yc=
+go.opentelemetry.io/otel/sdk v1.4.1 h1:J7EaW71E0v87qflB4cDolaqq3AcujGrtyIPGQoZOB0Y=
+go.opentelemetry.io/otel/sdk v1.4.1/go.mod h1:NBwHDgDIBYjwK2WNu1OPgsIc2IJzmBXNnvIJxJc8BpE=
 go.opentelemetry.io/otel/sdk/export/metric v0.20.0/go.mod h1:h7RBNMsDJ5pmI1zExLi+bJK+Dr8NQCh0qGhm1KDnNlE=
 go.opentelemetry.io/otel/sdk/metric v0.20.0/go.mod h1:knxiS8Xd4E/N+ZqKmUPf3gTTZ4/0TjTXukfxjzSTpHE=
 go.opentelemetry.io/otel/trace v0.17.0/go.mod h1:bIujpqg6ZL6xUTubIUgziI1jSaUPthmabA/ygf/6Cfg=
-go.opentelemetry.io/otel/trace v0.20.0 h1:1DL6EXUdcg95gukhuRRvLDO/4X5THh/5dIV52lqtnbw=
 go.opentelemetry.io/otel/trace v0.20.0/go.mod h1:6GjCW8zgDjwGHGa6GkyeB8+/5vjT16gUEi0Nf1iBdgw=
+go.opentelemetry.io/otel/trace v1.4.0/go.mod h1:uc3eRsqDfWs9R7b92xbQbU42/eTNz4N+gLP8qJCi4aE=
+go.opentelemetry.io/otel/trace v1.4.1 h1:O+16qcdTrT7zxv2J6GejTPFinSwA++cYerC5iSiF8EQ=
+go.opentelemetry.io/otel/trace v1.4.1/go.mod h1:iYEVbroFCNut9QkwEczV9vMRPHNKSSwYZjulEtsmhFc=
 go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
 go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
 go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
@@ -961,10 +986,10 @@ golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPh
 golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
 golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
 golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.0.0-20210817164053-32db794688a5/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871 h1:/pEO3GD/ABYAjuakUS6xSEmmlyVS4kxBNkeA9tLJiTI=
-golang.org/x/crypto v0.0.0-20211117183948-ae814b36b871/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70 h1:syTAU9FwmvzEoIYMqcPHOcVm4H3U5u90WsvuYgwpETU=
+golang.org/x/crypto v0.0.0-20220307211146-efcb8507fb70/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
 golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
 golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -1006,8 +1031,9 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.3.1-0.20200828183125-ce943fd02449/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
 golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
-golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
 golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/mod v0.5.1 h1:OJxoQ/rynoF0dcCdI7cLPktw/hR2cueqYfjm43oqK38=
+golang.org/x/mod v0.5.1/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
 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-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -1056,12 +1082,15 @@ golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v
 golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
 golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
 golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
+golang.org/x/net v0.0.0-20210421230115-4e50805a0758/go.mod h1:72T/g9IO56b78aLF+1Kcs5dz7/ng1VjMUvfKvpfy+jM=
 golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk=
 golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
-golang.org/x/net v0.0.0-20211209124913-491a49abca63 h1:iocB37TsdFuN6IBRZ+ry36wrkoV51/tl5vOWqkcPGvY=
 golang.org/x/net v0.0.0-20211209124913-491a49abca63/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc=
+golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
 golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
 golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
 golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1158,7 +1187,9 @@ golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7w
 golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210420072515-93ed5bcd2bfe/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210423082822-04245dca01da/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-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -1169,12 +1200,15 @@ golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBc
 golang.org/x/sys v0.0.0-20210816074244-15123e1e1f71/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211013075003-97ac67df715c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM=
+golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220307203707-22a9840ba4d7 h1:8IVLkfbr2cLhv0a/vKq4UFUcJym8RmDoDboxCFWEjYE=
+golang.org/x/sys v0.0.0-20220307203707-22a9840ba4d7/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
-golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b h1:9zKuko04nR4gjZ4+DNjHqRlAJqbJETHwiNKDqTfOjfE=
 golang.org/x/term v0.0.0-20210615171337-6886f2dfbf5b/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY=
+golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
 golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -1261,8 +1295,10 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0=
 golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
 golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
-golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff h1:VX/uD7MK0AHXGiScH3fsieUQUcpmRERPDYtqZdJnA+Q=
 golang.org/x/tools v0.1.6-0.20210820212750-d4cc65f0b2ff/go.mod h1:YD9qOF0M9xpSpdWTBbzEl5e/RnCefISl8E5Noe10jFM=
+golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
+golang.org/x/tools v0.1.9 h1:j9KsMiaP1c3B0OTQGth0/k+miLGTgLsAFUCrF2vLcF8=
+golang.org/x/tools v0.1.9/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU=
 golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
@@ -1351,8 +1387,9 @@ google.golang.org/genproto v0.0.0-20210310155132-4ce2db91004e/go.mod h1:FWY/as6D
 google.golang.org/genproto v0.0.0-20210319143718-93e7006c17a6/go.mod h1:FWY/as6DDZQgahTzZj3fqbO1CbirC29ZNUFHwi0/+no=
 google.golang.org/genproto v0.0.0-20210402141018-6c239bbf2bb1/go.mod h1:9lPAdzaEmUacj36I+k7YKbEc5CXzPIeORRgDAUOu28A=
 google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
-google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2 h1:NHN4wOCScVzKhPenJ2dt+BTs3X/XkBVI/Rh4iDt55T8=
 google.golang.org/genproto v0.0.0-20210831024726-fe130286e0e2/go.mod h1:eFjDcFEctNawg4eG61bRv87N7iHBWyVhJu7u1kqDUXY=
+google.golang.org/genproto v0.0.0-20220308174144-ae0e22291548 h1:J5ZNG1QIdstOl8aaUoFoQJfp04FKTsFV+jwkBHEchqs=
+google.golang.org/genproto v0.0.0-20220308174144-ae0e22291548/go.mod h1:kGP+zUP2Ddo0ayMi4YuN7C3WZyJvGLZRh8Z5wnAqvEI=
 google.golang.org/grpc v0.0.0-20160317175043-d3ddb4469d5a/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw=
 google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
 google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
@@ -1375,8 +1412,9 @@ google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG
 google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
 google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
 google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
-google.golang.org/grpc v1.40.0 h1:AGJ0Ih4mHjSeibYkFGh1dD9KJ/eOtZ93I6hoHhukQ5Q=
 google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
+google.golang.org/grpc v1.44.0 h1:weqSxi/TMs1SqFRMHCtBgXRs8k3X39QIDEZ0pRcttUg=
+google.golang.org/grpc v1.44.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU=
 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=
diff --git a/internal/dflog/logcore.go b/internal/dflog/logcore.go
index 98d5c412..66e65608 100644
--- a/internal/dflog/logcore.go
+++ b/internal/dflog/logcore.go
@@ -36,8 +36,8 @@ var (
 )
 
 const (
-	defaultRotateMaxSize    = 300
-	defaultRotateMaxBackups = 50
+	defaultRotateMaxSize    = 100
+	defaultRotateMaxBackups = 10
 	defaultRotateMaxAge     = 7
 )
 
diff --git a/manager/console b/manager/console
index cd8a0e49..781ecbae 160000
--- a/manager/console
+++ b/manager/console
@@ -1,1 +1,1 @@
-Subproject commit cd8a0e49a2f598b741163a0c05dd0c816d8e3333
+Subproject commit 781ecbae535bcf6ac74e7aa4b5adb7f721490618
diff --git a/manager/database/mysql.go b/manager/database/mysql.go
index b849e77f..0eb3f3c8 100644
--- a/manager/database/mysql.go
+++ b/manager/database/mysql.go
@@ -33,10 +33,13 @@ import (
 
 const (
 	// Default number of cdn load limit
-	defaultCDNLoadLimit = 300
+	DefaultCDNLoadLimit = 300
 
 	// Default number of client load limit
-	defaultClientLoadLimit = 50
+	DefaultClientLoadLimit = 50
+
+	// Default number of pieces to download in parallel
+	DefaultClientParallelCount = 4
 )
 
 func newMyqsl(cfg *config.MysqlConfig) (*gorm.DB, error) {
@@ -130,7 +133,7 @@ func seed(db *gorm.DB) error {
 			},
 			Name: "cdn-cluster-1",
 			Config: map[string]interface{}{
-				"load_limit": defaultCDNLoadLimit,
+				"load_limit": DefaultCDNLoadLimit,
 			},
 			IsDefault: true,
 		}).Error; err != nil {
@@ -150,7 +153,8 @@ func seed(db *gorm.DB) error {
 			Name:   "scheduler-cluster-1",
 			Config: map[string]interface{}{},
 			ClientConfig: map[string]interface{}{
-				"load_limit": defaultClientLoadLimit,
+				"load_limit":     DefaultClientLoadLimit,
+				"parallel_count": DefaultClientParallelCount,
 			},
 			Scopes:    map[string]interface{}{},
 			IsDefault: true,
diff --git a/manager/handlers/handlers.go b/manager/handlers/handlers.go
index b9d4ec73..11620de2 100644
--- a/manager/handlers/handlers.go
+++ b/manager/handlers/handlers.go
@@ -27,10 +27,10 @@ import (
 )
 
 type Handlers struct {
-	service service.REST
+	service service.Service
 }
 
-func New(service service.REST) *Handlers {
+func New(service service.Service) *Handlers {
 	return &Handlers{
 		service: service,
 	}
diff --git a/manager/handlers/user.go b/manager/handlers/user.go
index ca381215..ea73ed36 100644
--- a/manager/handlers/user.go
+++ b/manager/handlers/user.go
@@ -27,6 +27,40 @@ import (
 	"d7y.io/dragonfly/v2/manager/types"
 )
 
+// @Summary Update User
+// @Description Update by json config
+// @Tags User
+// @Accept json
+// @Produce json
+// @Param id path string true "id"
+// @Param User body types.UpdateUserRequest true "User"
+// @Success 200 {object} model.User
+// @Failure 400
+// @Failure 404
+// @Failure 500
+// @Router /users/{id} [patch]
+func (h *Handlers) UpdateUser(ctx *gin.Context) {
+	var params types.UserParams
+	if err := ctx.ShouldBindUri(&params); err != nil {
+		ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()})
+		return
+	}
+
+	var json types.UpdateUserRequest
+	if err := ctx.ShouldBindJSON(&json); err != nil {
+		ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()})
+		return
+	}
+
+	user, err := h.service.UpdateUser(ctx.Request.Context(), params.ID, json)
+	if err != nil {
+		ctx.Error(err) // nolint: errcheck
+		return
+	}
+
+	ctx.JSON(http.StatusOK, user)
+}
+
 // @Summary Get User
 // @Description Get User by id
 // @Tags User
diff --git a/manager/manager.go b/manager/manager.go
index f0815c78..9bd1fe5f 100644
--- a/manager/manager.go
+++ b/manager/manager.go
@@ -40,6 +40,8 @@ import (
 )
 
 const (
+	// gracefulStopTimeout specifies a time limit for
+	// grpc server to complete a graceful shutdown
 	gracefulStopTimeout = 10 * time.Second
 )
 
@@ -88,7 +90,7 @@ func New(cfg *config.Config, d dfpath.Dfpath) (*Server, error) {
 	}
 
 	// Initialize REST server
-	restService := service.NewREST(db, cache, job, enforcer)
+	restService := service.New(db, cache, job, enforcer)
 	router, err := router.Init(cfg, d.LogDir(), restService, enforcer)
 	if err != nil {
 		return nil, err
diff --git a/manager/middlewares/jwt.go b/manager/middlewares/jwt.go
index f8ccd6cb..5d90d6c2 100644
--- a/manager/middlewares/jwt.go
+++ b/manager/middlewares/jwt.go
@@ -29,7 +29,7 @@ import (
 	"d7y.io/dragonfly/v2/manager/types"
 )
 
-func Jwt(service service.REST) (*jwt.GinJWTMiddleware, error) {
+func Jwt(service service.Service) (*jwt.GinJWTMiddleware, error) {
 	identityKey := "id"
 
 	authMiddleware, err := jwt.New(&jwt.GinJWTMiddleware{
diff --git a/manager/router/router.go b/manager/router/router.go
index e33ed602..30de995b 100644
--- a/manager/router/router.go
+++ b/manager/router/router.go
@@ -43,7 +43,7 @@ const (
 
 var GinLogFileName = "gin.log"
 
-func Init(cfg *config.Config, logDir string, service service.REST, enforcer *casbin.Enforcer) (*gin.Engine, error) {
+func Init(cfg *config.Config, logDir string, service service.Service, enforcer *casbin.Enforcer) (*gin.Engine, error) {
 	// Set mode
 	if !cfg.Verbose {
 		gin.SetMode(gin.ReleaseMode)
@@ -93,6 +93,7 @@ func Init(cfg *config.Config, logDir string, service service.REST, enforcer *cas
 
 	// User
 	u := apiv1.Group("/users")
+	u.PATCH(":id", jwt.MiddlewareFunc(), rbac, h.UpdateUser)
 	u.GET("/:id", jwt.MiddlewareFunc(), rbac, h.GetUser)
 	u.GET("", jwt.MiddlewareFunc(), rbac, h.GetUsers)
 	u.POST("/signin", jwt.LoginHandler)
diff --git a/manager/service/application.go b/manager/service/application.go
index 3abfdc5c..e03decaf 100644
--- a/manager/service/application.go
+++ b/manager/service/application.go
@@ -23,7 +23,7 @@ import (
 	"d7y.io/dragonfly/v2/manager/types"
 )
 
-func (s *rest) CreateApplication(ctx context.Context, json types.CreateApplicationRequest) (*model.Application, error) {
+func (s *service) CreateApplication(ctx context.Context, json types.CreateApplicationRequest) (*model.Application, error) {
 	application := model.Application{
 		Name:              json.Name,
 		DownloadRateLimit: json.DownloadRateLimit,
@@ -40,7 +40,7 @@ func (s *rest) CreateApplication(ctx context.Context, json types.CreateApplicati
 	return &application, nil
 }
 
-func (s *rest) DestroyApplication(ctx context.Context, id uint) error {
+func (s *service) DestroyApplication(ctx context.Context, id uint) error {
 	application := model.Application{}
 	if err := s.db.WithContext(ctx).First(&application, id).Error; err != nil {
 		return err
@@ -53,7 +53,7 @@ func (s *rest) DestroyApplication(ctx context.Context, id uint) error {
 	return nil
 }
 
-func (s *rest) UpdateApplication(ctx context.Context, id uint, json types.UpdateApplicationRequest) (*model.Application, error) {
+func (s *service) UpdateApplication(ctx context.Context, id uint, json types.UpdateApplicationRequest) (*model.Application, error) {
 	application := model.Application{}
 	if err := s.db.WithContext(ctx).Preload("CDNClusters").Preload("SchedulerClusters").Preload("User").First(&application, id).Updates(model.Application{
 		Name:              json.Name,
@@ -69,7 +69,7 @@ func (s *rest) UpdateApplication(ctx context.Context, id uint, json types.Update
 	return &application, nil
 }
 
-func (s *rest) GetApplication(ctx context.Context, id uint) (*model.Application, error) {
+func (s *service) GetApplication(ctx context.Context, id uint) (*model.Application, error) {
 	application := model.Application{}
 	if err := s.db.WithContext(ctx).Preload("CDNClusters").Preload("SchedulerClusters").Preload("User").First(&application, id).Error; err != nil {
 		return nil, err
@@ -78,7 +78,7 @@ func (s *rest) GetApplication(ctx context.Context, id uint) (*model.Application,
 	return &application, nil
 }
 
-func (s *rest) GetApplications(ctx context.Context, q types.GetApplicationsQuery) (*[]model.Application, int64, error) {
+func (s *service) GetApplications(ctx context.Context, q types.GetApplicationsQuery) (*[]model.Application, int64, error) {
 	var count int64
 	applications := []model.Application{}
 	if err := s.db.WithContext(ctx).Scopes(model.Paginate(q.Page, q.PerPage)).Preload("CDNClusters").Preload("SchedulerClusters").Preload("User").Find(&applications).Count(&count).Error; err != nil {
@@ -88,7 +88,7 @@ func (s *rest) GetApplications(ctx context.Context, q types.GetApplicationsQuery
 	return &applications, count, nil
 }
 
-func (s *rest) AddSchedulerClusterToApplication(ctx context.Context, id, schedulerClusterID uint) error {
+func (s *service) AddSchedulerClusterToApplication(ctx context.Context, id, schedulerClusterID uint) error {
 	application := model.Application{}
 	if err := s.db.WithContext(ctx).First(&application, id).Error; err != nil {
 		return err
@@ -106,7 +106,7 @@ func (s *rest) AddSchedulerClusterToApplication(ctx context.Context, id, schedul
 	return nil
 }
 
-func (s *rest) DeleteSchedulerClusterToApplication(ctx context.Context, id, schedulerClusterID uint) error {
+func (s *service) DeleteSchedulerClusterToApplication(ctx context.Context, id, schedulerClusterID uint) error {
 	application := model.Application{}
 	if err := s.db.WithContext(ctx).First(&application, id).Error; err != nil {
 		return err
@@ -124,7 +124,7 @@ func (s *rest) DeleteSchedulerClusterToApplication(ctx context.Context, id, sche
 	return nil
 }
 
-func (s *rest) AddCDNClusterToApplication(ctx context.Context, id, cdnClusterID uint) error {
+func (s *service) AddCDNClusterToApplication(ctx context.Context, id, cdnClusterID uint) error {
 	application := model.Application{}
 	if err := s.db.WithContext(ctx).First(&application, id).Error; err != nil {
 		return err
@@ -142,7 +142,7 @@ func (s *rest) AddCDNClusterToApplication(ctx context.Context, id, cdnClusterID
 	return nil
 }
 
-func (s *rest) DeleteCDNClusterToApplication(ctx context.Context, id, cdnClusterID uint) error {
+func (s *service) DeleteCDNClusterToApplication(ctx context.Context, id, cdnClusterID uint) error {
 	application := model.Application{}
 	if err := s.db.WithContext(ctx).First(&application, id).Error; err != nil {
 		return err
diff --git a/manager/service/cdn.go b/manager/service/cdn.go
index 831c3a6c..346be9b7 100644
--- a/manager/service/cdn.go
+++ b/manager/service/cdn.go
@@ -23,7 +23,7 @@ import (
 	"d7y.io/dragonfly/v2/manager/types"
 )
 
-func (s *rest) CreateCDN(ctx context.Context, json types.CreateCDNRequest) (*model.CDN, error) {
+func (s *service) CreateCDN(ctx context.Context, json types.CreateCDNRequest) (*model.CDN, error) {
 	cdn := model.CDN{
 		HostName:     json.HostName,
 		IDC:          json.IDC,
@@ -41,7 +41,7 @@ func (s *rest) CreateCDN(ctx context.Context, json types.CreateCDNRequest) (*mod
 	return &cdn, nil
 }
 
-func (s *rest) DestroyCDN(ctx context.Context, id uint) error {
+func (s *service) DestroyCDN(ctx context.Context, id uint) error {
 	cdn := model.CDN{}
 	if err := s.db.WithContext(ctx).First(&cdn, id).Error; err != nil {
 		return err
@@ -54,7 +54,7 @@ func (s *rest) DestroyCDN(ctx context.Context, id uint) error {
 	return nil
 }
 
-func (s *rest) UpdateCDN(ctx context.Context, id uint, json types.UpdateCDNRequest) (*model.CDN, error) {
+func (s *service) UpdateCDN(ctx context.Context, id uint, json types.UpdateCDNRequest) (*model.CDN, error) {
 	cdn := model.CDN{}
 	if err := s.db.WithContext(ctx).First(&cdn, id).Updates(model.CDN{
 		IDC:          json.IDC,
@@ -70,7 +70,7 @@ func (s *rest) UpdateCDN(ctx context.Context, id uint, json types.UpdateCDNReque
 	return &cdn, nil
 }
 
-func (s *rest) GetCDN(ctx context.Context, id uint) (*model.CDN, error) {
+func (s *service) GetCDN(ctx context.Context, id uint) (*model.CDN, error) {
 	cdn := model.CDN{}
 	if err := s.db.WithContext(ctx).First(&cdn, id).Error; err != nil {
 		return nil, err
@@ -79,7 +79,7 @@ func (s *rest) GetCDN(ctx context.Context, id uint) (*model.CDN, error) {
 	return &cdn, nil
 }
 
-func (s *rest) GetCDNs(ctx context.Context, q types.GetCDNsQuery) (*[]model.CDN, int64, error) {
+func (s *service) GetCDNs(ctx context.Context, q types.GetCDNsQuery) (*[]model.CDN, int64, error) {
 	var count int64
 	var cdns []model.CDN
 	if err := s.db.WithContext(ctx).Scopes(model.Paginate(q.Page, q.PerPage)).Where(&model.CDN{
diff --git a/manager/service/cdn_cluster.go b/manager/service/cdn_cluster.go
index 414eecc0..cf941ce7 100644
--- a/manager/service/cdn_cluster.go
+++ b/manager/service/cdn_cluster.go
@@ -24,7 +24,7 @@ import (
 	"d7y.io/dragonfly/v2/pkg/util/structutils"
 )
 
-func (s *rest) CreateCDNCluster(ctx context.Context, json types.CreateCDNClusterRequest) (*model.CDNCluster, error) {
+func (s *service) CreateCDNCluster(ctx context.Context, json types.CreateCDNClusterRequest) (*model.CDNCluster, error) {
 	config, err := structutils.StructToMap(json.Config)
 	if err != nil {
 		return nil, err
@@ -44,7 +44,7 @@ func (s *rest) CreateCDNCluster(ctx context.Context, json types.CreateCDNCluster
 	return &cdnCluster, nil
 }
 
-func (s *rest) DestroyCDNCluster(ctx context.Context, id uint) error {
+func (s *service) DestroyCDNCluster(ctx context.Context, id uint) error {
 	cdnCluster := model.CDNCluster{}
 	if err := s.db.WithContext(ctx).First(&cdnCluster, id).Error; err != nil {
 		return err
@@ -57,7 +57,7 @@ func (s *rest) DestroyCDNCluster(ctx context.Context, id uint) error {
 	return nil
 }
 
-func (s *rest) UpdateCDNCluster(ctx context.Context, id uint, json types.UpdateCDNClusterRequest) (*model.CDNCluster, error) {
+func (s *service) UpdateCDNCluster(ctx context.Context, id uint, json types.UpdateCDNClusterRequest) (*model.CDNCluster, error) {
 	config, err := structutils.StructToMap(json.Config)
 	if err != nil {
 		return nil, err
@@ -76,7 +76,7 @@ func (s *rest) UpdateCDNCluster(ctx context.Context, id uint, json types.UpdateC
 	return &cdnCluster, nil
 }
 
-func (s *rest) GetCDNCluster(ctx context.Context, id uint) (*model.CDNCluster, error) {
+func (s *service) GetCDNCluster(ctx context.Context, id uint) (*model.CDNCluster, error) {
 	cdnCluster := model.CDNCluster{}
 	if err := s.db.WithContext(ctx).First(&cdnCluster, id).Error; err != nil {
 		return nil, err
@@ -85,7 +85,7 @@ func (s *rest) GetCDNCluster(ctx context.Context, id uint) (*model.CDNCluster, e
 	return &cdnCluster, nil
 }
 
-func (s *rest) GetCDNClusters(ctx context.Context, q types.GetCDNClustersQuery) (*[]model.CDNCluster, int64, error) {
+func (s *service) GetCDNClusters(ctx context.Context, q types.GetCDNClustersQuery) (*[]model.CDNCluster, int64, error) {
 	var count int64
 	var cdnClusters []model.CDNCluster
 	if err := s.db.WithContext(ctx).Scopes(model.Paginate(q.Page, q.PerPage)).Where(&model.CDNCluster{
@@ -97,7 +97,7 @@ func (s *rest) GetCDNClusters(ctx context.Context, q types.GetCDNClustersQuery)
 	return &cdnClusters, count, nil
 }
 
-func (s *rest) AddCDNToCDNCluster(ctx context.Context, id, cdnID uint) error {
+func (s *service) AddCDNToCDNCluster(ctx context.Context, id, cdnID uint) error {
 	cdnCluster := model.CDNCluster{}
 	if err := s.db.WithContext(ctx).First(&cdnCluster, id).Error; err != nil {
 		return err
@@ -115,7 +115,7 @@ func (s *rest) AddCDNToCDNCluster(ctx context.Context, id, cdnID uint) error {
 	return nil
 }
 
-func (s *rest) AddSchedulerClusterToCDNCluster(ctx context.Context, id, schedulerClusterID uint) error {
+func (s *service) AddSchedulerClusterToCDNCluster(ctx context.Context, id, schedulerClusterID uint) error {
 	cdnCluster := model.CDNCluster{}
 	if err := s.db.WithContext(ctx).First(&cdnCluster, id).Error; err != nil {
 		return err
diff --git a/manager/service/config.go b/manager/service/config.go
index 35d073fd..d872c293 100644
--- a/manager/service/config.go
+++ b/manager/service/config.go
@@ -23,7 +23,7 @@ import (
 	"d7y.io/dragonfly/v2/manager/types"
 )
 
-func (s *rest) CreateConfig(ctx context.Context, json types.CreateConfigRequest) (*model.Config, error) {
+func (s *service) CreateConfig(ctx context.Context, json types.CreateConfigRequest) (*model.Config, error) {
 	config := model.Config{
 		Name:   json.Name,
 		Value:  json.Value,
@@ -38,7 +38,7 @@ func (s *rest) CreateConfig(ctx context.Context, json types.CreateConfigRequest)
 	return &config, nil
 }
 
-func (s *rest) DestroyConfig(ctx context.Context, id uint) error {
+func (s *service) DestroyConfig(ctx context.Context, id uint) error {
 	config := model.Config{}
 	if err := s.db.WithContext(ctx).First(&config, id).Error; err != nil {
 		return err
@@ -51,7 +51,7 @@ func (s *rest) DestroyConfig(ctx context.Context, id uint) error {
 	return nil
 }
 
-func (s *rest) UpdateConfig(ctx context.Context, id uint, json types.UpdateConfigRequest) (*model.Config, error) {
+func (s *service) UpdateConfig(ctx context.Context, id uint, json types.UpdateConfigRequest) (*model.Config, error) {
 	config := model.Config{}
 	if err := s.db.WithContext(ctx).First(&config, id).Updates(model.Config{
 		Name:   json.Name,
@@ -65,7 +65,7 @@ func (s *rest) UpdateConfig(ctx context.Context, id uint, json types.UpdateConfi
 	return &config, nil
 }
 
-func (s *rest) GetConfig(ctx context.Context, id uint) (*model.Config, error) {
+func (s *service) GetConfig(ctx context.Context, id uint) (*model.Config, error) {
 	config := model.Config{}
 	if err := s.db.WithContext(ctx).First(&config, id).Error; err != nil {
 		return nil, err
@@ -74,7 +74,7 @@ func (s *rest) GetConfig(ctx context.Context, id uint) (*model.Config, error) {
 	return &config, nil
 }
 
-func (s *rest) GetConfigs(ctx context.Context, q types.GetConfigsQuery) (*[]model.Config, int64, error) {
+func (s *service) GetConfigs(ctx context.Context, q types.GetConfigsQuery) (*[]model.Config, int64, error) {
 	var count int64
 	var configs []model.Config
 	if err := s.db.WithContext(ctx).Scopes(model.Paginate(q.Page, q.PerPage)).Where(&model.Config{
diff --git a/manager/service/job.go b/manager/service/job.go
index 245ddb2a..959cdeaf 100644
--- a/manager/service/job.go
+++ b/manager/service/job.go
@@ -29,7 +29,7 @@ import (
 	"d7y.io/dragonfly/v2/pkg/util/structutils"
 )
 
-func (s *rest) CreatePreheatJob(ctx context.Context, json types.CreatePreheatJobRequest) (*model.Job, error) {
+func (s *service) CreatePreheatJob(ctx context.Context, json types.CreatePreheatJobRequest) (*model.Job, error) {
 	var schedulers []model.Scheduler
 	var schedulerClusters []model.SchedulerCluster
 
@@ -97,7 +97,7 @@ func (s *rest) CreatePreheatJob(ctx context.Context, json types.CreatePreheatJob
 	return &job, nil
 }
 
-func (s *rest) pollingJob(ctx context.Context, id uint, taskID string) {
+func (s *service) pollingJob(ctx context.Context, id uint, taskID string) {
 	var job model.Job
 
 	if _, _, err := retry.Run(ctx, func() (interface{}, bool, error) {
@@ -140,7 +140,7 @@ func (s *rest) pollingJob(ctx context.Context, id uint, taskID string) {
 	}
 }
 
-func (s *rest) DestroyJob(ctx context.Context, id uint) error {
+func (s *service) DestroyJob(ctx context.Context, id uint) error {
 	job := model.Job{}
 	if err := s.db.WithContext(ctx).First(&job, id).Error; err != nil {
 		return err
@@ -153,7 +153,7 @@ func (s *rest) DestroyJob(ctx context.Context, id uint) error {
 	return nil
 }
 
-func (s *rest) UpdateJob(ctx context.Context, id uint, json types.UpdateJobRequest) (*model.Job, error) {
+func (s *service) UpdateJob(ctx context.Context, id uint, json types.UpdateJobRequest) (*model.Job, error) {
 	job := model.Job{}
 	if err := s.db.WithContext(ctx).Preload("CDNClusters").Preload("SchedulerClusters").First(&job, id).Updates(model.Job{
 		BIO:    json.BIO,
@@ -165,7 +165,7 @@ func (s *rest) UpdateJob(ctx context.Context, id uint, json types.UpdateJobReque
 	return &job, nil
 }
 
-func (s *rest) GetJob(ctx context.Context, id uint) (*model.Job, error) {
+func (s *service) GetJob(ctx context.Context, id uint) (*model.Job, error) {
 	job := model.Job{}
 	if err := s.db.WithContext(ctx).Preload("CDNClusters").Preload("SchedulerClusters").First(&job, id).Error; err != nil {
 		return nil, err
@@ -174,7 +174,7 @@ func (s *rest) GetJob(ctx context.Context, id uint) (*model.Job, error) {
 	return &job, nil
 }
 
-func (s *rest) GetJobs(ctx context.Context, q types.GetJobsQuery) (*[]model.Job, int64, error) {
+func (s *service) GetJobs(ctx context.Context, q types.GetJobsQuery) (*[]model.Job, int64, error) {
 	var count int64
 	var jobs []model.Job
 	if err := s.db.WithContext(ctx).Scopes(model.Paginate(q.Page, q.PerPage)).Where(&model.Job{
@@ -188,7 +188,7 @@ func (s *rest) GetJobs(ctx context.Context, q types.GetJobsQuery) (*[]model.Job,
 	return &jobs, count, nil
 }
 
-func (s *rest) AddJobToSchedulerClusters(ctx context.Context, id, schedulerClusterIDs []uint) error {
+func (s *service) AddJobToSchedulerClusters(ctx context.Context, id, schedulerClusterIDs []uint) error {
 	job := model.Job{}
 	if err := s.db.WithContext(ctx).First(&job, id).Error; err != nil {
 		return err
@@ -210,7 +210,7 @@ func (s *rest) AddJobToSchedulerClusters(ctx context.Context, id, schedulerClust
 	return nil
 }
 
-func (s *rest) AddJobToCDNClusters(ctx context.Context, id, cdnClusterIDs []uint) error {
+func (s *service) AddJobToCDNClusters(ctx context.Context, id, cdnClusterIDs []uint) error {
 	job := model.Job{}
 	if err := s.db.WithContext(ctx).First(&job, id).Error; err != nil {
 		return err
diff --git a/manager/service/oauth.go b/manager/service/oauth.go
index aa944a1d..33e20d63 100644
--- a/manager/service/oauth.go
+++ b/manager/service/oauth.go
@@ -23,7 +23,7 @@ import (
 	"d7y.io/dragonfly/v2/manager/types"
 )
 
-func (s *rest) CreateOauth(ctx context.Context, json types.CreateOauthRequest) (*model.Oauth, error) {
+func (s *service) CreateOauth(ctx context.Context, json types.CreateOauthRequest) (*model.Oauth, error) {
 	oauth := model.Oauth{
 		Name:         json.Name,
 		BIO:          json.BIO,
@@ -39,7 +39,7 @@ func (s *rest) CreateOauth(ctx context.Context, json types.CreateOauthRequest) (
 	return &oauth, nil
 }
 
-func (s *rest) DestroyOauth(ctx context.Context, id uint) error {
+func (s *service) DestroyOauth(ctx context.Context, id uint) error {
 	oauth := model.Oauth{}
 	if err := s.db.WithContext(ctx).First(&oauth, id).Error; err != nil {
 		return err
@@ -52,7 +52,7 @@ func (s *rest) DestroyOauth(ctx context.Context, id uint) error {
 	return nil
 }
 
-func (s *rest) UpdateOauth(ctx context.Context, id uint, json types.UpdateOauthRequest) (*model.Oauth, error) {
+func (s *service) UpdateOauth(ctx context.Context, id uint, json types.UpdateOauthRequest) (*model.Oauth, error) {
 	oauth := model.Oauth{}
 	if err := s.db.WithContext(ctx).First(&oauth, id).Updates(model.Oauth{
 		Name:         json.Name,
@@ -67,7 +67,7 @@ func (s *rest) UpdateOauth(ctx context.Context, id uint, json types.UpdateOauthR
 	return &oauth, nil
 }
 
-func (s *rest) GetOauth(ctx context.Context, id uint) (*model.Oauth, error) {
+func (s *service) GetOauth(ctx context.Context, id uint) (*model.Oauth, error) {
 	oauth := model.Oauth{}
 	if err := s.db.WithContext(ctx).First(&oauth, id).Error; err != nil {
 		return nil, err
@@ -76,7 +76,7 @@ func (s *rest) GetOauth(ctx context.Context, id uint) (*model.Oauth, error) {
 	return &oauth, nil
 }
 
-func (s *rest) GetOauths(ctx context.Context, q types.GetOauthsQuery) (*[]model.Oauth, int64, error) {
+func (s *service) GetOauths(ctx context.Context, q types.GetOauthsQuery) (*[]model.Oauth, int64, error) {
 	var count int64
 	var oauths []model.Oauth
 	if err := s.db.WithContext(ctx).Scopes(model.Paginate(q.Page, q.PerPage)).Where(&model.Oauth{
diff --git a/manager/service/permission.go b/manager/service/permission.go
index 7219b92a..8b6015e0 100644
--- a/manager/service/permission.go
+++ b/manager/service/permission.go
@@ -24,6 +24,6 @@ import (
 	"d7y.io/dragonfly/v2/manager/permission/rbac"
 )
 
-func (s *rest) GetPermissions(ctx context.Context, g *gin.Engine) []rbac.Permission {
+func (s *service) GetPermissions(ctx context.Context, g *gin.Engine) []rbac.Permission {
 	return rbac.GetPermissions(g)
 }
diff --git a/manager/service/preheat.go b/manager/service/preheat.go
index b17d102b..5cde547b 100644
--- a/manager/service/preheat.go
+++ b/manager/service/preheat.go
@@ -44,7 +44,7 @@ const (
 	V1PreheatingStateFail = "FAIL"
 )
 
-func (s *rest) CreateV1Preheat(ctx context.Context, json types.CreateV1PreheatRequest) (*types.CreateV1PreheatResponse, error) {
+func (s *service) CreateV1Preheat(ctx context.Context, json types.CreateV1PreheatRequest) (*types.CreateV1PreheatResponse, error) {
 	job, err := s.CreatePreheatJob(ctx, types.CreatePreheatJobRequest{
 		Type: internaljob.PreheatJob,
 		Args: types.PreheatArgs{
@@ -63,7 +63,7 @@ func (s *rest) CreateV1Preheat(ctx context.Context, json types.CreateV1PreheatRe
 	}, nil
 }
 
-func (s *rest) GetV1Preheat(ctx context.Context, rawID string) (*types.GetV1PreheatResponse, error) {
+func (s *service) GetV1Preheat(ctx context.Context, rawID string) (*types.GetV1PreheatResponse, error) {
 	id, err := strconv.ParseUint(rawID, 10, 32)
 	if err != nil {
 		logger.Errorf("preheat convert error", err)
diff --git a/manager/service/role.go b/manager/service/role.go
index e2ba5e14..1df80198 100644
--- a/manager/service/role.go
+++ b/manager/service/role.go
@@ -22,7 +22,7 @@ import (
 	"d7y.io/dragonfly/v2/manager/types"
 )
 
-func (s *rest) CreateRole(ctx context.Context, json types.CreateRoleRequest) error {
+func (s *service) CreateRole(ctx context.Context, json types.CreateRoleRequest) error {
 	for _, permission := range json.Permissions {
 		_, err := s.enforcer.AddPermissionForUser(json.Role, permission.Object, permission.Action)
 		if err != nil {
@@ -33,22 +33,22 @@ func (s *rest) CreateRole(ctx context.Context, json types.CreateRoleRequest) err
 	return nil
 }
 
-func (s *rest) DestroyRole(ctx context.Context, role string) (bool, error) {
+func (s *service) DestroyRole(ctx context.Context, role string) (bool, error) {
 	return s.enforcer.DeleteRole(role)
 }
 
-func (s *rest) GetRole(ctx context.Context, role string) [][]string {
+func (s *service) GetRole(ctx context.Context, role string) [][]string {
 	return s.enforcer.GetPermissionsForUser(role)
 }
 
-func (s *rest) GetRoles(ctx context.Context) []string {
+func (s *service) GetRoles(ctx context.Context) []string {
 	return s.enforcer.GetAllSubjects()
 }
 
-func (s *rest) AddPermissionForRole(ctx context.Context, role string, json types.AddPermissionForRoleRequest) (bool, error) {
+func (s *service) AddPermissionForRole(ctx context.Context, role string, json types.AddPermissionForRoleRequest) (bool, error) {
 	return s.enforcer.AddPermissionForUser(role, json.Object, json.Action)
 }
 
-func (s *rest) DeletePermissionForRole(ctx context.Context, role string, json types.DeletePermissionForRoleRequest) (bool, error) {
+func (s *service) DeletePermissionForRole(ctx context.Context, role string, json types.DeletePermissionForRoleRequest) (bool, error) {
 	return s.enforcer.DeletePermissionForUser(role, json.Object, json.Action)
 }
diff --git a/manager/service/scheduler.go b/manager/service/scheduler.go
index e87f4062..46d4cf3d 100644
--- a/manager/service/scheduler.go
+++ b/manager/service/scheduler.go
@@ -23,7 +23,7 @@ import (
 	"d7y.io/dragonfly/v2/manager/types"
 )
 
-func (s *rest) CreateScheduler(ctx context.Context, json types.CreateSchedulerRequest) (*model.Scheduler, error) {
+func (s *service) CreateScheduler(ctx context.Context, json types.CreateSchedulerRequest) (*model.Scheduler, error) {
 	scheduler := model.Scheduler{
 		HostName:           json.HostName,
 		VIPs:               json.VIPs,
@@ -42,7 +42,7 @@ func (s *rest) CreateScheduler(ctx context.Context, json types.CreateSchedulerRe
 	return &scheduler, nil
 }
 
-func (s *rest) DestroyScheduler(ctx context.Context, id uint) error {
+func (s *service) DestroyScheduler(ctx context.Context, id uint) error {
 	scheduler := model.Scheduler{}
 	if err := s.db.WithContext(ctx).First(&scheduler, id).Error; err != nil {
 		return err
@@ -55,7 +55,7 @@ func (s *rest) DestroyScheduler(ctx context.Context, id uint) error {
 	return nil
 }
 
-func (s *rest) UpdateScheduler(ctx context.Context, id uint, json types.UpdateSchedulerRequest) (*model.Scheduler, error) {
+func (s *service) UpdateScheduler(ctx context.Context, id uint, json types.UpdateSchedulerRequest) (*model.Scheduler, error) {
 	scheduler := model.Scheduler{}
 	if err := s.db.WithContext(ctx).First(&scheduler, id).Updates(model.Scheduler{
 		VIPs:               json.VIPs,
@@ -72,7 +72,7 @@ func (s *rest) UpdateScheduler(ctx context.Context, id uint, json types.UpdateSc
 	return &scheduler, nil
 }
 
-func (s *rest) GetScheduler(ctx context.Context, id uint) (*model.Scheduler, error) {
+func (s *service) GetScheduler(ctx context.Context, id uint) (*model.Scheduler, error) {
 	scheduler := model.Scheduler{}
 	if err := s.db.WithContext(ctx).First(&scheduler, id).Error; err != nil {
 		return nil, err
@@ -81,7 +81,7 @@ func (s *rest) GetScheduler(ctx context.Context, id uint) (*model.Scheduler, err
 	return &scheduler, nil
 }
 
-func (s *rest) GetSchedulers(ctx context.Context, q types.GetSchedulersQuery) (*[]model.Scheduler, int64, error) {
+func (s *service) GetSchedulers(ctx context.Context, q types.GetSchedulersQuery) (*[]model.Scheduler, int64, error) {
 	var count int64
 	var schedulers []model.Scheduler
 	if err := s.db.WithContext(ctx).Scopes(model.Paginate(q.Page, q.PerPage)).Where(&model.Scheduler{
diff --git a/manager/service/scheduler_cluster.go b/manager/service/scheduler_cluster.go
index 247ff31e..026fc6f1 100644
--- a/manager/service/scheduler_cluster.go
+++ b/manager/service/scheduler_cluster.go
@@ -24,7 +24,7 @@ import (
 	"d7y.io/dragonfly/v2/pkg/util/structutils"
 )
 
-func (s *rest) CreateSchedulerCluster(ctx context.Context, json types.CreateSchedulerClusterRequest) (*model.SchedulerCluster, error) {
+func (s *service) CreateSchedulerCluster(ctx context.Context, json types.CreateSchedulerClusterRequest) (*model.SchedulerCluster, error) {
 	config, err := structutils.StructToMap(json.Config)
 	if err != nil {
 		return nil, err
@@ -62,7 +62,7 @@ func (s *rest) CreateSchedulerCluster(ctx context.Context, json types.CreateSche
 	return &schedulerCluster, nil
 }
 
-func (s *rest) DestroySchedulerCluster(ctx context.Context, id uint) error {
+func (s *service) DestroySchedulerCluster(ctx context.Context, id uint) error {
 	schedulerCluster := model.SchedulerCluster{}
 	if err := s.db.WithContext(ctx).First(&schedulerCluster, id).Error; err != nil {
 		return err
@@ -75,7 +75,7 @@ func (s *rest) DestroySchedulerCluster(ctx context.Context, id uint) error {
 	return nil
 }
 
-func (s *rest) UpdateSchedulerCluster(ctx context.Context, id uint, json types.UpdateSchedulerClusterRequest) (*model.SchedulerCluster, error) {
+func (s *service) UpdateSchedulerCluster(ctx context.Context, id uint, json types.UpdateSchedulerClusterRequest) (*model.SchedulerCluster, error) {
 	config, err := structutils.StructToMap(json.Config)
 	if err != nil {
 		return nil, err
@@ -112,7 +112,7 @@ func (s *rest) UpdateSchedulerCluster(ctx context.Context, id uint, json types.U
 	return &schedulerCluster, nil
 }
 
-func (s *rest) GetSchedulerCluster(ctx context.Context, id uint) (*model.SchedulerCluster, error) {
+func (s *service) GetSchedulerCluster(ctx context.Context, id uint) (*model.SchedulerCluster, error) {
 	schedulerCluster := model.SchedulerCluster{}
 	if err := s.db.WithContext(ctx).Preload("CDNClusters").First(&schedulerCluster, id).Error; err != nil {
 		return nil, err
@@ -121,7 +121,7 @@ func (s *rest) GetSchedulerCluster(ctx context.Context, id uint) (*model.Schedul
 	return &schedulerCluster, nil
 }
 
-func (s *rest) GetSchedulerClusters(ctx context.Context, q types.GetSchedulerClustersQuery) (*[]model.SchedulerCluster, int64, error) {
+func (s *service) GetSchedulerClusters(ctx context.Context, q types.GetSchedulerClustersQuery) (*[]model.SchedulerCluster, int64, error) {
 	var count int64
 	var schedulerClusters []model.SchedulerCluster
 	if err := s.db.WithContext(ctx).Scopes(model.Paginate(q.Page, q.PerPage)).Where(&model.SchedulerCluster{
@@ -133,7 +133,7 @@ func (s *rest) GetSchedulerClusters(ctx context.Context, q types.GetSchedulerClu
 	return &schedulerClusters, count, nil
 }
 
-func (s *rest) AddSchedulerToSchedulerCluster(ctx context.Context, id, schedulerID uint) error {
+func (s *service) AddSchedulerToSchedulerCluster(ctx context.Context, id, schedulerID uint) error {
 	schedulerCluster := model.SchedulerCluster{}
 	if err := s.db.WithContext(ctx).First(&schedulerCluster, id).Error; err != nil {
 		return err
diff --git a/manager/service/security_group.go b/manager/service/security_group.go
index f0788b1e..dfd36a76 100644
--- a/manager/service/security_group.go
+++ b/manager/service/security_group.go
@@ -23,7 +23,7 @@ import (
 	"d7y.io/dragonfly/v2/manager/types"
 )
 
-func (s *rest) CreateSecurityGroup(ctx context.Context, json types.CreateSecurityGroupRequest) (*model.SecurityGroup, error) {
+func (s *service) CreateSecurityGroup(ctx context.Context, json types.CreateSecurityGroupRequest) (*model.SecurityGroup, error) {
 	securityGroup := model.SecurityGroup{
 		Name: json.Name,
 		BIO:  json.BIO,
@@ -36,7 +36,7 @@ func (s *rest) CreateSecurityGroup(ctx context.Context, json types.CreateSecurit
 	return &securityGroup, nil
 }
 
-func (s *rest) DestroySecurityGroup(ctx context.Context, id uint) error {
+func (s *service) DestroySecurityGroup(ctx context.Context, id uint) error {
 	securityGroup := model.SecurityGroup{}
 	if err := s.db.WithContext(ctx).First(&securityGroup, id).Error; err != nil {
 		return err
@@ -49,7 +49,7 @@ func (s *rest) DestroySecurityGroup(ctx context.Context, id uint) error {
 	return nil
 }
 
-func (s *rest) UpdateSecurityGroup(ctx context.Context, id uint, json types.UpdateSecurityGroupRequest) (*model.SecurityGroup, error) {
+func (s *service) UpdateSecurityGroup(ctx context.Context, id uint, json types.UpdateSecurityGroupRequest) (*model.SecurityGroup, error) {
 	securityGroup := model.SecurityGroup{}
 	if err := s.db.WithContext(ctx).First(&securityGroup, id).Updates(model.SecurityGroup{
 		Name: json.Name,
@@ -61,7 +61,7 @@ func (s *rest) UpdateSecurityGroup(ctx context.Context, id uint, json types.Upda
 	return &securityGroup, nil
 }
 
-func (s *rest) GetSecurityGroup(ctx context.Context, id uint) (*model.SecurityGroup, error) {
+func (s *service) GetSecurityGroup(ctx context.Context, id uint) (*model.SecurityGroup, error) {
 	securityGroup := model.SecurityGroup{}
 	if err := s.db.WithContext(ctx).Preload("SecurityRules").First(&securityGroup, id).Error; err != nil {
 		return nil, err
@@ -70,7 +70,7 @@ func (s *rest) GetSecurityGroup(ctx context.Context, id uint) (*model.SecurityGr
 	return &securityGroup, nil
 }
 
-func (s *rest) GetSecurityGroups(ctx context.Context, q types.GetSecurityGroupsQuery) (*[]model.SecurityGroup, int64, error) {
+func (s *service) GetSecurityGroups(ctx context.Context, q types.GetSecurityGroupsQuery) (*[]model.SecurityGroup, int64, error) {
 	var count int64
 	var securityGroups []model.SecurityGroup
 	if err := s.db.WithContext(ctx).Scopes(model.Paginate(q.Page, q.PerPage)).Where(&model.SecurityGroup{
@@ -82,7 +82,7 @@ func (s *rest) GetSecurityGroups(ctx context.Context, q types.GetSecurityGroupsQ
 	return &securityGroups, count, nil
 }
 
-func (s *rest) AddSchedulerClusterToSecurityGroup(ctx context.Context, id, schedulerClusterID uint) error {
+func (s *service) AddSchedulerClusterToSecurityGroup(ctx context.Context, id, schedulerClusterID uint) error {
 	securityGroup := model.SecurityGroup{}
 	if err := s.db.WithContext(ctx).First(&securityGroup, id).Error; err != nil {
 		return err
@@ -100,7 +100,7 @@ func (s *rest) AddSchedulerClusterToSecurityGroup(ctx context.Context, id, sched
 	return nil
 }
 
-func (s *rest) AddCDNClusterToSecurityGroup(ctx context.Context, id, cdnClusterID uint) error {
+func (s *service) AddCDNClusterToSecurityGroup(ctx context.Context, id, cdnClusterID uint) error {
 	securityGroup := model.SecurityGroup{}
 	if err := s.db.WithContext(ctx).First(&securityGroup, id).Error; err != nil {
 		return err
@@ -118,7 +118,7 @@ func (s *rest) AddCDNClusterToSecurityGroup(ctx context.Context, id, cdnClusterI
 	return nil
 }
 
-func (s *rest) AddSecurityRuleToSecurityGroup(ctx context.Context, id, securityRuleID uint) error {
+func (s *service) AddSecurityRuleToSecurityGroup(ctx context.Context, id, securityRuleID uint) error {
 	securityGroup := model.SecurityGroup{}
 	if err := s.db.WithContext(ctx).First(&securityGroup, id).Error; err != nil {
 		return err
@@ -136,7 +136,7 @@ func (s *rest) AddSecurityRuleToSecurityGroup(ctx context.Context, id, securityR
 	return nil
 }
 
-func (s *rest) DestroySecurityRuleToSecurityGroup(ctx context.Context, id, securityRuleID uint) error {
+func (s *service) DestroySecurityRuleToSecurityGroup(ctx context.Context, id, securityRuleID uint) error {
 	securityGroup := model.SecurityGroup{}
 	if err := s.db.WithContext(ctx).First(&securityGroup, id).Error; err != nil {
 		return err
diff --git a/manager/service/security_rule.go b/manager/service/security_rule.go
index 0cf8a6a1..473c1878 100644
--- a/manager/service/security_rule.go
+++ b/manager/service/security_rule.go
@@ -23,7 +23,7 @@ import (
 	"d7y.io/dragonfly/v2/manager/types"
 )
 
-func (s *rest) CreateSecurityRule(ctx context.Context, json types.CreateSecurityRuleRequest) (*model.SecurityRule, error) {
+func (s *service) CreateSecurityRule(ctx context.Context, json types.CreateSecurityRuleRequest) (*model.SecurityRule, error) {
 	securityRule := model.SecurityRule{
 		Name:        json.Name,
 		BIO:         json.BIO,
@@ -38,7 +38,7 @@ func (s *rest) CreateSecurityRule(ctx context.Context, json types.CreateSecurity
 	return &securityRule, nil
 }
 
-func (s *rest) DestroySecurityRule(ctx context.Context, id uint) error {
+func (s *service) DestroySecurityRule(ctx context.Context, id uint) error {
 	securityRule := model.SecurityRule{}
 	if err := s.db.WithContext(ctx).First(&securityRule, id).Error; err != nil {
 		return err
@@ -51,7 +51,7 @@ func (s *rest) DestroySecurityRule(ctx context.Context, id uint) error {
 	return nil
 }
 
-func (s *rest) UpdateSecurityRule(ctx context.Context, id uint, json types.UpdateSecurityRuleRequest) (*model.SecurityRule, error) {
+func (s *service) UpdateSecurityRule(ctx context.Context, id uint, json types.UpdateSecurityRuleRequest) (*model.SecurityRule, error) {
 	securityRule := model.SecurityRule{}
 	if err := s.db.WithContext(ctx).First(&securityRule, id).Updates(model.SecurityRule{
 		Name:        json.Name,
@@ -65,7 +65,7 @@ func (s *rest) UpdateSecurityRule(ctx context.Context, id uint, json types.Updat
 	return &securityRule, nil
 }
 
-func (s *rest) GetSecurityRule(ctx context.Context, id uint) (*model.SecurityRule, error) {
+func (s *service) GetSecurityRule(ctx context.Context, id uint) (*model.SecurityRule, error) {
 	securityRule := model.SecurityRule{}
 	if err := s.db.WithContext(ctx).First(&securityRule, id).Error; err != nil {
 		return nil, err
@@ -74,7 +74,7 @@ func (s *rest) GetSecurityRule(ctx context.Context, id uint) (*model.SecurityRul
 	return &securityRule, nil
 }
 
-func (s *rest) GetSecurityRules(ctx context.Context, q types.GetSecurityRulesQuery) (*[]model.SecurityRule, int64, error) {
+func (s *service) GetSecurityRules(ctx context.Context, q types.GetSecurityRulesQuery) (*[]model.SecurityRule, int64, error) {
 	var count int64
 	var securityRules []model.SecurityRule
 	if err := s.db.WithContext(ctx).Scopes(model.Paginate(q.Page, q.PerPage)).Where(&model.SecurityRule{
diff --git a/manager/service/service.go b/manager/service/service.go
index 8a773e7b..be905398 100644
--- a/manager/service/service.go
+++ b/manager/service/service.go
@@ -32,7 +32,8 @@ import (
 	"d7y.io/dragonfly/v2/manager/types"
 )
 
-type REST interface {
+type Service interface {
+	UpdateUser(context.Context, uint, types.UpdateUserRequest) (*model.User, error)
 	GetUser(context.Context, uint) (*model.User, error)
 	GetUsers(context.Context, types.GetUsersQuery) (*[]model.User, int64, error)
 	SignIn(context.Context, types.SignInRequest) (*model.User, error)
@@ -128,7 +129,7 @@ type REST interface {
 	DeleteCDNClusterToApplication(context.Context, uint, uint) error
 }
 
-type rest struct {
+type service struct {
 	db       *gorm.DB
 	rdb      *redis.Client
 	cache    *cache.Cache
@@ -137,8 +138,8 @@ type rest struct {
 }
 
 // NewREST returns a new REST instence
-func NewREST(database *database.Database, cache *cache.Cache, job *job.Job, enforcer *casbin.Enforcer) REST {
-	return &rest{
+func New(database *database.Database, cache *cache.Cache, job *job.Job, enforcer *casbin.Enforcer) Service {
+	return &service{
 		db:       database.DB,
 		rdb:      database.RDB,
 		cache:    cache,
diff --git a/manager/service/user.go b/manager/service/user.go
index f981911a..5e400d6d 100644
--- a/manager/service/user.go
+++ b/manager/service/user.go
@@ -31,7 +31,22 @@ import (
 	"d7y.io/dragonfly/v2/manager/types"
 )
 
-func (s *rest) GetUser(ctx context.Context, id uint) (*model.User, error) {
+func (s *service) UpdateUser(ctx context.Context, id uint, json types.UpdateUserRequest) (*model.User, error) {
+	user := model.User{}
+	if err := s.db.WithContext(ctx).First(&user, id).Updates(model.User{
+		Email:    json.Email,
+		Phone:    json.Phone,
+		Avatar:   json.Avatar,
+		Location: json.Location,
+		BIO:      json.BIO,
+	}).Error; err != nil {
+		return nil, err
+	}
+
+	return &user, nil
+}
+
+func (s *service) GetUser(ctx context.Context, id uint) (*model.User, error) {
 	user := model.User{}
 	if err := s.db.WithContext(ctx).First(&user, id).Error; err != nil {
 		return nil, err
@@ -40,7 +55,7 @@ func (s *rest) GetUser(ctx context.Context, id uint) (*model.User, error) {
 	return &user, nil
 }
 
-func (s *rest) GetUsers(ctx context.Context, q types.GetUsersQuery) (*[]model.User, int64, error) {
+func (s *service) GetUsers(ctx context.Context, q types.GetUsersQuery) (*[]model.User, int64, error) {
 	var count int64
 	var users []model.User
 	if err := s.db.WithContext(ctx).Scopes(model.Paginate(q.Page, q.PerPage)).Where(&model.User{
@@ -55,7 +70,7 @@ func (s *rest) GetUsers(ctx context.Context, q types.GetUsersQuery) (*[]model.Us
 	return &users, count, nil
 }
 
-func (s *rest) SignIn(ctx context.Context, json types.SignInRequest) (*model.User, error) {
+func (s *service) SignIn(ctx context.Context, json types.SignInRequest) (*model.User, error) {
 	user := model.User{}
 	if err := s.db.WithContext(ctx).First(&user, model.User{
 		Name: json.Name,
@@ -70,7 +85,7 @@ func (s *rest) SignIn(ctx context.Context, json types.SignInRequest) (*model.Use
 	return &user, nil
 }
 
-func (s *rest) ResetPassword(ctx context.Context, id uint, json types.ResetPasswordRequest) error {
+func (s *service) ResetPassword(ctx context.Context, id uint, json types.ResetPasswordRequest) error {
 	user := model.User{}
 	if err := s.db.WithContext(ctx).First(&user, id).Error; err != nil {
 		return err
@@ -94,7 +109,7 @@ func (s *rest) ResetPassword(ctx context.Context, id uint, json types.ResetPassw
 	return nil
 }
 
-func (s *rest) SignUp(ctx context.Context, json types.SignUpRequest) (*model.User, error) {
+func (s *service) SignUp(ctx context.Context, json types.SignUpRequest) (*model.User, error) {
 	encryptedPasswordBytes, err := bcrypt.GenerateFromPassword([]byte(json.Password), bcrypt.MinCost)
 	if err != nil {
 		return nil, err
@@ -122,7 +137,7 @@ func (s *rest) SignUp(ctx context.Context, json types.SignUpRequest) (*model.Use
 	return &user, nil
 }
 
-func (s *rest) OauthSignin(ctx context.Context, name string) (string, error) {
+func (s *service) OauthSignin(ctx context.Context, name string) (string, error) {
 	oauth := model.Oauth{}
 	if err := s.db.WithContext(ctx).First(&oauth, model.Oauth{Name: name}).Error; err != nil {
 		return "", err
@@ -136,7 +151,7 @@ func (s *rest) OauthSignin(ctx context.Context, name string) (string, error) {
 	return o.AuthCodeURL()
 }
 
-func (s *rest) OauthSigninCallback(ctx context.Context, name, code string) (*model.User, error) {
+func (s *service) OauthSigninCallback(ctx context.Context, name, code string) (*model.User, error) {
 	oauth := model.Oauth{}
 	if err := s.db.WithContext(ctx).First(&oauth, model.Oauth{Name: name}).Error; err != nil {
 		return nil, err
@@ -178,14 +193,14 @@ func (s *rest) OauthSigninCallback(ctx context.Context, name, code string) (*mod
 	return &user, nil
 }
 
-func (s *rest) GetRolesForUser(ctx context.Context, id uint) ([]string, error) {
+func (s *service) GetRolesForUser(ctx context.Context, id uint) ([]string, error) {
 	return s.enforcer.GetRolesForUser(fmt.Sprint(id))
 }
 
-func (s *rest) AddRoleForUser(ctx context.Context, json types.AddRoleForUserParams) (bool, error) {
+func (s *service) AddRoleForUser(ctx context.Context, json types.AddRoleForUserParams) (bool, error) {
 	return s.enforcer.AddRoleForUser(fmt.Sprint(json.ID), json.Role)
 }
 
-func (s *rest) DeleteRoleForUser(ctx context.Context, json types.DeleteRoleForUserParams) (bool, error) {
+func (s *service) DeleteRoleForUser(ctx context.Context, json types.DeleteRoleForUserParams) (bool, error) {
 	return s.enforcer.DeleteRoleForUser(fmt.Sprint(json.ID), json.Role)
 }
diff --git a/manager/types/user.go b/manager/types/user.go
index b4d47c74..6885f362 100644
--- a/manager/types/user.go
+++ b/manager/types/user.go
@@ -16,6 +16,14 @@
 
 package types
 
+type UpdateUserRequest struct {
+	Email    string `json:"email" binding:"omitempty"`
+	Phone    string `json:"phone" binding:"omitempty"`
+	Avatar   string `json:"avatar" binding:"omitempty"`
+	Location string `json:"location" binding:"omitempty"`
+	BIO      string `json:"bio" binding:"omitempty"`
+}
+
 type UserParams struct {
 	ID uint `uri:"id" binding:"required"`
 }
diff --git a/pkg/idgen/peer_id.go b/pkg/idgen/peer_id.go
index c3b37a67..50f02c59 100644
--- a/pkg/idgen/peer_id.go
+++ b/pkg/idgen/peer_id.go
@@ -23,10 +23,16 @@ import (
 	"github.com/google/uuid"
 )
 
+var pid int
+
+func init() {
+	pid = os.Getpid()
+}
+
 func CDNPeerID(ip string) string {
 	return fmt.Sprintf("%s_%s", PeerID(ip), "CDN")
 }
 
 func PeerID(ip string) string {
-	return fmt.Sprintf("%s-%d-%s", ip, os.Getpid(), uuid.New())
+	return fmt.Sprintf("%s-%d-%s", ip, pid, uuid.New())
 }
diff --git a/pkg/rpc/cdnsystem/client/client.go b/pkg/rpc/cdnsystem/client/client.go
index 8e688d40..5fe5af32 100644
--- a/pkg/rpc/cdnsystem/client/client.go
+++ b/pkg/rpc/cdnsystem/client/client.go
@@ -51,7 +51,7 @@ func GetElasticClientByAddrs(addrs []dfnet.NetAddr, opts ...grpc.DialOption) (Cd
 	once.Do(func() {
 		elasticCdnClient = &cdnClient{
 			rpc.NewConnection(context.Background(), "cdn-elastic", make([]dfnet.NetAddr, 0), []rpc.ConnOption{
-				rpc.WithConnExpireTime(30 * time.Second),
+				rpc.WithConnExpireTime(60 * time.Second),
 				rpc.WithDialOption(opts),
 			}),
 		}
diff --git a/pkg/rpc/client.go b/pkg/rpc/client.go
index 013766f5..87f788e8 100644
--- a/pkg/rpc/client.go
+++ b/pkg/rpc/client.go
@@ -26,6 +26,7 @@ import (
 	"github.com/serialx/hashring"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
+	"google.golang.org/grpc/credentials/insecure"
 	"google.golang.org/grpc/keepalive"
 	"google.golang.org/grpc/status"
 	"k8s.io/apimachinery/pkg/util/sets"
@@ -91,7 +92,7 @@ var defaultClientOpts = []grpc.DialOption{
 	grpc.WithBlock(),
 	grpc.WithDisableServiceConfig(),
 	grpc.WithInitialConnWindowSize(8 * 1024 * 1024),
-	grpc.WithInsecure(),
+	grpc.WithTransportCredentials(insecure.NewCredentials()),
 	grpc.WithKeepaliveParams(keepalive.ClientParameters{
 		Time:    20 * time.Second,
 		Timeout: 20 * time.Second,
diff --git a/pkg/rpc/client_util.go b/pkg/rpc/client_util.go
index a0135879..e3fb5463 100644
--- a/pkg/rpc/client_util.go
+++ b/pkg/rpc/client_util.go
@@ -22,7 +22,6 @@ import (
 	"time"
 
 	"go.opentelemetry.io/otel/attribute"
-	"go.opentelemetry.io/otel/semconv"
 	"go.opentelemetry.io/otel/trace"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/codes"
@@ -35,6 +34,15 @@ import (
 	"d7y.io/dragonfly/v2/pkg/util/mathutils"
 )
 
+const (
+	// Identifier of message transmitted or received.
+	RPCMessageIDKey = attribute.Key("message.id")
+
+	// The uncompressed size of the message transmitted or received in
+	// bytes.
+	RPCMessageUncompressedSizeKey = attribute.Key("message.uncompressed_size")
+)
+
 func (conn *Connection) startGC() {
 	// TODO 从hashing环中删除频繁失败的节点
 	logger.GrpcLogger.With("conn", conn.name).Debugf("start the gc connections job")
@@ -124,8 +132,8 @@ func (m messageType) Event(ctx context.Context, id int, message interface{}) {
 		content, _ := proto.Marshal(p)
 		span.AddEvent("message", trace.WithAttributes(
 			attribute.KeyValue(m),
-			semconv.RPCMessageIDKey.Int(id),
-			semconv.RPCMessageUncompressedSizeKey.String(string(content)),
+			RPCMessageIDKey.Int(id),
+			RPCMessageUncompressedSizeKey.String(string(content)),
 		))
 	}
 }
diff --git a/pkg/rpc/dfdaemon/client/client.go b/pkg/rpc/dfdaemon/client/client.go
index e04346cc..843719e7 100644
--- a/pkg/rpc/dfdaemon/client/client.go
+++ b/pkg/rpc/dfdaemon/client/client.go
@@ -57,7 +57,7 @@ func GetElasticClientByAddrs(addrs []dfnet.NetAddr, opts ...grpc.DialOption) (Da
 	once.Do(func() {
 		elasticDaemonClient = &daemonClient{
 			rpc.NewConnection(context.Background(), "daemon-elastic", make([]dfnet.NetAddr, 0), []rpc.ConnOption{
-				rpc.WithConnExpireTime(30 * time.Second),
+				rpc.WithConnExpireTime(60 * time.Second),
 				rpc.WithDialOption(opts),
 			}),
 		}
diff --git a/pkg/rpc/manager/client/client.go b/pkg/rpc/manager/client/client.go
index 947a79b6..e2e04167 100644
--- a/pkg/rpc/manager/client/client.go
+++ b/pkg/rpc/manager/client/client.go
@@ -26,6 +26,7 @@ import (
 	grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
 	"google.golang.org/grpc"
 	"google.golang.org/grpc/backoff"
+	"google.golang.org/grpc/credentials/insecure"
 
 	logger "d7y.io/dragonfly/v2/internal/dflog"
 	"d7y.io/dragonfly/v2/internal/dfnet"
@@ -69,7 +70,7 @@ type client struct {
 func New(target string) (Client, error) {
 	conn, err := grpc.Dial(
 		target,
-		grpc.WithInsecure(),
+		grpc.WithTransportCredentials(insecure.NewCredentials()),
 		grpc.WithBlock(),
 		grpc.WithConnectParams(grpc.ConnectParams{
 			Backoff: backoff.Config{
diff --git a/pkg/rpc/scheduler/client/client.go b/pkg/rpc/scheduler/client/client.go
index 2add25d5..c7b19d07 100644
--- a/pkg/rpc/scheduler/client/client.go
+++ b/pkg/rpc/scheduler/client/client.go
@@ -39,7 +39,7 @@ func GetClientByAddr(addrs []dfnet.NetAddr, opts ...grpc.DialOption) (SchedulerC
 	}
 	sc := &schedulerClient{
 		rpc.NewConnection(context.Background(), "scheduler-static", addrs, []rpc.ConnOption{
-			rpc.WithConnExpireTime(30 * time.Minute),
+			rpc.WithConnExpireTime(60 * time.Second),
 			rpc.WithDialOption(opts),
 		}),
 	}
diff --git a/pkg/rpc/scheduler/scheduler.pb.go b/pkg/rpc/scheduler/scheduler.pb.go
index 9f7f1df0..1e0f2590 100644
--- a/pkg/rpc/scheduler/scheduler.pb.go
+++ b/pkg/rpc/scheduler/scheduler.pb.go
@@ -910,165 +910,166 @@ var file_pkg_rpc_scheduler_scheduler_proto_rawDesc = []byte{
 	0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x17, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74,
 	0x65, 0x2f, 0x76, 0x61, 0x6c, 0x69, 0x64, 0x61, 0x74, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f,
 	0x1a, 0x1b, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
-	0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xfb, 0x01,
+	0x66, 0x2f, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x85, 0x02,
 	0x0a, 0x0f, 0x50, 0x65, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
 	0x74, 0x12, 0x1a, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08,
-	0xfa, 0x42, 0x05, 0x72, 0x03, 0x88, 0x01, 0x01, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x28, 0x0a,
+	0xfa, 0x42, 0x05, 0x72, 0x03, 0x88, 0x01, 0x01, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x32, 0x0a,
 	0x08, 0x75, 0x72, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32,
-	0x0d, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x55, 0x72, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x52, 0x07,
-	0x75, 0x72, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x12, 0x20, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f,
-	0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10,
-	0x01, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x09, 0x70, 0x65, 0x65,
-	0x72, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73,
-	0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x48, 0x6f, 0x73,
-	0x74, 0x52, 0x08, 0x70, 0x65, 0x65, 0x72, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x2b, 0x0a, 0x09, 0x68,
-	0x6f, 0x73, 0x74, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e,
-	0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x4c, 0x6f, 0x61, 0x64, 0x52, 0x08,
-	0x68, 0x6f, 0x73, 0x74, 0x4c, 0x6f, 0x61, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x73, 0x5f, 0x6d,
-	0x69, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b,
-	0x69, 0x73, 0x4d, 0x69, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x22, 0xe0, 0x01, 0x0a, 0x0e,
-	0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x20,
-	0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42,
-	0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64,
-	0x12, 0x38, 0x0a, 0x0a, 0x73, 0x69, 0x7a, 0x65, 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x03,
-	0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x53, 0x69, 0x7a, 0x65,
-	0x53, 0x63, 0x6f, 0x70, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52,
-	0x09, 0x73, 0x69, 0x7a, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x69,
-	0x6e, 0x67, 0x6c, 0x65, 0x5f, 0x70, 0x69, 0x65, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b,
-	0x32, 0x16, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x69, 0x6e,
-	0x67, 0x6c, 0x65, 0x50, 0x69, 0x65, 0x63, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x69, 0x6e, 0x67,
-	0x6c, 0x65, 0x50, 0x69, 0x65, 0x63, 0x65, 0x12, 0x25, 0x0a, 0x0d, 0x70, 0x69, 0x65, 0x63, 0x65,
-	0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00,
-	0x52, 0x0c, 0x70, 0x69, 0x65, 0x63, 0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x42, 0x0e,
-	0x0a, 0x0c, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x5f, 0x70, 0x69, 0x65, 0x63, 0x65, 0x22, 0x83,
-	0x01, 0x0a, 0x0b, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x50, 0x69, 0x65, 0x63, 0x65, 0x12, 0x20,
-	0x0a, 0x07, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42,
-	0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x06, 0x64, 0x73, 0x74, 0x50, 0x69, 0x64,
-	0x12, 0x22, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01,
-	0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x07, 0x64, 0x73, 0x74,
-	0x41, 0x64, 0x64, 0x72, 0x12, 0x2e, 0x0a, 0x0a, 0x70, 0x69, 0x65, 0x63, 0x65, 0x5f, 0x69, 0x6e,
-	0x66, 0x6f, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e,
-	0x50, 0x69, 0x65, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x70, 0x69, 0x65, 0x63, 0x65,
-	0x49, 0x6e, 0x66, 0x6f, 0x22, 0xb5, 0x02, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x48, 0x6f, 0x73,
-	0x74, 0x12, 0x1c, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42,
-	0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0xb0, 0x01, 0x01, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12,
-	0x17, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04,
-	0x72, 0x02, 0x70, 0x01, 0x52, 0x02, 0x69, 0x70, 0x12, 0x27, 0x0a, 0x08, 0x72, 0x70, 0x63, 0x5f,
-	0x70, 0x6f, 0x72, 0x74, 0x18, 0x03, 0x20, 0x01, 0x28, 0x05, 0x42, 0x0c, 0xfa, 0x42, 0x09, 0x1a,
-	0x07, 0x10, 0xff, 0xff, 0x03, 0x28, 0x80, 0x08, 0x52, 0x07, 0x72, 0x70, 0x63, 0x50, 0x6f, 0x72,
-	0x74, 0x12, 0x29, 0x0a, 0x09, 0x64, 0x6f, 0x77, 0x6e, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04,
+	0x0d, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x55, 0x72, 0x6c, 0x4d, 0x65, 0x74, 0x61, 0x42, 0x08,
+	0xfa, 0x42, 0x05, 0x8a, 0x01, 0x02, 0x10, 0x01, 0x52, 0x07, 0x75, 0x72, 0x6c, 0x4d, 0x65, 0x74,
+	0x61, 0x12, 0x20, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x06, 0x70, 0x65, 0x65,
+	0x72, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x09, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x68, 0x6f, 0x73, 0x74,
+	0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x13, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
+	0x65, 0x72, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x48, 0x6f, 0x73, 0x74, 0x52, 0x08, 0x70, 0x65, 0x65,
+	0x72, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x2b, 0x0a, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x6c, 0x6f,
+	0x61, 0x64, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e,
+	0x48, 0x6f, 0x73, 0x74, 0x4c, 0x6f, 0x61, 0x64, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x4c, 0x6f,
+	0x61, 0x64, 0x12, 0x21, 0x0a, 0x0c, 0x69, 0x73, 0x5f, 0x6d, 0x69, 0x67, 0x72, 0x61, 0x74, 0x69,
+	0x6e, 0x67, 0x18, 0x06, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x69, 0x73, 0x4d, 0x69, 0x67, 0x72,
+	0x61, 0x74, 0x69, 0x6e, 0x67, 0x22, 0xe0, 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74,
+	0x65, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x20, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b,
+	0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02,
+	0x10, 0x01, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x38, 0x0a, 0x0a, 0x73, 0x69,
+	0x7a, 0x65, 0x5f, 0x73, 0x63, 0x6f, 0x70, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0f,
+	0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x53, 0x69, 0x7a, 0x65, 0x53, 0x63, 0x6f, 0x70, 0x65, 0x42,
+	0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x09, 0x73, 0x69, 0x7a, 0x65, 0x53,
+	0x63, 0x6f, 0x70, 0x65, 0x12, 0x3b, 0x0a, 0x0c, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x5f, 0x70,
+	0x69, 0x65, 0x63, 0x65, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x16, 0x2e, 0x73, 0x63, 0x68,
+	0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x2e, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x50, 0x69, 0x65,
+	0x63, 0x65, 0x48, 0x00, 0x52, 0x0b, 0x73, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x50, 0x69, 0x65, 0x63,
+	0x65, 0x12, 0x25, 0x0a, 0x0d, 0x70, 0x69, 0x65, 0x63, 0x65, 0x5f, 0x63, 0x6f, 0x6e, 0x74, 0x65,
+	0x6e, 0x74, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x0c, 0x70, 0x69, 0x65, 0x63,
+	0x65, 0x43, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x42, 0x0e, 0x0a, 0x0c, 0x64, 0x69, 0x72, 0x65,
+	0x63, 0x74, 0x5f, 0x70, 0x69, 0x65, 0x63, 0x65, 0x22, 0x83, 0x01, 0x0a, 0x0b, 0x53, 0x69, 0x6e,
+	0x67, 0x6c, 0x65, 0x50, 0x69, 0x65, 0x63, 0x65, 0x12, 0x20, 0x0a, 0x07, 0x64, 0x73, 0x74, 0x5f,
+	0x70, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02,
+	0x10, 0x01, 0x52, 0x06, 0x64, 0x73, 0x74, 0x50, 0x69, 0x64, 0x12, 0x22, 0x0a, 0x08, 0x64, 0x73,
+	0x74, 0x5f, 0x61, 0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42,
+	0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x07, 0x64, 0x73, 0x74, 0x41, 0x64, 0x64, 0x72, 0x12, 0x2e,
+	0x0a, 0x0a, 0x70, 0x69, 0x65, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x03, 0x20, 0x01,
+	0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x50, 0x69, 0x65, 0x63, 0x65, 0x49,
+	0x6e, 0x66, 0x6f, 0x52, 0x09, 0x70, 0x69, 0x65, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x22, 0xb5,
+	0x02, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x1c, 0x0a, 0x04, 0x75,
+	0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03,
+	0xb0, 0x01, 0x01, 0x52, 0x04, 0x75, 0x75, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x02, 0x69, 0x70, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x70, 0x01, 0x52, 0x02,
+	0x69, 0x70, 0x12, 0x27, 0x0a, 0x08, 0x72, 0x70, 0x63, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03,
 	0x20, 0x01, 0x28, 0x05, 0x42, 0x0c, 0xfa, 0x42, 0x09, 0x1a, 0x07, 0x10, 0xff, 0xff, 0x03, 0x28,
-	0x80, 0x08, 0x52, 0x08, 0x64, 0x6f, 0x77, 0x6e, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x24, 0x0a, 0x09,
-	0x68, 0x6f, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42,
-	0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x68, 0x01, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x4e, 0x61,
-	0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x64,
-	0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x63,
-	0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6c,
-	0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c,
-	0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x63, 0x18, 0x08,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x69, 0x64, 0x63, 0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x65, 0x74,
-	0x5f, 0x74, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x0b, 0x6e, 0x65, 0x74, 0x54, 0x6f, 0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x22, 0xec, 0x02, 0x0a,
-	0x0b, 0x50, 0x69, 0x65, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x20, 0x0a, 0x07,
-	0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa,
-	0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x20,
-	0x0a, 0x07, 0x73, 0x72, 0x63, 0x5f, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42,
-	0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x06, 0x73, 0x72, 0x63, 0x50, 0x69, 0x64,
-	0x12, 0x17, 0x0a, 0x07, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x06, 0x64, 0x73, 0x74, 0x50, 0x69, 0x64, 0x12, 0x2e, 0x0a, 0x0a, 0x70, 0x69, 0x65,
-	0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e,
-	0x62, 0x61, 0x73, 0x65, 0x2e, 0x50, 0x69, 0x65, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09,
-	0x70, 0x69, 0x65, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x65, 0x67,
-	0x69, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62,
-	0x65, 0x67, 0x69, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f,
-	0x74, 0x69, 0x6d, 0x65, 0x18, 0x06, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x54,
-	0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x07,
-	0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x28, 0x0a,
-	0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x62, 0x61,
-	0x73, 0x65, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10,
-	0x01, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x2b, 0x0a, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x5f,
-	0x6c, 0x6f, 0x61, 0x64, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x62, 0x61, 0x73,
-	0x65, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x4c, 0x6f, 0x61, 0x64, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74,
-	0x4c, 0x6f, 0x61, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64,
-	0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x66, 0x69,
-	0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x98, 0x03, 0x0a, 0x0a,
-	0x50, 0x65, 0x65, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x12, 0x20, 0x0a, 0x07, 0x74, 0x61,
-	0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04,
-	0x72, 0x02, 0x10, 0x01, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x07,
-	0x73, 0x72, 0x63, 0x5f, 0x70, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa,
-	0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x06, 0x73, 0x72, 0x63, 0x50, 0x69, 0x64, 0x12, 0x2e,
-	0x0a, 0x0e, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74,
-	0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x1a, 0x02, 0x28, 0x01, 0x52,
-	0x0d, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x3b,
-	0x0a, 0x09, 0x6d, 0x61, 0x69, 0x6e, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28,
-	0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x2e, 0x50, 0x65,
-	0x65, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x50, 0x65, 0x65,
-	0x72, 0x52, 0x08, 0x6d, 0x61, 0x69, 0x6e, 0x50, 0x65, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x0b, 0x73,
-	0x74, 0x65, 0x61, 0x6c, 0x5f, 0x70, 0x65, 0x65, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b,
-	0x32, 0x1e, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x2e, 0x50, 0x65, 0x65,
-	0x72, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x50, 0x65, 0x65, 0x72,
-	0x52, 0x0a, 0x73, 0x74, 0x65, 0x61, 0x6c, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12, 0x28, 0x0a, 0x04,
-	0x63, 0x6f, 0x64, 0x65, 0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x62, 0x61, 0x73,
-	0x65, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01,
-	0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x1a, 0x6e, 0x0a, 0x08, 0x44, 0x65, 0x73, 0x74, 0x50, 0x65,
-	0x65, 0x72, 0x12, 0x17, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07,
-	0xfa, 0x42, 0x04, 0x72, 0x02, 0x70, 0x01, 0x52, 0x02, 0x69, 0x70, 0x12, 0x27, 0x0a, 0x08, 0x72,
-	0x70, 0x63, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x42, 0x0c, 0xfa,
-	0x42, 0x09, 0x1a, 0x07, 0x10, 0xff, 0xff, 0x03, 0x28, 0x80, 0x08, 0x52, 0x07, 0x72, 0x70, 0x63,
-	0x50, 0x6f, 0x72, 0x74, 0x12, 0x20, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18,
-	0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x06,
-	0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x22, 0x8c, 0x03, 0x0a, 0x0a, 0x50, 0x65, 0x65, 0x72, 0x52,
-	0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x20, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64,
-	0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52,
-	0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f,
-	0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10,
-	0x01, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x06, 0x73, 0x72, 0x63,
-	0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02,
-	0x70, 0x01, 0x52, 0x05, 0x73, 0x72, 0x63, 0x49, 0x70, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x63,
-	0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61,
-	0x69, 0x6e, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x03, 0x69, 0x64, 0x63, 0x12, 0x1a, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28,
-	0x09, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x72, 0x03, 0x88, 0x01, 0x01, 0x52, 0x03, 0x75, 0x72, 0x6c,
-	0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x65, 0x6e, 0x67,
-	0x74, 0x68, 0x18, 0x07, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e,
-	0x74, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x72, 0x61, 0x66, 0x66,
-	0x69, 0x63, 0x18, 0x08, 0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69,
-	0x63, 0x12, 0x12, 0x0a, 0x04, 0x63, 0x6f, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52,
-	0x04, 0x63, 0x6f, 0x73, 0x74, 0x12, 0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73,
-	0x18, 0x0a, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12,
-	0x28, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e,
-	0x62, 0x61, 0x73, 0x65, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01,
-	0x02, 0x10, 0x01, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x6f, 0x74,
-	0x61, 0x6c, 0x5f, 0x70, 0x69, 0x65, 0x63, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0c,
-	0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x69, 0x65, 0x63, 0x65,
-	0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x50, 0x0a, 0x0a, 0x50, 0x65, 0x65, 0x72, 0x54, 0x61, 0x72,
-	0x67, 0x65, 0x74, 0x12, 0x20, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01,
-	0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x06, 0x74,
-	0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64,
-	0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52,
-	0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x32, 0x9d, 0x02, 0x0a, 0x09, 0x53, 0x63, 0x68, 0x65,
-	0x64, 0x75, 0x6c, 0x65, 0x72, 0x12, 0x49, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65,
-	0x72, 0x50, 0x65, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x1a, 0x2e, 0x73, 0x63, 0x68, 0x65,
-	0x64, 0x75, 0x6c, 0x65, 0x72, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65,
-	0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x19, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65,
-	0x72, 0x2e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74,
-	0x12, 0x46, 0x0a, 0x11, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x69, 0x65, 0x63, 0x65, 0x52,
-	0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x16, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65,
-	0x72, 0x2e, 0x50, 0x69, 0x65, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, 0x15, 0x2e,
-	0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x50, 0x61,
-	0x63, 0x6b, 0x65, 0x74, 0x28, 0x01, 0x30, 0x01, 0x12, 0x41, 0x0a, 0x10, 0x52, 0x65, 0x70, 0x6f,
-	0x72, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x15, 0x2e, 0x73,
-	0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73,
-	0x75, 0x6c, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3a, 0x0a, 0x09, 0x4c,
-	0x65, 0x61, 0x76, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x12, 0x15, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64,
-	0x75, 0x6c, 0x65, 0x72, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x1a,
-	0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75,
-	0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x42, 0x27, 0x5a, 0x25, 0x64, 0x37, 0x79, 0x2e, 0x69,
-	0x6f, 0x2f, 0x64, 0x72, 0x61, 0x67, 0x6f, 0x6e, 0x66, 0x6c, 0x79, 0x2f, 0x76, 0x32, 0x2f, 0x70,
-	0x6b, 0x67, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72,
-	0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x80, 0x08, 0x52, 0x07, 0x72, 0x70, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x29, 0x0a, 0x09, 0x64,
+	0x6f, 0x77, 0x6e, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x42, 0x0c,
+	0xfa, 0x42, 0x09, 0x1a, 0x07, 0x10, 0xff, 0xff, 0x03, 0x28, 0x80, 0x08, 0x52, 0x08, 0x64, 0x6f,
+	0x77, 0x6e, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x24, 0x0a, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x6e,
+	0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02,
+	0x68, 0x01, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x27, 0x0a, 0x0f,
+	0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f, 0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18,
+	0x06, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44,
+	0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f,
+	0x6e, 0x18, 0x07, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f,
+	0x6e, 0x12, 0x10, 0x0a, 0x03, 0x69, 0x64, 0x63, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03,
+	0x69, 0x64, 0x63, 0x12, 0x21, 0x0a, 0x0c, 0x6e, 0x65, 0x74, 0x5f, 0x74, 0x6f, 0x70, 0x6f, 0x6c,
+	0x6f, 0x67, 0x79, 0x18, 0x09, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x6e, 0x65, 0x74, 0x54, 0x6f,
+	0x70, 0x6f, 0x6c, 0x6f, 0x67, 0x79, 0x22, 0xec, 0x02, 0x0a, 0x0b, 0x50, 0x69, 0x65, 0x63, 0x65,
+	0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x20, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69,
+	0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01,
+	0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x07, 0x73, 0x72, 0x63, 0x5f,
+	0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02,
+	0x10, 0x01, 0x52, 0x06, 0x73, 0x72, 0x63, 0x50, 0x69, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x64, 0x73,
+	0x74, 0x5f, 0x70, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x64, 0x73, 0x74,
+	0x50, 0x69, 0x64, 0x12, 0x2e, 0x0a, 0x0a, 0x70, 0x69, 0x65, 0x63, 0x65, 0x5f, 0x69, 0x6e, 0x66,
+	0x6f, 0x18, 0x04, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x0f, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x50,
+	0x69, 0x65, 0x63, 0x65, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x09, 0x70, 0x69, 0x65, 0x63, 0x65, 0x49,
+	0x6e, 0x66, 0x6f, 0x12, 0x1d, 0x0a, 0x0a, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x5f, 0x74, 0x69, 0x6d,
+	0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x04, 0x52, 0x09, 0x62, 0x65, 0x67, 0x69, 0x6e, 0x54, 0x69,
+	0x6d, 0x65, 0x12, 0x19, 0x0a, 0x08, 0x65, 0x6e, 0x64, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x06,
+	0x20, 0x01, 0x28, 0x04, 0x52, 0x07, 0x65, 0x6e, 0x64, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x18, 0x0a,
+	0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x07, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07,
+	0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x28, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18,
+	0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x43, 0x6f, 0x64,
+	0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x63, 0x6f, 0x64,
+	0x65, 0x12, 0x2b, 0x0a, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x6c, 0x6f, 0x61, 0x64, 0x18, 0x09,
+	0x20, 0x01, 0x28, 0x0b, 0x32, 0x0e, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x48, 0x6f, 0x73, 0x74,
+	0x4c, 0x6f, 0x61, 0x64, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x4c, 0x6f, 0x61, 0x64, 0x12, 0x25,
+	0x0a, 0x0e, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74,
+	0x18, 0x0a, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0d, 0x66, 0x69, 0x6e, 0x69, 0x73, 0x68, 0x65, 0x64,
+	0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22, 0x98, 0x03, 0x0a, 0x0a, 0x50, 0x65, 0x65, 0x72, 0x50, 0x61,
+	0x63, 0x6b, 0x65, 0x74, 0x12, 0x20, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x06,
+	0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x20, 0x0a, 0x07, 0x73, 0x72, 0x63, 0x5f, 0x70, 0x69,
+	0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01,
+	0x52, 0x06, 0x73, 0x72, 0x63, 0x50, 0x69, 0x64, 0x12, 0x2e, 0x0a, 0x0e, 0x70, 0x61, 0x72, 0x61,
+	0x6c, 0x6c, 0x65, 0x6c, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05,
+	0x42, 0x07, 0xfa, 0x42, 0x04, 0x1a, 0x02, 0x28, 0x01, 0x52, 0x0d, 0x70, 0x61, 0x72, 0x61, 0x6c,
+	0x6c, 0x65, 0x6c, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x12, 0x3b, 0x0a, 0x09, 0x6d, 0x61, 0x69, 0x6e,
+	0x5f, 0x70, 0x65, 0x65, 0x72, 0x18, 0x05, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x63,
+	0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x50, 0x61, 0x63, 0x6b,
+	0x65, 0x74, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, 0x08, 0x6d, 0x61, 0x69,
+	0x6e, 0x50, 0x65, 0x65, 0x72, 0x12, 0x3f, 0x0a, 0x0b, 0x73, 0x74, 0x65, 0x61, 0x6c, 0x5f, 0x70,
+	0x65, 0x65, 0x72, 0x73, 0x18, 0x06, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x73, 0x63, 0x68,
+	0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x65,
+	0x74, 0x2e, 0x44, 0x65, 0x73, 0x74, 0x50, 0x65, 0x65, 0x72, 0x52, 0x0a, 0x73, 0x74, 0x65, 0x61,
+	0x6c, 0x50, 0x65, 0x65, 0x72, 0x73, 0x12, 0x28, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x07,
+	0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x43, 0x6f, 0x64, 0x65,
+	0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65,
+	0x1a, 0x6e, 0x0a, 0x08, 0x44, 0x65, 0x73, 0x74, 0x50, 0x65, 0x65, 0x72, 0x12, 0x17, 0x0a, 0x02,
+	0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x70,
+	0x01, 0x52, 0x02, 0x69, 0x70, 0x12, 0x27, 0x0a, 0x08, 0x72, 0x70, 0x63, 0x5f, 0x70, 0x6f, 0x72,
+	0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x42, 0x0c, 0xfa, 0x42, 0x09, 0x1a, 0x07, 0x10, 0xff,
+	0xff, 0x03, 0x28, 0x80, 0x08, 0x52, 0x07, 0x72, 0x70, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x20,
+	0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42,
+	0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64,
+	0x22, 0x8c, 0x03, 0x0a, 0x0a, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12,
+	0x20, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49,
+	0x64, 0x12, 0x20, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
+	0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x06, 0x70, 0x65, 0x65,
+	0x72, 0x49, 0x64, 0x12, 0x1e, 0x0a, 0x06, 0x73, 0x72, 0x63, 0x5f, 0x69, 0x70, 0x18, 0x03, 0x20,
+	0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x70, 0x01, 0x52, 0x05, 0x73, 0x72,
+	0x63, 0x49, 0x70, 0x12, 0x27, 0x0a, 0x0f, 0x73, 0x65, 0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x5f,
+	0x64, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0e, 0x73, 0x65,
+	0x63, 0x75, 0x72, 0x69, 0x74, 0x79, 0x44, 0x6f, 0x6d, 0x61, 0x69, 0x6e, 0x12, 0x10, 0x0a, 0x03,
+	0x69, 0x64, 0x63, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x69, 0x64, 0x63, 0x12, 0x1a,
+	0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 0x42, 0x08, 0xfa, 0x42, 0x05,
+	0x72, 0x03, 0x88, 0x01, 0x01, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f,
+	0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x07, 0x20, 0x01,
+	0x28, 0x03, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x4c, 0x65, 0x6e, 0x67, 0x74,
+	0x68, 0x12, 0x18, 0x0a, 0x07, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x18, 0x08, 0x20, 0x01,
+	0x28, 0x04, 0x52, 0x07, 0x74, 0x72, 0x61, 0x66, 0x66, 0x69, 0x63, 0x12, 0x12, 0x0a, 0x04, 0x63,
+	0x6f, 0x73, 0x74, 0x18, 0x09, 0x20, 0x01, 0x28, 0x0d, 0x52, 0x04, 0x63, 0x6f, 0x73, 0x74, 0x12,
+	0x18, 0x0a, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x18, 0x0a, 0x20, 0x01, 0x28, 0x08,
+	0x52, 0x07, 0x73, 0x75, 0x63, 0x63, 0x65, 0x73, 0x73, 0x12, 0x28, 0x0a, 0x04, 0x63, 0x6f, 0x64,
+	0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x43,
+	0x6f, 0x64, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x04, 0x63,
+	0x6f, 0x64, 0x65, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x69, 0x65,
+	0x63, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x0c, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f,
+	0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x69, 0x65, 0x63, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x22,
+	0x50, 0x0a, 0x0a, 0x50, 0x65, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x20, 0x0a,
+	0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07,
+	0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12,
+	0x20, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
+	0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x10, 0x01, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49,
+	0x64, 0x32, 0x9d, 0x02, 0x0a, 0x09, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x12,
+	0x49, 0x0a, 0x10, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x50, 0x65, 0x65, 0x72, 0x54,
+	0x61, 0x73, 0x6b, 0x12, 0x1a, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x2e,
+	0x50, 0x65, 0x65, 0x72, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a,
+	0x19, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x2e, 0x52, 0x65, 0x67, 0x69,
+	0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x46, 0x0a, 0x11, 0x52, 0x65,
+	0x70, 0x6f, 0x72, 0x74, 0x50, 0x69, 0x65, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12,
+	0x16, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x2e, 0x50, 0x69, 0x65, 0x63,
+	0x65, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, 0x15, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75,
+	0x6c, 0x65, 0x72, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 0x28, 0x01,
+	0x30, 0x01, 0x12, 0x41, 0x0a, 0x10, 0x52, 0x65, 0x70, 0x6f, 0x72, 0x74, 0x50, 0x65, 0x65, 0x72,
+	0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x15, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
+	0x65, 0x72, 0x2e, 0x50, 0x65, 0x65, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x1a, 0x16, 0x2e,
+	0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e,
+	0x45, 0x6d, 0x70, 0x74, 0x79, 0x12, 0x3a, 0x0a, 0x09, 0x4c, 0x65, 0x61, 0x76, 0x65, 0x54, 0x61,
+	0x73, 0x6b, 0x12, 0x15, 0x2e, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x2e, 0x50,
+	0x65, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x1a, 0x16, 0x2e, 0x67, 0x6f, 0x6f, 0x67,
+	0x6c, 0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74,
+	0x79, 0x42, 0x27, 0x5a, 0x25, 0x64, 0x37, 0x79, 0x2e, 0x69, 0x6f, 0x2f, 0x64, 0x72, 0x61, 0x67,
+	0x6f, 0x6e, 0x66, 0x6c, 0x79, 0x2f, 0x76, 0x32, 0x2f, 0x70, 0x6b, 0x67, 0x2f, 0x72, 0x70, 0x63,
+	0x2f, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74,
+	0x6f, 0x33,
 }
 
 var (
diff --git a/pkg/rpc/scheduler/scheduler.pb.validate.go b/pkg/rpc/scheduler/scheduler.pb.validate.go
index 46fa68ec..fcc67dba 100644
--- a/pkg/rpc/scheduler/scheduler.pb.validate.go
+++ b/pkg/rpc/scheduler/scheduler.pb.validate.go
@@ -67,6 +67,13 @@ func (m *PeerTaskRequest) Validate() error {
 		}
 	}
 
+	if m.GetUrlMeta() == nil {
+		return PeerTaskRequestValidationError{
+			field:  "UrlMeta",
+			reason: "value is required",
+		}
+	}
+
 	if v, ok := interface{}(m.GetUrlMeta()).(interface{ Validate() error }); ok {
 		if err := v.Validate(); err != nil {
 			return PeerTaskRequestValidationError{
diff --git a/pkg/rpc/scheduler/scheduler.proto b/pkg/rpc/scheduler/scheduler.proto
index 366c74b0..fed2c389 100644
--- a/pkg/rpc/scheduler/scheduler.proto
+++ b/pkg/rpc/scheduler/scheduler.proto
@@ -28,7 +28,7 @@ message PeerTaskRequest{
   // universal resource locator for different kind of storage
   string url = 1 [(validate.rules).string.uri = true];
   // url meta info
-  base.UrlMeta url_meta = 2;
+  base.UrlMeta url_meta = 2 [(validate.rules).message.required = true];
   // peer's id and must be global uniqueness
   string peer_id = 3 [(validate.rules).string.min_len = 1];
   // peer host info
diff --git a/pkg/source/httpprotocol/http_source_client.go b/pkg/source/httpprotocol/http_source_client.go
index 2a6cb3c4..6dfac626 100644
--- a/pkg/source/httpprotocol/http_source_client.go
+++ b/pkg/source/httpprotocol/http_source_client.go
@@ -196,6 +196,9 @@ func (client *httpSourceClient) Download(request *source.Request) (*source.Respo
 				ETag:         resp.Header.Get(headers.ETag),
 			},
 		))
+	if resp.ContentLength > 0 {
+		response.ContentLength = resp.ContentLength
+	}
 	return response, nil
 }
 
diff --git a/scheduler/config/config.go b/scheduler/config/config.go
index 644ab254..1a3a98d3 100644
--- a/scheduler/config/config.go
+++ b/scheduler/config/config.go
@@ -67,8 +67,8 @@ func New() *Config {
 			Algorithm:            "default",
 			BackSourceCount:      3,
 			RetryBackSourceLimit: 5,
-			RetryLimit:           20,
-			RetryInterval:        200 * time.Millisecond,
+			RetryLimit:           10,
+			RetryInterval:        50 * time.Millisecond,
 			GC: &GCConfig{
 				PeerGCInterval: 10 * time.Minute,
 				PeerTTL:        24 * time.Hour,
diff --git a/scheduler/config/dynconfig.go b/scheduler/config/dynconfig.go
index 95c5184d..abdd1b5a 100644
--- a/scheduler/config/dynconfig.go
+++ b/scheduler/config/dynconfig.go
@@ -214,6 +214,7 @@ func (d *dynconfig) Get() (*DynconfigData, error) {
 	if err := d.Unmarshal(&config); err != nil {
 		return nil, err
 	}
+
 	return &config, nil
 }
 
diff --git a/scheduler/metrics/metrics.go b/scheduler/metrics/metrics.go
index beef3150..043d45d4 100644
--- a/scheduler/metrics/metrics.go
+++ b/scheduler/metrics/metrics.go
@@ -29,64 +29,92 @@ import (
 	"d7y.io/dragonfly/v2/scheduler/config"
 )
 
+var (
+	// TrafficP2PType is p2p type for traffic metrics
+	TrafficP2PType = "p2p"
+
+	// TrafficBackToSourceType is back-to-source type for traffic metrics
+	TrafficBackToSourceType = "back_to_source"
+
+	// PeerHostTrafficUploadType is upload traffic type for peer host traffic metrics
+	PeerHostTrafficUploadType = "upload"
+
+	// PeerHostTrafficDownloadType is download traffic type for peer host traffic metrics
+	PeerHostTrafficDownloadType = "download"
+)
+
 // Variables declared for metrics.
 var (
-	RegisterPeerTaskCount = promauto.NewCounter(prometheus.CounterOpts{
+	RegisterPeerTaskCount = promauto.NewCounterVec(prometheus.CounterOpts{
 		Namespace: constants.MetricsNamespace,
 		Subsystem: constants.SchedulerMetricsName,
 		Name:      "register_peer_task_total",
 		Help:      "Counter of the number of the register peer task.",
-	})
+	}, []string{"biz_tag"})
 
-	RegisterPeerTaskFailureCount = promauto.NewCounter(prometheus.CounterOpts{
+	RegisterPeerTaskFailureCount = promauto.NewCounterVec(prometheus.CounterOpts{
 		Namespace: constants.MetricsNamespace,
 		Subsystem: constants.SchedulerMetricsName,
 		Name:      "register_peer_task_failure_total",
 		Help:      "Counter of the number of failed of the register peer task.",
-	})
+	}, []string{"biz_tag"})
 
-	DownloadCount = promauto.NewCounter(prometheus.CounterOpts{
+	DownloadCount = promauto.NewCounterVec(prometheus.CounterOpts{
 		Namespace: constants.MetricsNamespace,
 		Subsystem: constants.SchedulerMetricsName,
 		Name:      "download_total",
 		Help:      "Counter of the number of the downloading.",
-	})
+	}, []string{"biz_tag"})
 
-	DownloadFailureCount = promauto.NewCounter(prometheus.CounterOpts{
+	DownloadFailureCount = promauto.NewCounterVec(prometheus.CounterOpts{
 		Namespace: constants.MetricsNamespace,
 		Subsystem: constants.SchedulerMetricsName,
 		Name:      "download_failure_total",
 		Help:      "Counter of the number of failed of the downloading.",
-	})
+	}, []string{"biz_tag"})
 
-	P2PTraffic = promauto.NewCounter(prometheus.CounterOpts{
+	LeaveTaskCount = promauto.NewCounterVec(prometheus.CounterOpts{
 		Namespace: constants.MetricsNamespace,
 		Subsystem: constants.SchedulerMetricsName,
-		Name:      "p2p_traffic",
-		Help:      "Counter of the number of p2p traffic.",
-	})
+		Name:      "leave_task_total",
+		Help:      "Counter of the number of the leaving task.",
+	}, []string{"biz_tag"})
+
+	LeaveTaskFailureCount = promauto.NewCounterVec(prometheus.CounterOpts{
+		Namespace: constants.MetricsNamespace,
+		Subsystem: constants.SchedulerMetricsName,
+		Name:      "leave_task_failure_total",
+		Help:      "Counter of the number of failed of the leaving task.",
+	}, []string{"biz_tag"})
+
+	Traffic = promauto.NewCounterVec(prometheus.CounterOpts{
+		Namespace: constants.MetricsNamespace,
+		Subsystem: constants.SchedulerMetricsName,
+		Name:      "traffic",
+		Help:      "Counter of the number of traffic.",
+	}, []string{"biz_tag", "type"})
 
 	PeerHostTraffic = promauto.NewCounterVec(prometheus.CounterOpts{
 		Namespace: constants.MetricsNamespace,
 		Subsystem: constants.SchedulerMetricsName,
 		Name:      "peer_host_traffic",
 		Help:      "Counter of the number of per peer host traffic.",
-	}, []string{"traffic_type", "peer_host_uuid", "peer_host_ip"})
+	}, []string{"biz_tag", "traffic_type", "peer_host_uuid", "peer_host_ip"})
 
 	PeerTaskCounter = promauto.NewCounterVec(prometheus.CounterOpts{
 		Namespace: constants.MetricsNamespace,
 		Subsystem: constants.SchedulerMetricsName,
 		Name:      "peer_task_total",
 		Help:      "Counter of the number of peer task.",
-	}, []string{"type"})
+	}, []string{"biz_tag", "type"})
 
-	PeerTaskDownloadDuration = promauto.NewHistogram(prometheus.HistogramOpts{
+	PeerTaskDownloadDuration = promauto.NewHistogramVec(prometheus.HistogramOpts{
 		Namespace: constants.MetricsNamespace,
 		Subsystem: constants.SchedulerMetricsName,
 		Name:      "peer_task_download_duration_milliseconds",
 		Help:      "Histogram of the time each peer task downloading.",
 		Buckets:   []float64{100, 200, 500, 1000, 1500, 2 * 1000, 3 * 1000, 5 * 1000, 10 * 1000, 20 * 1000, 60 * 1000, 120 * 1000, 300 * 1000},
-	})
+	}, []string{"biz_tag"})
 
 	ConcurrentScheduleGauge = promauto.NewGauge(prometheus.GaugeOpts{
 		Namespace: constants.MetricsNamespace,
diff --git a/scheduler/resource/cdn.go b/scheduler/resource/cdn.go
index 2b324921..7a169055 100644
--- a/scheduler/resource/cdn.go
+++ b/scheduler/resource/cdn.go
@@ -37,6 +37,11 @@ import (
 	"d7y.io/dragonfly/v2/scheduler/config"
 )
 
+const (
+	// Default value of biz tag for cdn peer
+	cdnBizTag = "d7y/cdn"
+)
+
 type CDN interface {
 	// TriggerTask start to trigger cdn task
 	TriggerTask(context.Context, *Task) (*Peer, *rpcscheduler.PeerResult, error)
@@ -146,7 +151,7 @@ func (c *cdn) initPeer(task *Task, ps *cdnsystem.PieceSeed) (*Peer, error) {
 	}
 
 	// New cdn peer
-	peer = NewPeer(ps.PeerId, task, host)
+	peer = NewPeer(ps.PeerId, task, host, WithBizTag(cdnBizTag))
 	peer.Log.Info("new cdn peer successfully")
 
 	// Store cdn peer
@@ -254,7 +259,7 @@ func cdnsToHosts(cdns []*config.CDN) map[string]*Host {
 	for _, cdn := range cdns {
 		var netTopology string
 		options := []HostOption{WithIsCDN(true)}
-		if config, ok := cdn.GetCDNClusterConfig(); ok {
+		if config, ok := cdn.GetCDNClusterConfig(); ok && config.LoadLimit > 0 {
 			options = append(options, WithUploadLoadLimit(int32(config.LoadLimit)))
 			netTopology = config.NetTopology
 		}
diff --git a/scheduler/resource/host.go b/scheduler/resource/host.go
index b374a992..3607f9b6 100644
--- a/scheduler/resource/host.go
+++ b/scheduler/resource/host.go
@@ -23,14 +23,10 @@ import (
 	"go.uber.org/atomic"
 
 	logger "d7y.io/dragonfly/v2/internal/dflog"
+	"d7y.io/dragonfly/v2/manager/database"
 	"d7y.io/dragonfly/v2/pkg/rpc/scheduler"
 )
 
-const (
-	// Host default upload load limit
-	defaultUploadLoadLimit = 100
-)
-
 // HostOption is a functional option for configuring the host
 type HostOption func(h *Host) *Host
 
@@ -114,7 +110,7 @@ func NewHost(rawHost *scheduler.PeerHost, options ...HostOption) *Host {
 		IDC:             rawHost.Idc,
 		NetTopology:     rawHost.NetTopology,
 		Location:        rawHost.Location,
-		UploadLoadLimit: atomic.NewInt32(defaultUploadLoadLimit),
+		UploadLoadLimit: atomic.NewInt32(database.DefaultClientLoadLimit),
 		Peers:           &sync.Map{},
 		PeerCount:       atomic.NewInt32(0),
 		IsCDN:           false,
diff --git a/scheduler/resource/peer.go b/scheduler/resource/peer.go
index e414b195..2e726b1b 100644
--- a/scheduler/resource/peer.go
+++ b/scheduler/resource/peer.go
@@ -37,6 +37,9 @@ import (
 const (
 	// Download tiny file timeout
 	downloadTinyFileContextTimeout = 2 * time.Minute
+
+	// Default value of biz tag
+	defaultBizTag = "unknow"
 )
 
 const (
@@ -94,10 +97,24 @@ const (
 	PeerEventLeave = "Leave"
 )
 
+// PeerOption is a functional option for configuring the peer
+type PeerOption func(p *Peer) *Peer
+
+// WithBizTag sets peer's BizTag
+func WithBizTag(bizTag string) PeerOption {
+	return func(p *Peer) *Peer {
+		p.BizTag = bizTag
+		return p
+	}
+}
+
 type Peer struct {
 	// ID is peer id
 	ID string
 
+	// BizTag is peer biz tag
+	BizTag string
+
 	// Pieces is piece bitset
 	Pieces *bitset.BitSet
 
@@ -139,9 +156,10 @@ type Peer struct {
 }
 
 // New Peer instance
-func NewPeer(id string, task *Task, host *Host) *Peer {
+func NewPeer(id string, task *Task, host *Host, options ...PeerOption) *Peer {
 	p := &Peer{
 		ID:         id,
+		BizTag:     defaultBizTag,
 		Pieces:     &bitset.BitSet{},
 		pieceCosts: []int64{},
 		Stream:     &atomic.Value{},
@@ -165,7 +183,12 @@ func NewPeer(id string, task *Task, host *Host) *Peer {
 			{Name: PeerEventRegisterNormal, Src: []string{PeerStatePending}, Dst: PeerStateReceivedNormal},
 			{Name: PeerEventDownload, Src: []string{PeerStateReceivedTiny, PeerStateReceivedSmall, PeerStateReceivedNormal}, Dst: PeerStateRunning},
 			{Name: PeerEventDownloadFromBackToSource, Src: []string{PeerStateReceivedTiny, PeerStateReceivedSmall, PeerStateReceivedNormal, PeerStateRunning}, Dst: PeerStateBackToSource},
-			{Name: PeerEventDownloadSucceeded, Src: []string{PeerStateRunning, PeerStateBackToSource}, Dst: PeerStateSucceeded},
+			{Name: PeerEventDownloadSucceeded, Src: []string{
+				// Since ReportPeerResult and ReportPieceResult are called in no order,
+				// the result may be reported after the register is successful.
+				PeerStateReceivedTiny, PeerStateReceivedSmall, PeerStateReceivedNormal,
+				PeerStateRunning, PeerStateBackToSource,
+			}, Dst: PeerStateSucceeded},
 			{Name: PeerEventDownloadFailed, Src: []string{
 				PeerStatePending, PeerStateReceivedTiny, PeerStateReceivedSmall, PeerStateReceivedNormal,
 				PeerStateRunning, PeerStateBackToSource, PeerStateSucceeded,
@@ -192,6 +215,7 @@ func NewPeer(id string, task *Task, host *Host) *Peer {
 			PeerEventDownloadFromBackToSource: func(e *fsm.Event) {
 				p.Task.BackToSourcePeers.Add(p)
 				p.DeleteParent()
+				p.Host.DeletePeer(p.ID)
 				p.UpdateAt.Store(time.Now())
 				p.Log.Infof("peer state is %s", e.FSM.Current())
 			},
@@ -201,6 +225,7 @@ func NewPeer(id string, task *Task, host *Host) *Peer {
 				}
 
 				p.DeleteParent()
+				p.Host.DeletePeer(p.ID)
 				p.UpdateAt.Store(time.Now())
 				p.Log.Infof("peer state is %s", e.FSM.Current())
 			},
@@ -210,16 +235,22 @@ func NewPeer(id string, task *Task, host *Host) *Peer {
 				}
 
 				p.DeleteParent()
+				p.Host.DeletePeer(p.ID)
 				p.UpdateAt.Store(time.Now())
 				p.Log.Infof("peer state is %s", e.FSM.Current())
 			},
 			PeerEventLeave: func(e *fsm.Event) {
 				p.DeleteParent()
+				p.Host.DeletePeer(p.ID)
 				p.Log.Infof("peer state is %s", e.FSM.Current())
 			},
 		},
 	)
 
+	for _, opt := range options {
+		opt(p)
+	}
+
 	return p
 }
 
diff --git a/scheduler/rpcserver/rpcserver.go b/scheduler/rpcserver/rpcserver.go
index 3ff73a95..e48bc6a9 100644
--- a/scheduler/rpcserver/rpcserver.go
+++ b/scheduler/rpcserver/rpcserver.go
@@ -47,13 +47,13 @@ func New(service *service.Service, opts ...grpc.ServerOption) *grpc.Server {
 
 // RegisterPeerTask registers peer and triggers CDN download task
 func (s *Server) RegisterPeerTask(ctx context.Context, req *scheduler.PeerTaskRequest) (*scheduler.RegisterResult, error) {
-	metrics.RegisterPeerTaskCount.Inc()
+	metrics.RegisterPeerTaskCount.WithLabelValues(req.UrlMeta.Tag).Inc()
 
 	resp, err := s.service.RegisterPeerTask(ctx, req)
 	if err != nil {
-		metrics.RegisterPeerTaskFailureCount.Inc()
+		metrics.RegisterPeerTaskFailureCount.WithLabelValues(req.UrlMeta.Tag).Inc()
 	} else {
-		metrics.PeerTaskCounter.WithLabelValues(resp.SizeScope.String()).Inc()
+		metrics.PeerTaskCounter.WithLabelValues(req.UrlMeta.Tag, resp.SizeScope.String()).Inc()
 	}
 
 	return resp, err
@@ -69,14 +69,6 @@ func (s *Server) ReportPieceResult(stream scheduler.Scheduler_ReportPieceResultS
 
 // ReportPeerResult handles peer result reported by dfdaemon
 func (s *Server) ReportPeerResult(ctx context.Context, req *scheduler.PeerResult) (*empty.Empty, error) {
-	metrics.DownloadCount.Inc()
-	if req.Success {
-		metrics.P2PTraffic.Add(float64(req.Traffic))
-		metrics.PeerTaskDownloadDuration.Observe(float64(req.Cost))
-	} else {
-		metrics.DownloadFailureCount.Inc()
-	}
-
 	return new(empty.Empty), s.service.ReportPeerResult(ctx, req)
 }
 
diff --git a/scheduler/scheduler.go b/scheduler/scheduler.go
index b2a570fd..20fa4760 100644
--- a/scheduler/scheduler.go
+++ b/scheduler/scheduler.go
@@ -41,6 +41,8 @@ import (
 )
 
 const (
+	// gracefulStopTimeout specifies a time limit for
+	// grpc server to complete a graceful shutdown
 	gracefulStopTimeout = 10 * time.Second
 )
 
diff --git a/scheduler/scheduler/scheduler.go b/scheduler/scheduler/scheduler.go
index c320f0f5..9af5305f 100644
--- a/scheduler/scheduler/scheduler.go
+++ b/scheduler/scheduler/scheduler.go
@@ -23,6 +23,7 @@ import (
 	"sort"
 	"time"
 
+	"d7y.io/dragonfly/v2/manager/database"
 	"d7y.io/dragonfly/v2/pkg/container/set"
 	"d7y.io/dragonfly/v2/pkg/rpc/base"
 	rpcscheduler "d7y.io/dragonfly/v2/pkg/rpc/scheduler"
@@ -32,9 +33,6 @@ import (
 )
 
 const (
-	// Default number of pieces downloaded in parallel
-	defaultParallelCount = 4
-
 	// Default limit the number of filter traversals
 	defaultFilterParentLimit = 10
 
@@ -120,8 +118,6 @@ func (s *scheduler) ScheduleParent(ctx context.Context, peer *resource.Peer, blo
 				}
 			}
 
-			// If the peer downloads back-to-source, its parent needs to be deleted
-			peer.DeleteParent()
 			return
 		}
 
@@ -281,7 +277,8 @@ func (s *scheduler) filterParents(peer *resource.Peer, blocklist set.SafeSet) []
 		}
 
 		if parent.Host.FreeUploadLoad() <= 0 {
-			peer.Log.Debugf("parent %s is not selected because its free upload is empty", parent.ID)
+			peer.Log.Debugf("parent %s is not selected because its free upload is empty, upload limit is %d, peer count is %d",
+				parent.ID, parent.Host.UploadLoadLimit.Load(), parent.Host.PeerCount.Load())
 			return true
 		}
 
@@ -296,7 +293,7 @@ func (s *scheduler) filterParents(peer *resource.Peer, blocklist set.SafeSet) []
 
 // Construct peer successful packet
 func constructSuccessPeerPacket(dynconfig config.DynconfigInterface, peer *resource.Peer, parent *resource.Peer, candidateParents []*resource.Peer) *rpcscheduler.PeerPacket {
-	parallelCount := defaultParallelCount
+	parallelCount := database.DefaultClientParallelCount
 	if config, ok := dynconfig.GetSchedulerClusterClientConfig(); ok && config.ParallelCount > 0 {
 		parallelCount = int(config.ParallelCount)
 	}
diff --git a/scheduler/service/service.go b/scheduler/service/service.go
index 78565d06..6042e447 100644
--- a/scheduler/service/service.go
+++ b/scheduler/service/service.go
@@ -21,6 +21,8 @@ import (
 	"fmt"
 	"io"
 
+	"go.opentelemetry.io/otel/trace"
+
 	"d7y.io/dragonfly/v2/internal/dferrors"
 	logger "d7y.io/dragonfly/v2/internal/dflog"
 	"d7y.io/dragonfly/v2/pkg/container/set"
@@ -276,13 +278,20 @@ func (s *Service) ReportPieceResult(stream rpcscheduler.Scheduler_ReportPieceRes
 
 			// Collect peer host traffic metrics
 			if s.config.Metrics != nil && s.config.Metrics.EnablePeerHost {
-				metrics.PeerHostTraffic.WithLabelValues("download", peer.Host.ID, peer.Host.IP).Add(float64(piece.PieceInfo.RangeSize))
+				metrics.PeerHostTraffic.WithLabelValues(peer.BizTag, metrics.PeerHostTrafficDownloadType, peer.Host.ID, peer.Host.IP).Add(float64(piece.PieceInfo.RangeSize))
 				if parent, ok := s.resource.PeerManager().Load(piece.DstPid); ok {
-					metrics.PeerHostTraffic.WithLabelValues("upload", parent.Host.ID, parent.Host.IP).Add(float64(piece.PieceInfo.RangeSize))
+					metrics.PeerHostTraffic.WithLabelValues(peer.BizTag, metrics.PeerHostTrafficUploadType, parent.Host.ID, parent.Host.IP).Add(float64(piece.PieceInfo.RangeSize))
 				} else {
 					peer.Log.Warnf("dst peer %s not found for piece %#v %#v", piece.DstPid, piece, piece.PieceInfo)
 				}
 			}
+
+			// Collect traffic metrics
+			if piece.DstPid != "" {
+				metrics.Traffic.WithLabelValues(peer.BizTag, metrics.TrafficP2PType).Add(float64(piece.PieceInfo.RangeSize))
+			} else {
+				metrics.Traffic.WithLabelValues(peer.BizTag, metrics.TrafficBackToSourceType).Add(float64(piece.PieceInfo.RangeSize))
+			}
 			continue
 		}
 
@@ -311,12 +320,16 @@ func (s *Service) ReportPeerResult(ctx context.Context, req *rpcscheduler.PeerRe
 		return dferrors.Newf(base.Code_SchedPeerNotFound, "peer %s not found", req.PeerId)
 	}
 
+	metrics.DownloadCount.WithLabelValues(peer.BizTag).Inc()
+
 	if !req.Success {
 		peer.Log.Errorf("report peer failed result: %s %#v", req.Code, req)
 		if peer.FSM.Is(resource.PeerStateBackToSource) {
 			s.handleTaskFail(ctx, peer.Task)
 		}
 		s.handlePeerFail(ctx, peer)
+
+		metrics.DownloadFailureCount.WithLabelValues(peer.BizTag).Inc()
 		return nil
 	}
 
@@ -325,6 +338,8 @@ func (s *Service) ReportPeerResult(ctx context.Context, req *rpcscheduler.PeerRe
 		s.handleTaskSuccess(ctx, peer.Task, req)
 	}
 	s.handlePeerSuccess(ctx, peer)
+
+	metrics.PeerTaskDownloadDuration.WithLabelValues(peer.BizTag).Observe(float64(req.Cost))
 	return nil
 }
 
@@ -336,9 +351,13 @@ func (s *Service) LeaveTask(ctx context.Context, req *rpcscheduler.PeerTarget) e
 		return dferrors.Newf(base.Code_SchedPeerNotFound, "peer %s not found", req.PeerId)
 	}
 
+	metrics.LeaveTaskCount.WithLabelValues(peer.BizTag).Inc()
+
 	peer.Log.Infof("leave task: %#v", req)
 	if err := peer.FSM.Event(resource.PeerEventLeave); err != nil {
 		peer.Log.Errorf("peer fsm event failed: %v", err)
+
+		metrics.LeaveTaskFailureCount.WithLabelValues(peer.BizTag).Inc()
 		return dferrors.Newf(base.Code_SchedTaskStatusError, err.Error())
 	}
 
@@ -357,7 +376,6 @@ func (s *Service) LeaveTask(ctx context.Context, req *rpcscheduler.PeerTarget) e
 		return true
 	})
 
-	peer.DeleteParent()
 	s.resource.PeerManager().Delete(peer.ID)
 	return nil
 }
@@ -401,7 +419,7 @@ func (s *Service) registerHost(ctx context.Context, req *rpcscheduler.PeerTaskRe
 	if !ok {
 		// Get scheduler cluster client config by manager
 		var options []resource.HostOption
-		if clientConfig, ok := s.dynconfig.GetSchedulerClusterClientConfig(); ok {
+		if clientConfig, ok := s.dynconfig.GetSchedulerClusterClientConfig(); ok && clientConfig.LoadLimit > 0 {
 			options = append(options, resource.WithUploadLoadLimit(int32(clientConfig.LoadLimit)))
 		}
 
@@ -417,7 +435,7 @@ func (s *Service) registerHost(ctx context.Context, req *rpcscheduler.PeerTaskRe
 
 // registerPeer creates a new peer or reuses a previous peer
 func (s *Service) registerPeer(ctx context.Context, req *rpcscheduler.PeerTaskRequest, task *resource.Task, host *resource.Host) *resource.Peer {
-	peer, loaded := s.resource.PeerManager().LoadOrStore(resource.NewPeer(req.PeerId, task, host))
+	peer, loaded := s.resource.PeerManager().LoadOrStore(resource.NewPeer(req.PeerId, task, host, resource.WithBizTag(req.UrlMeta.Tag)))
 	if !loaded {
 		peer.Log.Info("create new peer")
 		return peer
@@ -430,7 +448,8 @@ func (s *Service) registerPeer(ctx context.Context, req *rpcscheduler.PeerTaskRe
 // triggerCDNTask starts trigger cdn task
 func (s *Service) triggerCDNTask(ctx context.Context, task *resource.Task) {
 	task.Log.Infof("trigger cdn download task and task status is %s", task.FSM.Current())
-	peer, endOfPiece, err := s.resource.CDN().TriggerTask(context.Background(), task)
+	peer, endOfPiece, err := s.resource.CDN().TriggerTask(
+		trace.ContextWithSpanContext(context.Background(), trace.SpanContextFromContext(ctx)), task)
 	if err != nil {
 		task.Log.Errorf("trigger cdn download task failed: %v", err)
 		s.handleTaskFail(ctx, task)


Test patch:
diff --git a/cdn/supervisor/cdn/storage/disk/disk_test.go b/cdn/supervisor/cdn/storage/disk/disk_test.go
index be7faaf2..2c6de004 100644
--- a/cdn/supervisor/cdn/storage/disk/disk_test.go
+++ b/cdn/supervisor/cdn/storage/disk/disk_test.go
@@ -18,14 +18,19 @@ package disk
 
 import (
 	"fmt"
+	"os"
+	"path/filepath"
 	"testing"
 
 	"github.com/golang/mock/gomock"
 	"github.com/stretchr/testify/suite"
 
 	"d7y.io/dragonfly/v2/cdn/storedriver"
+	"d7y.io/dragonfly/v2/cdn/storedriver/local"
 	"d7y.io/dragonfly/v2/cdn/supervisor/cdn/storage"
 	taskMock "d7y.io/dragonfly/v2/cdn/supervisor/mocks/task"
+	"d7y.io/dragonfly/v2/cdn/supervisor/task"
+	"d7y.io/dragonfly/v2/pkg/rpc/base"
 	"d7y.io/dragonfly/v2/pkg/unit"
 )
 
@@ -132,3 +137,26 @@ func (suite *DiskStorageManagerSuite) TestTryFreeSpace() {
 		})
 	}
 }
+
+func (suite *DiskStorageManagerSuite) TestDeleteTask() {
+	workHome, _ := os.MkdirTemp("/tmp", "cdn-storageManager-")
+	diskDriver, err := local.NewStorageDriver(&storedriver.Config{BaseDir: workHome})
+	suite.Nil(err)
+	suite.m = &diskStorageManager{
+		diskDriver: diskDriver,
+	}
+	testTask := task.NewSeedTask("fooTask", "http://www.dragonfly", &base.UrlMeta{})
+	suite.Nil(suite.m.ResetRepo(testTask))
+	downloadFile, _ := os.Stat(filepath.Join(workHome, "download", "foo", "fooTask"))
+	uploadFile, _ := os.Stat(filepath.Join(workHome, "upload", "foo", "fooTask"))
+	suite.NotNil(downloadFile)
+	suite.NotNil(uploadFile)
+	suite.Nil(suite.m.DeleteTask(testTask.ID))
+	downloadFile, err = os.Stat(filepath.Join(workHome, "download", "foo", "fooTask"))
+	suite.True(os.IsNotExist(err))
+	uploadFile, err = os.Stat(filepath.Join(workHome, "upload", "foo", "fooTask"))
+	suite.True(os.IsNotExist(err))
+	suite.Nil(downloadFile)
+	suite.Nil(uploadFile)
+	os.RemoveAll(workHome)
+}
diff --git a/client/daemon/peer/peertask_stream_backsource_partial_test.go b/client/daemon/peer/peertask_stream_backsource_partial_test.go
index dfc38be0..80b93449 100644
--- a/client/daemon/peer/peertask_stream_backsource_partial_test.go
+++ b/client/daemon/peer/peertask_stream_backsource_partial_test.go
@@ -226,13 +226,11 @@ func TestStreamPeerTask_BackSource_Partial_WithContentLength(t *testing.T) {
 	source.UnRegister("http")
 	require.Nil(t, source.Register("http", sourceClient, httpprotocol.Adapter))
 	defer source.UnRegister("http")
-	sourceClient.EXPECT().GetContentLength(gomock.Any()).DoAndReturn(
-		func(request *source.Request) (int64, error) {
-			return int64(len(testBytes)), nil
-		})
 	sourceClient.EXPECT().Download(gomock.Any()).DoAndReturn(
 		func(request *source.Request) (*source.Response, error) {
-			return source.NewResponse(io.NopCloser(bytes.NewBuffer(testBytes))), nil
+			response := source.NewResponse(io.NopCloser(bytes.NewBuffer(testBytes)))
+			response.ContentLength = int64(len(testBytes))
+			return response, nil
 		})
 
 	pm := &pieceManager{
diff --git a/client/daemon/peer/piece_manager_test.go b/client/daemon/peer/piece_manager_test.go
index 6e351dc3..0d292251 100644
--- a/client/daemon/peer/piece_manager_test.go
+++ b/client/daemon/peer/piece_manager_test.go
@@ -197,7 +197,7 @@ func TestPieceManager_DownloadSource(t *testing.T) {
 			}))
 			defer ts.Close()
 
-			pm, err := NewPieceManager(storageManager, pieceDownloadTimeout)
+			pm, err := NewPieceManager(pieceDownloadTimeout)
 			assert.Nil(err)
 			pm.(*pieceManager).computePieceSize = func(length int64) uint32 {
 				return tc.pieceSize
diff --git a/client/daemon/transport/transport_test.go b/client/daemon/transport/transport_test.go
index ba2a9c45..84a05e27 100644
--- a/client/daemon/transport/transport_test.go
+++ b/client/daemon/transport/transport_test.go
@@ -30,7 +30,6 @@ import (
 	"d7y.io/dragonfly/v2/client/daemon/peer"
 	"d7y.io/dragonfly/v2/client/daemon/test"
 	mock_peer "d7y.io/dragonfly/v2/client/daemon/test/mock/peer"
-	"d7y.io/dragonfly/v2/pkg/rpc/scheduler"
 )
 
 func TestMain(m *testing.M) {
@@ -52,7 +51,7 @@ func TestTransport_RoundTrip(t *testing.T) {
 		},
 	)
 	rt, _ := New(
-		WithPeerHost(&scheduler.PeerHost{}),
+		WithPeerIDGenerator(peer.NewPeerIDGenerator("127.0.0.1")),
 		WithPeerTaskManager(peerTaskManager),
 		WithCondition(func(r *http.Request) bool {
 			return true
diff --git a/pkg/cache/cache_test.go b/pkg/cache/cache_test.go
index b1ebe10c..13fccddb 100644
--- a/pkg/cache/cache_test.go
+++ b/pkg/cache/cache_test.go
@@ -94,19 +94,19 @@ func TestCache(t *testing.T) {
 func TestCacheTimes(t *testing.T) {
 	var found bool
 
-	tc := New(50*time.Millisecond, 1*time.Millisecond)
+	tc := New(100*time.Millisecond, 1*time.Millisecond)
 	tc.Set("a", 1, DefaultExpiration)
 	tc.Set("b", 2, NoExpiration)
-	tc.Set("c", 3, 20*time.Millisecond)
-	tc.Set("d", 4, 70*time.Millisecond)
+	tc.Set("c", 3, 40*time.Millisecond)
+	tc.Set("d", 4, 140*time.Millisecond)
 
-	<-time.After(25 * time.Millisecond)
+	<-time.After(50 * time.Millisecond)
 	_, found = tc.Get("c")
 	if found {
 		t.Error("Found c when it should have been automatically deleted")
 	}
 
-	<-time.After(30 * time.Millisecond)
+	<-time.After(80 * time.Millisecond)
 	_, found = tc.Get("a")
 	if found {
 		t.Error("Found a when it should have been automatically deleted")
@@ -122,7 +122,7 @@ func TestCacheTimes(t *testing.T) {
 		t.Error("Did not find d even though it was set to expire later than the default")
 	}
 
-	<-time.After(20 * time.Millisecond)
+	<-time.After(40 * time.Millisecond)
 	_, found = tc.Get("d")
 	if found {
 		t.Error("Found d when it should have been automatically deleted (later than the default)")
diff --git a/scheduler/resource/cdn_test.go b/scheduler/resource/cdn_test.go
index 36c0d28d..ed6437ca 100644
--- a/scheduler/resource/cdn_test.go
+++ b/scheduler/resource/cdn_test.go
@@ -28,6 +28,7 @@ import (
 	"github.com/stretchr/testify/assert"
 
 	"d7y.io/dragonfly/v2/internal/dfnet"
+	"d7y.io/dragonfly/v2/manager/database"
 	"d7y.io/dragonfly/v2/manager/types"
 	rpcscheduler "d7y.io/dragonfly/v2/pkg/rpc/scheduler"
 	"d7y.io/dragonfly/v2/scheduler/config"
@@ -352,7 +353,7 @@ func TestCDNClient_cdnsToHosts(t *testing.T) {
 				assert.Equal(hosts[mockRawCDNHost.Uuid].IDC, mockRawCDNHost.Idc)
 				assert.Equal(hosts[mockRawCDNHost.Uuid].NetTopology, "")
 				assert.Equal(hosts[mockRawCDNHost.Uuid].Location, mockRawCDNHost.Location)
-				assert.Equal(hosts[mockRawCDNHost.Uuid].UploadLoadLimit.Load(), int32(defaultUploadLoadLimit))
+				assert.Equal(hosts[mockRawCDNHost.Uuid].UploadLoadLimit.Load(), int32(database.DefaultClientLoadLimit))
 				assert.Empty(hosts[mockRawCDNHost.Uuid].Peers)
 				assert.Equal(hosts[mockRawCDNHost.Uuid].IsCDN, true)
 				assert.NotEqual(hosts[mockRawCDNHost.Uuid].CreateAt.Load(), 0)
diff --git a/scheduler/resource/host_test.go b/scheduler/resource/host_test.go
index 559d162f..12664b8a 100644
--- a/scheduler/resource/host_test.go
+++ b/scheduler/resource/host_test.go
@@ -21,6 +21,7 @@ import (
 
 	"github.com/stretchr/testify/assert"
 
+	"d7y.io/dragonfly/v2/manager/database"
 	"d7y.io/dragonfly/v2/pkg/idgen"
 	"d7y.io/dragonfly/v2/pkg/rpc/scheduler"
 )
@@ -72,7 +73,7 @@ func TestHost_NewHost(t *testing.T) {
 				assert.Equal(host.Location, mockRawHost.Location)
 				assert.Equal(host.IDC, mockRawHost.Idc)
 				assert.Equal(host.NetTopology, mockRawHost.NetTopology)
-				assert.Equal(host.UploadLoadLimit.Load(), int32(defaultUploadLoadLimit))
+				assert.Equal(host.UploadLoadLimit.Load(), int32(database.DefaultClientLoadLimit))
 				assert.Equal(host.PeerCount.Load(), int32(0))
 				assert.Equal(host.IsCDN, false)
 				assert.NotEqual(host.CreateAt.Load(), 0)
@@ -95,7 +96,7 @@ func TestHost_NewHost(t *testing.T) {
 				assert.Equal(host.Location, mockRawCDNHost.Location)
 				assert.Equal(host.IDC, mockRawCDNHost.Idc)
 				assert.Equal(host.NetTopology, mockRawCDNHost.NetTopology)
-				assert.Equal(host.UploadLoadLimit.Load(), int32(defaultUploadLoadLimit))
+				assert.Equal(host.UploadLoadLimit.Load(), int32(database.DefaultClientLoadLimit))
 				assert.Equal(host.PeerCount.Load(), int32(0))
 				assert.Equal(host.IsCDN, true)
 				assert.NotEqual(host.CreateAt.Load(), 0)
@@ -383,7 +384,7 @@ func TestHost_FreeUploadLoad(t *testing.T) {
 				host.StorePeer(mockPeer)
 				mockPeer.ID = idgen.PeerID("0.0.0.0")
 				host.StorePeer(mockPeer)
-				assert.Equal(host.FreeUploadLoad(), int32(defaultUploadLoadLimit-2))
+				assert.Equal(host.FreeUploadLoad(), int32(database.DefaultClientLoadLimit-2))
 			},
 		},
 		{
@@ -391,7 +392,7 @@ func TestHost_FreeUploadLoad(t *testing.T) {
 			rawHost: mockRawHost,
 			expect: func(t *testing.T, host *Host, mockPeer *Peer) {
 				assert := assert.New(t)
-				assert.Equal(host.FreeUploadLoad(), int32(defaultUploadLoadLimit))
+				assert.Equal(host.FreeUploadLoad(), int32(database.DefaultClientLoadLimit))
 			},
 		},
 	}
diff --git a/scheduler/resource/peer_test.go b/scheduler/resource/peer_test.go
index 26344873..7004189e 100644
--- a/scheduler/resource/peer_test.go
+++ b/scheduler/resource/peer_test.go
@@ -42,9 +42,10 @@ var (
 
 func TestPeer_NewPeer(t *testing.T) {
 	tests := []struct {
-		name   string
-		id     string
-		expect func(t *testing.T, peer *Peer, mockTask *Task, mockHost *Host)
+		name    string
+		id      string
+		options []PeerOption
+		expect  func(t *testing.T, peer *Peer, mockTask *Task, mockHost *Host)
 	}{
 		{
 			name: "new peer",
@@ -65,13 +66,34 @@ func TestPeer_NewPeer(t *testing.T) {
 				assert.NotNil(peer.Log)
 			},
 		},
+		{
+			name:    "new peer with bizTag",
+			id:      mockPeerID,
+			options: []PeerOption{WithBizTag("foo")},
+			expect: func(t *testing.T, peer *Peer, mockTask *Task, mockHost *Host) {
+				assert := assert.New(t)
+				assert.Equal(peer.ID, mockPeerID)
+				assert.Equal(peer.BizTag, "foo")
+				assert.Empty(peer.Pieces)
+				assert.Equal(len(peer.PieceCosts()), 0)
+				assert.Empty(peer.Stream)
+				assert.Equal(peer.FSM.Current(), PeerStatePending)
+				assert.EqualValues(peer.Task, mockTask)
+				assert.EqualValues(peer.Host, mockHost)
+				assert.Empty(peer.Parent)
+				assert.Empty(peer.Children)
+				assert.NotEqual(peer.CreateAt.Load(), 0)
+				assert.NotEqual(peer.UpdateAt.Load(), 0)
+				assert.NotNil(peer.Log)
+			},
+		},
 	}
 
 	for _, tc := range tests {
 		t.Run(tc.name, func(t *testing.T) {
 			mockHost := NewHost(mockRawHost)
 			mockTask := NewTask(mockTaskID, mockTaskURL, mockTaskBackToSourceLimit, mockTaskURLMeta)
-			tc.expect(t, NewPeer(tc.id, mockTask, mockHost), mockTask, mockHost)
+			tc.expect(t, NewPeer(tc.id, mockTask, mockHost, tc.options...), mockTask, mockHost)
 		})
 	}
 }
diff --git a/scheduler/scheduler/evaluator/evaluator_base_test.go b/scheduler/scheduler/evaluator/evaluator_base_test.go
index 22e98f0a..f480ea83 100644
--- a/scheduler/scheduler/evaluator/evaluator_base_test.go
+++ b/scheduler/scheduler/evaluator/evaluator_base_test.go
@@ -290,7 +290,7 @@ func TestEvaluatorBase_calculateFreeLoadScore(t *testing.T) {
 			},
 			expect: func(t *testing.T, score float64) {
 				assert := assert.New(t)
-				assert.Equal(score, float64(0.99))
+				assert.Equal(score, float64(0.98))
 			},
 		},
 		{
diff --git a/scheduler/scheduler/scheduler_test.go b/scheduler/scheduler/scheduler_test.go
index c404a05d..fe8c8353 100644
--- a/scheduler/scheduler/scheduler_test.go
+++ b/scheduler/scheduler/scheduler_test.go
@@ -872,3 +872,85 @@ func TestScheduler_FindParent(t *testing.T) {
 		})
 	}
 }
+
+func TestScheduler_constructSuccessPeerPacket(t *testing.T) {
+	tests := []struct {
+		name   string
+		mock   func(md *configmocks.MockDynconfigInterfaceMockRecorder)
+		expect func(t *testing.T, packet *rpcscheduler.PeerPacket, parent *resource.Peer, candidateParents []*resource.Peer)
+	}{
+		{
+			name: "get parallelCount from dynconfig",
+			mock: func(md *configmocks.MockDynconfigInterfaceMockRecorder) {
+				md.GetSchedulerClusterClientConfig().Return(types.SchedulerClusterClientConfig{
+					ParallelCount: 1,
+				}, true).Times(1)
+			},
+			expect: func(t *testing.T, packet *rpcscheduler.PeerPacket, parent *resource.Peer, candidateParents []*resource.Peer) {
+				assert := assert.New(t)
+				assert.EqualValues(packet, &rpcscheduler.PeerPacket{
+					TaskId:        mockTaskID,
+					SrcPid:        mockPeerID,
+					ParallelCount: 1,
+					MainPeer: &rpcscheduler.PeerPacket_DestPeer{
+						Ip:      parent.Host.IP,
+						RpcPort: parent.Host.Port,
+						PeerId:  parent.ID,
+					},
+					StealPeers: []*rpcscheduler.PeerPacket_DestPeer{
+						{
+							Ip:      candidateParents[0].Host.IP,
+							RpcPort: candidateParents[0].Host.Port,
+							PeerId:  candidateParents[0].ID,
+						},
+					},
+					Code: base.Code_Success,
+				})
+			},
+		},
+		{
+			name: "use default parallelCount",
+			mock: func(md *configmocks.MockDynconfigInterfaceMockRecorder) {
+				md.GetSchedulerClusterClientConfig().Return(types.SchedulerClusterClientConfig{}, false).Times(1)
+			},
+			expect: func(t *testing.T, packet *rpcscheduler.PeerPacket, parent *resource.Peer, candidateParents []*resource.Peer) {
+				assert := assert.New(t)
+				assert.EqualValues(packet, &rpcscheduler.PeerPacket{
+					TaskId:        mockTaskID,
+					SrcPid:        mockPeerID,
+					ParallelCount: 4,
+					MainPeer: &rpcscheduler.PeerPacket_DestPeer{
+						Ip:      parent.Host.IP,
+						RpcPort: parent.Host.Port,
+						PeerId:  parent.ID,
+					},
+					StealPeers: []*rpcscheduler.PeerPacket_DestPeer{
+						{
+							Ip:      candidateParents[0].Host.IP,
+							RpcPort: candidateParents[0].Host.Port,
+							PeerId:  candidateParents[0].ID,
+						},
+					},
+					Code: base.Code_Success,
+				})
+			},
+		},
+	}
+
+	for _, tc := range tests {
+		t.Run(tc.name, func(t *testing.T) {
+			ctl := gomock.NewController(t)
+			defer ctl.Finish()
+			dynconfig := configmocks.NewMockDynconfigInterface(ctl)
+			mockHost := resource.NewHost(mockRawHost)
+			mockTask := resource.NewTask(mockTaskID, mockTaskURL, mockTaskBackToSourceLimit, mockTaskURLMeta)
+
+			peer := resource.NewPeer(mockPeerID, mockTask, mockHost)
+			parent := resource.NewPeer(idgen.PeerID("127.0.0.1"), mockTask, mockHost)
+			candidateParents := []*resource.Peer{resource.NewPeer(idgen.PeerID("127.0.0.1"), mockTask, mockHost)}
+
+			tc.mock(dynconfig.EXPECT())
+			tc.expect(t, constructSuccessPeerPacket(dynconfig, peer, parent, candidateParents), parent, candidateParents)
+		})
+	}
+}
diff --git a/scheduler/service/service_test.go b/scheduler/service/service_test.go
index 3725cd23..bd1820ce 100644
--- a/scheduler/service/service_test.go
+++ b/scheduler/service/service_test.go
@@ -132,7 +132,9 @@ func TestService_RegisterPeerTask(t *testing.T) {
 	}{
 		{
 			name: "task register failed",
-			req:  &rpcscheduler.PeerTaskRequest{},
+			req: &rpcscheduler.PeerTaskRequest{
+				UrlMeta: &base.UrlMeta{},
+			},
 			mock: func(
 				req *rpcscheduler.PeerTaskRequest, mockPeer *resource.Peer, mockCDNPeer *resource.Peer,
 				scheduler scheduler.Scheduler, res resource.Resource, hostManager resource.HostManager, taskManager resource.TaskManager, peerManager resource.PeerManager,
@@ -154,6 +156,7 @@ func TestService_RegisterPeerTask(t *testing.T) {
 		{
 			name: "task state is TaskStateFailed",
 			req: &rpcscheduler.PeerTaskRequest{
+				UrlMeta: &base.UrlMeta{},
 				PeerHost: &rpcscheduler.PeerHost{
 					Uuid: mockRawHost.Uuid,
 				},
@@ -184,6 +187,7 @@ func TestService_RegisterPeerTask(t *testing.T) {
 		{
 			name: "task state is TaskStateFailed and peer state is PeerStateFailed",
 			req: &rpcscheduler.PeerTaskRequest{
+				UrlMeta: &base.UrlMeta{},
 				PeerHost: &rpcscheduler.PeerHost{
 					Uuid: mockRawHost.Uuid,
 				},
@@ -215,6 +219,7 @@ func TestService_RegisterPeerTask(t *testing.T) {
 		{
 			name: "task scope size is SizeScope_TINY",
 			req: &rpcscheduler.PeerTaskRequest{
+				UrlMeta: &base.UrlMeta{},
 				PeerHost: &rpcscheduler.PeerHost{
 					Uuid: mockRawHost.Uuid,
 				},
@@ -250,6 +255,7 @@ func TestService_RegisterPeerTask(t *testing.T) {
 		{
 			name: "task scope size is SizeScope_TINY and direct piece content is empty",
 			req: &rpcscheduler.PeerTaskRequest{
+				UrlMeta: &base.UrlMeta{},
 				PeerHost: &rpcscheduler.PeerHost{
 					Uuid: mockRawHost.Uuid,
 				},
@@ -283,6 +289,7 @@ func TestService_RegisterPeerTask(t *testing.T) {
 		{
 			name: "task scope size is SizeScope_TINY and direct piece content is error, peer state is PeerStateFailed",
 			req: &rpcscheduler.PeerTaskRequest{
+				UrlMeta: &base.UrlMeta{},
 				PeerHost: &rpcscheduler.PeerHost{
 					Uuid: mockRawHost.Uuid,
 				},
@@ -316,6 +323,7 @@ func TestService_RegisterPeerTask(t *testing.T) {
 		{
 			name: "task scope size is SizeScope_TINY and direct piece content is error",
 			req: &rpcscheduler.PeerTaskRequest{
+				UrlMeta: &base.UrlMeta{},
 				PeerHost: &rpcscheduler.PeerHost{
 					Uuid: mockRawHost.Uuid,
 				},
@@ -349,6 +357,7 @@ func TestService_RegisterPeerTask(t *testing.T) {
 		{
 			name: "task scope size is SizeScope_SMALL and load piece error, parent state is PeerStateRunning",
 			req: &rpcscheduler.PeerTaskRequest{
+				UrlMeta: &base.UrlMeta{},
 				PeerHost: &rpcscheduler.PeerHost{
 					Uuid: mockRawHost.Uuid,
 				},
@@ -389,6 +398,7 @@ func TestService_RegisterPeerTask(t *testing.T) {
 		{
 			name: "task scope size is SizeScope_SMALL and load piece error, peer state is PeerStateFailed",
 			req: &rpcscheduler.PeerTaskRequest{
+				UrlMeta: &base.UrlMeta{},
 				PeerHost: &rpcscheduler.PeerHost{
 					Uuid: mockRawHost.Uuid,
 				},
@@ -428,6 +438,7 @@ func TestService_RegisterPeerTask(t *testing.T) {
 		{
 			name: "task scope size is SizeScope_SMALL and peer state is PeerStateFailed",
 			req: &rpcscheduler.PeerTaskRequest{
+				UrlMeta: &base.UrlMeta{},
 				PeerHost: &rpcscheduler.PeerHost{
 					Uuid: mockRawHost.Uuid,
 				},
@@ -467,6 +478,7 @@ func TestService_RegisterPeerTask(t *testing.T) {
 		{
 			name: "task scope size is SizeScope_SMALL",
 			req: &rpcscheduler.PeerTaskRequest{
+				UrlMeta: &base.UrlMeta{},
 				PeerHost: &rpcscheduler.PeerHost{
 					Uuid: mockRawHost.Uuid,
 				},
@@ -506,6 +518,7 @@ func TestService_RegisterPeerTask(t *testing.T) {
 		{
 			name: "task scope size is SizeScope_NORMAL and peer state is PeerStateFailed",
 			req: &rpcscheduler.PeerTaskRequest{
+				UrlMeta: &base.UrlMeta{},
 				PeerHost: &rpcscheduler.PeerHost{
 					Uuid: mockRawHost.Uuid,
 				},
@@ -539,6 +552,7 @@ func TestService_RegisterPeerTask(t *testing.T) {
 		{
 			name: "task scope size is SizeScope_NORMAL",
 			req: &rpcscheduler.PeerTaskRequest{
+				UrlMeta: &base.UrlMeta{},
 				PeerHost: &rpcscheduler.PeerHost{
 					Uuid: mockRawHost.Uuid,
 				},
@@ -1752,7 +1766,8 @@ func TestService_registerPeer(t *testing.T) {
 		{
 			name: "peer already exists",
 			req: &rpcscheduler.PeerTaskRequest{
-				PeerId: mockPeerID,
+				PeerId:  mockPeerID,
+				UrlMeta: &base.UrlMeta{},
 			},
 			mock: func(mockPeer *resource.Peer, peerManager resource.PeerManager, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder) {
 				gomock.InOrder(
@@ -1768,7 +1783,8 @@ func TestService_registerPeer(t *testing.T) {
 		{
 			name: "peer does not exists",
 			req: &rpcscheduler.PeerTaskRequest{
-				PeerId: mockPeerID,
+				PeerId:  mockPeerID,
+				UrlMeta: &base.UrlMeta{},
 			},
 			mock: func(mockPeer *resource.Peer, peerManager resource.PeerManager, mr *resource.MockResourceMockRecorder, mp *resource.MockPeerManagerMockRecorder) {
 				gomock.InOrder(
@@ -2110,9 +2126,9 @@ func TestService_handlePieceFail(t *testing.T) {
 					mr.PeerManager().Return(peerManager).Times(1),
 					mp.Load(gomock.Eq(parent.ID)).Return(parent, true).Times(1),
 				)
-				ms.ScheduleParent(gomock.Any(), gomock.Eq(peer), gomock.Eq(blocklist)).Return().Times(1)
 				mr.CDN().Do(func() { wg.Done() }).Return(cdn).Times(1)
 				mc.TriggerTask(gomock.Any(), gomock.Any()).Do(func(ctx context.Context, task *resource.Task) { wg.Done() }).Return(peer, &rpcscheduler.PeerResult{}, nil).Times(1)
+				ms.ScheduleParent(gomock.Any(), gomock.Eq(peer), gomock.Eq(blocklist)).Return().AnyTimes()
 
 				svc.handlePieceFail(context.Background(), peer, piece)
 				assert := assert.New(t)