Repository: dragonflyoss/Dragonfly2
Pull request #509 (2021-07-29 06:10:45)

Feature/concurrent dead lock
<!--- Provide a general summary of your changes in the Title above -->

## Description

<!--- Describe your changes in detail -->

## 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: -->

- [x] Bug fix (non-breaking change which fixes an issue)
- [x] 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! -->

- [x] 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.


codecov-commenter: # [Codecov](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/509?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss) Report
> Merging [#509](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/509?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss) (9dca480) into [main](https://codecov.io/gh/dragonflyoss/Dragonfly2/commit/e655635fc277ad51c6b8ddb36256626ecbd1ae63?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss) (e655635) will **decrease** coverage by `0.04%`.
> The diff coverage is `28.00%`.

[![Impacted file tree graph](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/509/graphs/tree.svg?width=650&height=150&src=pr&token=PUICJYSAT7&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss)](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/509?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss)

```diff
@@            Coverage Diff             @@
##             main     #509      +/-   ##
==========================================
- Coverage   39.59%   39.55%   -0.05%     
==========================================
  Files          81       81              
  Lines        6284     6293       +9     
==========================================
+ Hits         2488     2489       +1     
- Misses       3437     3443       +6     
- Partials      359      361       +2     
```

| Flag | Coverage Δ | |
|---|---|---|
| e2etests | `?` | |
| unittests | `39.55% <28.00%> (-0.05%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/509?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss) | Coverage Δ | |
|---|---|---|
| [client/daemon/daemon.go](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/509/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#diff-Y2xpZW50L2RhZW1vbi9kYWVtb24uZ28=) | `0.00% <0.00%> (ø)` | |
| [client/daemon/peer/peertask\_base.go](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/509/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#diff-Y2xpZW50L2RhZW1vbi9wZWVyL3BlZXJ0YXNrX2Jhc2UuZ28=) | `32.39% <0.00%> (-0.71%)` | :arrow_down: |
| [client/daemon/service/manager.go](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/509/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#diff-Y2xpZW50L2RhZW1vbi9zZXJ2aWNlL21hbmFnZXIuZ28=) | `33.00% <0.00%> (ø)` | |
| [pkg/structure/sortedlist/sorted\_list.go](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/509/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#diff-cGtnL3N0cnVjdHVyZS9zb3J0ZWRsaXN0L3NvcnRlZF9saXN0Lmdv) | `56.31% <0.00%> (-2.28%)` | :arrow_down: |
| [scheduler/config/config.go](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/509/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#diff-c2NoZWR1bGVyL2NvbmZpZy9jb25maWcuZ28=) | `0.00% <0.00%> (ø)` | |
| [client/daemon/peer/peertask\_file\_callback.go](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/509/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#diff-Y2xpZW50L2RhZW1vbi9wZWVyL3BlZXJ0YXNrX2ZpbGVfY2FsbGJhY2suZ28=) | `62.96% <25.00%> (ø)` | |
| [client/daemon/peer/peertask\_stream\_callback.go](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/509/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#diff-Y2xpZW50L2RhZW1vbi9wZWVyL3BlZXJ0YXNrX3N0cmVhbV9jYWxsYmFjay5nbw==) | `64.55% <25.00%> (ø)` | |
| [client/daemon/peer/peertask\_file.go](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/509/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#diff-Y2xpZW50L2RhZW1vbi9wZWVyL3BlZXJ0YXNrX2ZpbGUuZ28=) | `53.81% <50.00%> (+0.15%)` | :arrow_up: |
| [client/daemon/peer/peertask\_stream.go](https://codecov.io/gh/dragonflyoss/Dragonfly2/pull/509/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=dragonflyoss#diff-Y2xpZW50L2RhZW1vbi9wZWVyL3BlZXJ0YXNrX3N0cmVhbS5nbw==) | `57.29% <100.00%> (+0.31%)` | :arrow_up: |


Patch:
diff --git a/cdnsystem/server/service/cdn_seed_server.go b/cdnsystem/server/service/cdn_seed_server.go
index f6182476..d59b3f6a 100644
--- a/cdnsystem/server/service/cdn_seed_server.go
+++ b/cdnsystem/server/service/cdn_seed_server.go
@@ -74,7 +74,7 @@ func constructRegisterRequest(req *cdnsystem.SeedRequest) (*types.TaskRegisterRe
 		URL:    req.Url,
 		Md5:    header["md5"],
 		TaskID: req.TaskId,
-		Filter: strings.Split(req.Filter, "&"),
+		Filter: strings.Split(req.UrlMeta.Filter, "&"),
 	}, nil
 }
 
@@ -159,7 +159,6 @@ func (css *CdnSeedServer) GetPieceTasks(ctx context.Context, req *base.PieceTask
 		return nil, dferrors.Newf(dfcodes.BadRequest, "failed to validate seed request for task(%s): %v", req.TaskId, err)
 	}
 	task, err := css.taskMgr.Get(req.TaskId)
-	logger.Debugf("task: %+v", task)
 	if err != nil {
 		if cdnerrors.IsDataNotFound(err) {
 			return nil, dferrors.Newf(dfcodes.CdnTaskNotFound, "failed to get task(%s) from cdn: %v", req.TaskId, err)
diff --git a/client/daemon/daemon.go b/client/daemon/daemon.go
index eb45d66a..60f27b1b 100644
--- a/client/daemon/daemon.go
+++ b/client/daemon/daemon.go
@@ -111,9 +111,9 @@ func New(opt *config.DaemonOption) (Daemon, error) {
 				PeerId: request.PeerID,
 			})
 			if er != nil {
-				logger.Errorf("leave task %s/%s, error: %v", request.TaskID, request.PeerID, er)
+				logger.Errorf("step 4:leave task %s/%s, error: %v", request.TaskID, request.PeerID, er)
 			} else {
-				logger.Infof("leave task %s/%s state ok", request.TaskID, request.PeerID)
+				logger.Infof("step 4:leave task %s/%s state ok", request.TaskID, request.PeerID)
 			}
 		})
 	if err != nil {
diff --git a/client/daemon/peer/peertask_base.go b/client/daemon/peer/peertask_base.go
index b439c4e2..dd28df4b 100644
--- a/client/daemon/peer/peertask_base.go
+++ b/client/daemon/peer/peertask_base.go
@@ -685,7 +685,8 @@ func (pt *peerTask) getPieceTasks(span trace.Span, curPeerPacket *scheduler.Peer
 			span.RecordError(getErr)
 			// fast way to exit retry
 			if curPeerPacket != pt.peerPacket {
-				pt.Warnf("get piece tasks with error: %s, but peer packet changed, switch to new peer packet", getErr)
+				pt.Warnf("get piece tasks with error: %s, but peer packet changed, switch to new peer packet, current destPeer %s, new destPeer %s", getErr,
+					curPeerPacket.MainPeer.PeerId, pt.peerPacket.MainPeer.PeerId)
 				peerPacketChanged = true
 				return nil, true, nil
 			}
@@ -709,13 +710,14 @@ func (pt *peerTask) getPieceTasks(span trace.Span, curPeerPacket *scheduler.Peer
 			}
 			// fast way to exit retry
 			if curPeerPacket != pt.peerPacket {
-				pt.Warnf("get empty pieces and peer packet changed, switch to new peer packet")
+				pt.Warnf("get empty pieces and peer packet changed, switch to new peer packet, current destPeer %s, new destPeer %s",
+					curPeerPacket.MainPeer.PeerId, pt.peerPacket.MainPeer.PeerId)
 				peerPacketChanged = true
 				return nil, true, nil
 			}
 			span.AddEvent("retry due to empty pieces",
 				trace.WithAttributes(config.AttributeGetPieceRetry.Int(count)))
-			pt.Warnf("peer %s returns success but with empty pieces, retry later", peer.PeerId)
+			pt.Infof("peer %s returns success but with empty pieces, retry later", peer.PeerId)
 			return nil, false, dferrors.ErrEmptyValue
 		}
 		return pp, false, nil
diff --git a/client/daemon/peer/peertask_file.go b/client/daemon/peer/peertask_file.go
index 7f481963..7d625656 100644
--- a/client/daemon/peer/peertask_file.go
+++ b/client/daemon/peer/peertask_file.go
@@ -85,15 +85,17 @@ func newFilePeerTask(ctx context.Context,
 	span.SetAttributes(config.AttributePeerID.String(request.PeerId))
 	span.SetAttributes(semconv.HTTPURLKey.String(request.Url))
 
-	logger.Infof("request overview, url: %s, filter: %s, meta: %s, biz: %s, peer: %s", request.Url, request.Filter, request.UrlMeta, request.BizId, request.PeerId)
+	logger.Infof("request overview, url: %s, filter: %s, meta: %s, biz: %s, peer: %s", request.Url, request.UrlMeta.Filter, request.UrlMeta, request.UrlMeta.Tag, request.PeerId)
 	// trace register
 	_, regSpan := tracer.Start(ctx, config.SpanRegisterTask)
 	result, err := schedulerClient.RegisterPeerTask(ctx, request)
+	logger.Infof("step 1: peer %s start to register", request.PeerId)
 	regSpan.RecordError(err)
 	regSpan.End()
 
 	var backSource bool
 	if err != nil {
+		logger.Errorf("step 1: peer %s register failed: err", request.PeerId, err)
 		// check if it is back source error
 		if de, ok := err.(*dferrors.DfError); ok && de.Code == dfcodes.SchedNeedBackSource {
 			backSource = true
@@ -102,18 +104,17 @@ func newFilePeerTask(ctx context.Context,
 		if !backSource {
 			span.RecordError(err)
 			span.End()
-			logger.Errorf("register peer task failed: %s, peer id: %s", err, request.PeerId)
 			return ctx, nil, nil, err
 		}
 	}
 	if result == nil {
 		defer span.End()
 		span.RecordError(err)
-		err = errors.Errorf("empty schedule result")
+		err = errors.Errorf("step 1: peer register result is nil")
 		return ctx, nil, nil, err
 	}
 	span.SetAttributes(config.AttributeTaskID.String(result.TaskId))
-	logger.Infof("register task success, task id: %s, peer id: %s, SizeScope: %s",
+	logger.Infof("step 1: register task success, task id: %s, peer id: %s, SizeScope: %s",
 		result.TaskId, request.PeerId, base.SizeScope_name[int32(result.SizeScope)])
 
 	var singlePiece *scheduler.SinglePiece
@@ -147,7 +148,9 @@ func newFilePeerTask(ctx context.Context,
 	}
 
 	peerPacketStream, err := schedulerClient.ReportPieceResult(ctx, result.TaskId, request)
+	logger.Infof("step 2: start report peer %s piece result", request.PeerId)
 	if err != nil {
+		logger.Errorf("step 2: peer %s report piece failed: err", request.PeerId, err)
 		defer span.End()
 		span.RecordError(err)
 		return ctx, nil, nil, err
diff --git a/client/daemon/peer/peertask_file_callback.go b/client/daemon/peer/peertask_file_callback.go
index db94b9b9..ffadc4f6 100644
--- a/client/daemon/peer/peertask_file_callback.go
+++ b/client/daemon/peer/peertask_file_callback.go
@@ -106,9 +106,9 @@ func (p *filePeerTaskCallback) Done(pt Task) error {
 		Code:           dfcodes.Success,
 	})
 	if err != nil {
-		pt.Log().Errorf("report successful peer result, error: %v", err)
+		pt.Log().Errorf("step 3: report successful peer result, error: %v", err)
 	} else {
-		pt.Log().Infof("report successful peer result ok")
+		pt.Log().Infof("step 3: report successful peer result ok")
 	}
 	return nil
 }
@@ -131,9 +131,9 @@ func (p *filePeerTaskCallback) Fail(pt Task, code base.Code, reason string) erro
 		Code:           code,
 	})
 	if err != nil {
-		pt.Log().Errorf("report fail peer result, error: %v", err)
+		pt.Log().Errorf("step 3: report fail peer result, error: %v", err)
 	} else {
-		pt.Log().Infof("report fail peer result ok")
+		pt.Log().Infof("step 3: report fail peer result ok")
 	}
 	return nil
 }
diff --git a/client/daemon/peer/peertask_reuse.go b/client/daemon/peer/peertask_reuse.go
index 85b10075..67edc966 100644
--- a/client/daemon/peer/peertask_reuse.go
+++ b/client/daemon/peer/peertask_reuse.go
@@ -35,7 +35,7 @@ import (
 
 func (ptm *peerTaskManager) tryReuseFilePeerTask(ctx context.Context,
 	request *FilePeerTaskRequest) (chan *FilePeerTaskProgress, bool) {
-	taskID := idgen.TaskID(request.Url, request.Filter, request.UrlMeta, request.BizId)
+	taskID := idgen.TaskID(request.Url, request.UrlMeta)
 	reuse := ptm.storageManager.FindCompletedTask(taskID)
 	if reuse == nil {
 		return nil, false
@@ -101,7 +101,7 @@ func (ptm *peerTaskManager) tryReuseFilePeerTask(ctx context.Context,
 
 func (ptm *peerTaskManager) tryReuseStreamPeerTask(ctx context.Context,
 	request *scheduler.PeerTaskRequest) (io.ReadCloser, map[string]string, bool) {
-	taskID := idgen.TaskID(request.Url, request.Filter, request.UrlMeta, request.BizId)
+	taskID := idgen.TaskID(request.Url, request.UrlMeta)
 	reuse := ptm.storageManager.FindCompletedTask(taskID)
 	if reuse == nil {
 		return nil, nil, false
diff --git a/client/daemon/peer/peertask_stream.go b/client/daemon/peer/peertask_stream.go
index 216c777d..7bb48c6b 100644
--- a/client/daemon/peer/peertask_stream.go
+++ b/client/daemon/peer/peertask_stream.go
@@ -67,11 +67,12 @@ func newStreamPeerTask(ctx context.Context,
 	span.SetAttributes(config.AttributePeerID.String(request.PeerId))
 	span.SetAttributes(semconv.HTTPURLKey.String(request.Url))
 
-	logger.Debugf("request overview, pid: %s, url: %s, filter: %s, meta: %s, biz: %s",
-		request.PeerId, request.Url, request.Filter, request.UrlMeta, request.BizId)
+	logger.Debugf("request overview, pid: %s, url: %s, filter: %s, meta: %s, tag: %s",
+		request.PeerId, request.Url, request.UrlMeta.Filter, request.UrlMeta, request.UrlMeta.Tag)
 	// trace register
 	_, regSpan := tracer.Start(ctx, config.SpanRegisterTask)
 	result, err := schedulerClient.RegisterPeerTask(ctx, request)
+	logger.Infof("step 1: peer %s start to register", request.PeerId)
 	regSpan.RecordError(err)
 	regSpan.End()
 
@@ -128,6 +129,7 @@ func newStreamPeerTask(ctx context.Context,
 	}
 
 	peerPacketStream, err := schedulerClient.ReportPieceResult(ctx, result.TaskId, request)
+	logger.Infof("step 2: start report peer %s piece result", request.PeerId)
 	if err != nil {
 		defer span.End()
 		span.RecordError(err)
diff --git a/client/daemon/peer/peertask_stream_callback.go b/client/daemon/peer/peertask_stream_callback.go
index 5455575c..09dcf28f 100644
--- a/client/daemon/peer/peertask_stream_callback.go
+++ b/client/daemon/peer/peertask_stream_callback.go
@@ -104,9 +104,9 @@ func (p *streamPeerTaskCallback) Done(pt Task) error {
 		Code:           dfcodes.Success,
 	})
 	if err != nil {
-		pt.Log().Errorf("report successful peer result, error: %v", err)
+		pt.Log().Errorf("step 3: report successful peer result, error: %v", err)
 	} else {
-		pt.Log().Infof("report successful peer result ok")
+		pt.Log().Infof("step 3: report successful peer result ok")
 	}
 	return nil
 }
@@ -129,9 +129,9 @@ func (p *streamPeerTaskCallback) Fail(pt Task, code base.Code, reason string) er
 		Code:           code,
 	})
 	if err != nil {
-		pt.Log().Errorf("report fail peer result, error: %v", err)
+		pt.Log().Errorf("step 3: report fail peer result, error: %v", err)
 	} else {
-		pt.Log().Infof("report fail peer result ok")
+		pt.Log().Infof("step 3: report fail peer result ok")
 	}
 	return nil
 }
diff --git a/client/daemon/service/manager.go b/client/daemon/service/manager.go
index 31f0380f..345c3ea1 100644
--- a/client/daemon/service/manager.go
+++ b/client/daemon/service/manager.go
@@ -105,7 +105,7 @@ func (m *manager) GetPieceTasks(ctx context.Context, request *base.PieceTaskRequ
 			return nil, dferrors.New(code, err.Error())
 		}
 
-		logger.Warnf("try to get piece tasks, "+
+		logger.Infof("try to get piece tasks, "+
 			"but target peer task is initializing, "+
 			"there is no available pieces, "+
 			"task id: %s, src peer: %s, dst peer: %s, piece num: %d, limit: %d",
@@ -140,8 +140,6 @@ func (m *manager) Download(ctx context.Context,
 	peerTask := &peer.FilePeerTaskRequest{
 		PeerTaskRequest: scheduler.PeerTaskRequest{
 			Url:      req.Url,
-			Filter:   req.UrlMeta.Filter,
-			BizId:    req.UrlMeta.Tag,
 			UrlMeta:  req.UrlMeta,
 			PeerId:   clientutil.GenPeerID(m.peerHost),
 			PeerHost: m.peerHost,
diff --git a/client/daemon/transport/transport.go b/client/daemon/transport/transport.go
index 0556e240..65ade780 100644
--- a/client/daemon/transport/transport.go
+++ b/client/daemon/transport/transport.go
@@ -166,19 +166,19 @@ func (rt *transport) download(req *http.Request) (*http.Response, error) {
 
 	// Pick header's parameters
 	filter := pickHeader(req.Header, config.HeaderDragonflyFilter, rt.defaultFilter)
-	biz := pickHeader(req.Header, config.HeaderDragonflyBiz, rt.defaultBiz)
+	tag := pickHeader(req.Header, config.HeaderDragonflyBiz, rt.defaultBiz)
 
 	// Delete hop-by-hop headers
 	delHopHeaders(req.Header)
 
 	meta.Header = headerToMap(req.Header)
+	meta.Tag = tag
+	meta.Filter = filter
 
 	body, attr, err := rt.peerTaskManager.StartStreamPeerTask(
 		req.Context(),
 		&scheduler.PeerTaskRequest{
 			Url:         url,
-			Filter:      filter,
-			BizId:       biz,
 			UrlMeta:     meta,
 			PeerId:      peerID,
 			PeerHost:    rt.peerHost,
diff --git a/internal/dfcodes/rpc_code.go b/internal/dfcodes/rpc_code.go
index a7c3d928..531fcdff 100644
--- a/internal/dfcodes/rpc_code.go
+++ b/internal/dfcodes/rpc_code.go
@@ -41,7 +41,8 @@ const (
 	ClientRequestLimitFail  base.Code = 4006
 
 	// scheduler response error 5000-5999
-	SchedError                     base.Code = 5000
+	SchedError base.Code = 5000
+	/** @deprecated */
 	SchedNeedBackSource            base.Code = 5001 // client should try to download from source
 	SchedPeerGone                  base.Code = 5002 // client should disconnect from scheduler
 	SchedPeerRegisterFail          base.Code = 5003
diff --git a/internal/idgen/task_id.go b/internal/idgen/task_id.go
index f665b67a..cd5fc905 100644
--- a/internal/idgen/task_id.go
+++ b/internal/idgen/task_id.go
@@ -32,9 +32,14 @@ const (
 
 // GenerateTaskID generates a taskId.
 // filter is separated by & character.
-func TaskID(url string, filter string, meta *base.UrlMeta, bizID string) string {
+func TaskID(url string, meta *base.UrlMeta) string {
 	var data []string
 
+	filter := ""
+	if meta != nil {
+		filter = meta.Filter
+	}
+
 	data = append(data, urlutils.FilterURLParam(url, strings.Split(filter, "&")))
 
 	if meta != nil {
@@ -45,18 +50,18 @@ func TaskID(url string, filter string, meta *base.UrlMeta, bizID string) string
 		if meta.Range != "" {
 			data = append(data, meta.Range)
 		}
-	}
 
-	if bizID != "" {
-		data = append(data, bizID)
+		if meta.Tag != "" {
+			data = append(data, meta.Tag)
+		}
 	}
 
 	return digestutils.Sha256(data...)
 }
 
 // GenerateTwinsTaskId used A/B testing
-func TwinsTaskID(url string, filter string, meta *base.UrlMeta, bizID, peerID string) string {
-	taskID := TaskID(url, filter, meta, bizID)
+func TwinsTaskID(url string, meta *base.UrlMeta, peerID string) string {
+	taskID := TaskID(url, meta)
 
 	if crc32.ChecksumIEEE([]byte(peerID))&1 == 0 {
 		taskID += TwinsASuffix
diff --git a/manager/service/service_grpc.go b/manager/service/service_grpc.go
index 573927a6..e85470fa 100644
--- a/manager/service/service_grpc.go
+++ b/manager/service/service_grpc.go
@@ -386,7 +386,7 @@ func (s *GRPC) UpdateScheduler(ctx context.Context, req *manager.UpdateScheduler
 	}, nil
 }
 
-func (s *GRPC) AddSchedulerClusterToSchedulerCluster(ctx context.Context, req *manager.AddSchedulerClusterToSchedulerClusterRequest) (*emptypb.Empty, error) {
+func (s *GRPC) AddSchedulerToSchedulerCluster(ctx context.Context, req *manager.AddSchedulerToSchedulerClusterRequest) (*emptypb.Empty, error) {
 	if err := req.Validate(); err != nil {
 		return nil, status.Error(codes.InvalidArgument, err.Error())
 	}
diff --git a/pkg/rpc/cdnsystem/cdnsystem.pb.go b/pkg/rpc/cdnsystem/cdnsystem.pb.go
index 745e7723..745f520f 100644
--- a/pkg/rpc/cdnsystem/cdnsystem.pb.go
+++ b/pkg/rpc/cdnsystem/cdnsystem.pb.go
@@ -43,8 +43,7 @@ type SeedRequest struct {
 
 	TaskId  string        `protobuf:"bytes,1,opt,name=task_id,json=taskId,proto3" json:"task_id,omitempty"`
 	Url     string        `protobuf:"bytes,2,opt,name=url,proto3" json:"url,omitempty"`
-	Filter  string        `protobuf:"bytes,3,opt,name=filter,proto3" json:"filter,omitempty"`
-	UrlMeta *base.UrlMeta `protobuf:"bytes,4,opt,name=url_meta,json=urlMeta,proto3" json:"url_meta,omitempty"`
+	UrlMeta *base.UrlMeta `protobuf:"bytes,3,opt,name=url_meta,json=urlMeta,proto3" json:"url_meta,omitempty"`
 }
 
 func (x *SeedRequest) Reset() {
@@ -93,13 +92,6 @@ func (x *SeedRequest) GetUrl() string {
 	return ""
 }
 
-func (x *SeedRequest) GetFilter() string {
-	if x != nil {
-		return x.Filter
-	}
-	return ""
-}
-
 func (x *SeedRequest) GetUrlMeta() *base.UrlMeta {
 	if x != nil {
 		return x.UrlMeta
@@ -208,40 +200,38 @@ var file_pkg_rpc_cdnsystem_cdnsystem_proto_rawDesc = []byte{
 	0x74, 0x65, 0x6d, 0x2f, 0x63, 0x64, 0x6e, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x70, 0x72,
 	0x6f, 0x74, 0x6f, 0x12, 0x09, 0x63, 0x64, 0x6e, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x1a, 0x17,
 	0x70, 0x6b, 0x67, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x62, 0x61, 0x73, 0x65, 0x2f, 0x62, 0x61, 0x73,
-	0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x7a, 0x0a, 0x0b, 0x53, 0x65, 0x65, 0x64, 0x52,
+	0x65, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x62, 0x0a, 0x0b, 0x53, 0x65, 0x65, 0x64, 0x52,
 	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69,
 	0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12,
 	0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72,
-	0x6c, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x18, 0x03, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74, 0x65, 0x72, 0x12, 0x28, 0x0a, 0x08, 0x75, 0x72, 0x6c,
-	0x5f, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x04, 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, 0x22, 0xd8, 0x01, 0x0a, 0x09, 0x50, 0x69, 0x65, 0x63, 0x65, 0x53, 0x65, 0x65,
-	0x64, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x6f,
-	0x73, 0x74, 0x5f, 0x75, 0x75, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68,
-	0x6f, 0x73, 0x74, 0x55, 0x75, 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, 0x12, 0x0a, 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x18,
-	0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x63,
-	0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x6c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x06, 0x20,
-	0x01, 0x28, 0x03, 0x52, 0x0d, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x4c, 0x65, 0x6e, 0x67,
-	0x74, 0x68, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x5f, 0x70, 0x69, 0x65, 0x63,
-	0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x74,
-	0x6f, 0x74, 0x61, 0x6c, 0x50, 0x69, 0x65, 0x63, 0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x32, 0x83,
-	0x01, 0x0a, 0x06, 0x53, 0x65, 0x65, 0x64, 0x65, 0x72, 0x12, 0x3d, 0x0a, 0x0b, 0x4f, 0x62, 0x74,
-	0x61, 0x69, 0x6e, 0x53, 0x65, 0x65, 0x64, 0x73, 0x12, 0x16, 0x2e, 0x63, 0x64, 0x6e, 0x73, 0x79,
-	0x73, 0x74, 0x65, 0x6d, 0x2e, 0x53, 0x65, 0x65, 0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
-	0x1a, 0x14, 0x2e, 0x63, 0x64, 0x6e, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x50, 0x69, 0x65,
-	0x63, 0x65, 0x53, 0x65, 0x65, 0x64, 0x30, 0x01, 0x12, 0x3a, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x50,
-	0x69, 0x65, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x16, 0x2e, 0x62, 0x61, 0x73, 0x65,
-	0x2e, 0x50, 0x69, 0x65, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
-	0x74, 0x1a, 0x11, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x50, 0x69, 0x65, 0x63, 0x65, 0x50, 0x61,
-	0x63, 0x6b, 0x65, 0x74, 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, 0x63, 0x64, 0x6e, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x62, 0x06, 0x70,
-	0x72, 0x6f, 0x74, 0x6f, 0x33,
+	0x6c, 0x12, 0x28, 0x0a, 0x08, 0x75, 0x72, 0x6c, 0x5f, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x03, 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, 0x22, 0xd8, 0x01, 0x0a, 0x09,
+	0x50, 0x69, 0x65, 0x63, 0x65, 0x53, 0x65, 0x65, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65,
+	0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72,
+	0x49, 0x64, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x75, 0x75, 0x69, 0x64, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x55, 0x75, 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,
+	0x12, 0x0a, 0x04, 0x64, 0x6f, 0x6e, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x08, 0x52, 0x04, 0x64,
+	0x6f, 0x6e, 0x65, 0x12, 0x25, 0x0a, 0x0e, 0x63, 0x6f, 0x6e, 0x74, 0x65, 0x6e, 0x74, 0x5f, 0x6c,
+	0x65, 0x6e, 0x67, 0x74, 0x68, 0x18, 0x06, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0d, 0x63, 0x6f, 0x6e,
+	0x74, 0x65, 0x6e, 0x74, 0x4c, 0x65, 0x6e, 0x67, 0x74, 0x68, 0x12, 0x2a, 0x0a, 0x11, 0x74, 0x6f,
+	0x74, 0x61, 0x6c, 0x5f, 0x70, 0x69, 0x65, 0x63, 0x65, 0x5f, 0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18,
+	0x07, 0x20, 0x01, 0x28, 0x05, 0x52, 0x0f, 0x74, 0x6f, 0x74, 0x61, 0x6c, 0x50, 0x69, 0x65, 0x63,
+	0x65, 0x43, 0x6f, 0x75, 0x6e, 0x74, 0x32, 0x83, 0x01, 0x0a, 0x06, 0x53, 0x65, 0x65, 0x64, 0x65,
+	0x72, 0x12, 0x3d, 0x0a, 0x0b, 0x4f, 0x62, 0x74, 0x61, 0x69, 0x6e, 0x53, 0x65, 0x65, 0x64, 0x73,
+	0x12, 0x16, 0x2e, 0x63, 0x64, 0x6e, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x2e, 0x53, 0x65, 0x65,
+	0x64, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x14, 0x2e, 0x63, 0x64, 0x6e, 0x73, 0x79,
+	0x73, 0x74, 0x65, 0x6d, 0x2e, 0x50, 0x69, 0x65, 0x63, 0x65, 0x53, 0x65, 0x65, 0x64, 0x30, 0x01,
+	0x12, 0x3a, 0x0a, 0x0d, 0x47, 0x65, 0x74, 0x50, 0x69, 0x65, 0x63, 0x65, 0x54, 0x61, 0x73, 0x6b,
+	0x73, 0x12, 0x16, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x50, 0x69, 0x65, 0x63, 0x65, 0x54, 0x61,
+	0x73, 0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x11, 0x2e, 0x62, 0x61, 0x73, 0x65,
+	0x2e, 0x50, 0x69, 0x65, 0x63, 0x65, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74, 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, 0x63, 0x64, 0x6e, 0x73,
+	0x79, 0x73, 0x74, 0x65, 0x6d, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
diff --git a/pkg/rpc/cdnsystem/cdnsystem.pb.validate.go b/pkg/rpc/cdnsystem/cdnsystem.pb.validate.go
index c2604189..68f7b8a9 100644
--- a/pkg/rpc/cdnsystem/cdnsystem.pb.validate.go
+++ b/pkg/rpc/cdnsystem/cdnsystem.pb.validate.go
@@ -45,8 +45,6 @@ func (m *SeedRequest) Validate() error {
 
 	// no validation rules for Url
 
-	// no validation rules for Filter
-
 	if v, ok := interface{}(m.GetUrlMeta()).(interface{ Validate() error }); ok {
 		if err := v.Validate(); err != nil {
 			return SeedRequestValidationError{
diff --git a/pkg/rpc/cdnsystem/cdnsystem.proto b/pkg/rpc/cdnsystem/cdnsystem.proto
index 20f42fd5..7c1255b7 100644
--- a/pkg/rpc/cdnsystem/cdnsystem.proto
+++ b/pkg/rpc/cdnsystem/cdnsystem.proto
@@ -25,8 +25,7 @@ option go_package = "d7y.io/dragonfly/v2/pkg/rpc/cdnsystem";
 message SeedRequest{
   string task_id = 1;
   string url = 2;
-  string filter = 3;
-  base.UrlMeta url_meta = 4;
+  base.UrlMeta url_meta = 3;
 }
 
 // keep piece meta and data separately
diff --git a/pkg/rpc/cdnsystem/cdnsystem_grpc.pb.go b/pkg/rpc/cdnsystem/cdnsystem_grpc.pb.go
index d5b70a7c..f2994552 100644
--- a/pkg/rpc/cdnsystem/cdnsystem_grpc.pb.go
+++ b/pkg/rpc/cdnsystem/cdnsystem_grpc.pb.go
@@ -12,6 +12,7 @@ import (
 
 // This is a compile-time assertion to ensure that this generated file
 // is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
 const _ = grpc.SupportPackageIsVersion7
 
 // SeederClient is the client API for Seeder service.
@@ -33,7 +34,7 @@ func NewSeederClient(cc grpc.ClientConnInterface) SeederClient {
 }
 
 func (c *seederClient) ObtainSeeds(ctx context.Context, in *SeedRequest, opts ...grpc.CallOption) (Seeder_ObtainSeedsClient, error) {
-	stream, err := c.cc.NewStream(ctx, &_Seeder_serviceDesc.Streams[0], "/cdnsystem.Seeder/ObtainSeeds", opts...)
+	stream, err := c.cc.NewStream(ctx, &Seeder_ServiceDesc.Streams[0], "/cdnsystem.Seeder/ObtainSeeds", opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -104,7 +105,7 @@ type UnsafeSeederServer interface {
 }
 
 func RegisterSeederServer(s grpc.ServiceRegistrar, srv SeederServer) {
-	s.RegisterService(&_Seeder_serviceDesc, srv)
+	s.RegisterService(&Seeder_ServiceDesc, srv)
 }
 
 func _Seeder_ObtainSeeds_Handler(srv interface{}, stream grpc.ServerStream) error {
@@ -146,7 +147,10 @@ func _Seeder_GetPieceTasks_Handler(srv interface{}, ctx context.Context, dec fun
 	return interceptor(ctx, in, info, handler)
 }
 
-var _Seeder_serviceDesc = grpc.ServiceDesc{
+// Seeder_ServiceDesc is the grpc.ServiceDesc for Seeder service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var Seeder_ServiceDesc = grpc.ServiceDesc{
 	ServiceName: "cdnsystem.Seeder",
 	HandlerType: (*SeederServer)(nil),
 	Methods: []grpc.MethodDesc{
diff --git a/pkg/rpc/client.go b/pkg/rpc/client.go
index a8663934..505acd58 100644
--- a/pkg/rpc/client.go
+++ b/pkg/rpc/client.go
@@ -26,7 +26,6 @@ import (
 	"d7y.io/dragonfly/v2/internal/dferrors"
 	logger "d7y.io/dragonfly/v2/internal/dflog"
 	"d7y.io/dragonfly/v2/pkg/basic/dfnet"
-	"d7y.io/dragonfly/v2/pkg/synclock"
 	"github.com/pkg/errors"
 	"github.com/serialx/hashring"
 	"google.golang.org/grpc"
@@ -55,7 +54,7 @@ type ConnStatus string
 type Connection struct {
 	ctx            context.Context
 	cancelFun      context.CancelFunc
-	rwMutex        *synclock.LockerPool
+	rwMutex        sync.RWMutex
 	dialOpts       []grpc.DialOption
 	key2NodeMap    sync.Map // key -> node(many to one)
 	node2ClientMap sync.Map // node -> clientConn(one to one)
@@ -75,11 +74,7 @@ func newDefaultConnection(ctx context.Context) *Connection {
 	return &Connection{
 		ctx:            childCtx,
 		cancelFun:      cancel,
-		rwMutex:        synclock.NewLockerPool(),
 		dialOpts:       defaultClientOpts,
-		key2NodeMap:    sync.Map{},
-		node2ClientMap: sync.Map{},
-		accessNodeMap:  sync.Map{},
 		connExpireTime: defaultConnExpireTime,
 		gcConnTimeout:  defaultGcConnTimeout,
 		gcConnInterval: defaultGcConnInterval,
@@ -169,10 +164,10 @@ func (conn *Connection) CorrectKey2NodeRelation(tmpHashKey, realHashKey string)
 	if tmpHashKey == realHashKey {
 		return
 	}
+	conn.rwMutex.Lock()
+	defer conn.rwMutex.Unlock()
 	key, _ := conn.key2NodeMap.Load(tmpHashKey)
 	serverNode := key.(string)
-	conn.rwMutex.Lock(serverNode, false)
-	defer conn.rwMutex.UnLock(serverNode, false)
 	conn.key2NodeMap.Store(realHashKey, serverNode)
 	conn.key2NodeMap.Delete(tmpHashKey)
 }
@@ -197,11 +192,11 @@ func (conn *Connection) UpdateAccessNodeMapByServerNode(serverNode string) {
 }
 
 func (conn *Connection) AddServerNodes(addrs []dfnet.NetAddr) error {
+	conn.rwMutex.Lock()
+	defer conn.rwMutex.Unlock()
 	for _, addr := range addrs {
 		serverNode := addr.GetEndpoint()
-		conn.rwMutex.Lock(serverNode, false)
 		conn.hashRing = conn.hashRing.AddNode(serverNode)
-		conn.rwMutex.UnLock(serverNode, false)
 		logger.With("conn", conn.name).Debugf("success add %s to server node list", addr)
 	}
 	return nil
@@ -209,6 +204,21 @@ func (conn *Connection) AddServerNodes(addrs []dfnet.NetAddr) error {
 
 // findCandidateClientConn find candidate node client conn other than exclusiveNodes
 func (conn *Connection) findCandidateClientConn(key string, exclusiveNodes ...string) (*candidateClient, error) {
+	if node, ok := conn.key2NodeMap.Load(key); ok {
+		candidateNode := node.(string)
+		selected := true
+		for _, exclusiveNode := range exclusiveNodes {
+			if exclusiveNode == candidateNode {
+				selected = false
+			}
+		}
+		if selected {
+			if client, ok := conn.node2ClientMap.Load(node); ok {
+				return client.(*candidateClient), nil
+			}
+		}
+	}
+
 	ringNodes, ok := conn.hashRing.GetNodes(key, conn.hashRing.Size())
 	if !ok {
 		logger.Warnf("cannot obtain expected %d server nodes", conn.hashRing.Size())
@@ -231,12 +241,10 @@ func (conn *Connection) findCandidateClientConn(key string, exclusiveNodes ...st
 	logger.With("conn", conn.name).Infof("candidate result for hash key %s: all server node list: %v, exclusiveNodes node list: %v, candidate node list: %v",
 		key, ringNodes, exclusiveNodes, candidateNodes)
 	for _, candidateNode := range candidateNodes {
-		conn.rwMutex.Lock(candidateNode, true)
 		// Check whether there is a corresponding mapping client in the node2ClientMap
 		// TODO 下面部分可以直接调用loadOrCreate方法，但是日志没有这么调用打印全
 		if client, ok := conn.node2ClientMap.Load(candidateNode); ok {
 			logger.With("conn", conn.name).Infof("hit cache candidateNode %s for hash key %s", candidateNode, key)
-			conn.rwMutex.UnLock(candidateNode, true)
 			return &candidateClient{
 				node: candidateNode,
 				Ref:  client,
@@ -246,7 +254,6 @@ func (conn *Connection) findCandidateClientConn(key string, exclusiveNodes ...st
 		clientConn, err := conn.createClient(candidateNode, append(defaultClientOpts, conn.dialOpts...)...)
 		if err == nil {
 			logger.With("conn", conn.name).Infof("success connect to candidateNode %s for hash key %s", candidateNode, key)
-			conn.rwMutex.UnLock(candidateNode, true)
 			return &candidateClient{
 				node: candidateNode,
 				Ref:  clientConn,
@@ -254,7 +261,6 @@ func (conn *Connection) findCandidateClientConn(key string, exclusiveNodes ...st
 		}
 
 		logger.With("conn", conn.name).Infof("failed to connect candidateNode %s for hash key %s: %v", candidateNode, key, err)
-		conn.rwMutex.UnLock(candidateNode, true)
 	}
 	return nil, dferrors.ErrNoCandidateNode
 }
@@ -273,6 +279,8 @@ func (conn *Connection) createClient(target string, opts ...grpc.DialOption) (*g
 
 // GetServerNode
 func (conn *Connection) GetServerNode(hashKey string) (string, bool) {
+	conn.rwMutex.RLock()
+	defer conn.rwMutex.RUnlock()
 	node, ok := conn.key2NodeMap.Load(hashKey)
 	serverNode := node.(string)
 	if ok {
@@ -283,8 +291,8 @@ func (conn *Connection) GetServerNode(hashKey string) (string, bool) {
 
 func (conn *Connection) GetClientConnByTarget(node string) (*grpc.ClientConn, error) {
 	logger.With("conn", conn.name).Debugf("start to get client conn by target %s", node)
-	conn.rwMutex.Lock(node, true)
-	defer conn.rwMutex.UnLock(node, true)
+	conn.rwMutex.RLock()
+	defer conn.rwMutex.RUnlock()
 	clientConn, err := conn.loadOrCreateClientConnByNode(node)
 	if err != nil {
 		return nil, errors.Wrapf(err, "get client conn by conn %s", node)
@@ -322,30 +330,32 @@ func (conn *Connection) loadOrCreateClientConnByNode(node string) (clientConn *g
 // stick whether hash key need already associated with specify node
 func (conn *Connection) GetClientConn(hashKey string, stick bool) (*grpc.ClientConn, error) {
 	logger.With("conn", conn.name).Debugf("start to get client conn hashKey %s, stick %t", hashKey, stick)
+	conn.rwMutex.RLock()
 	node, ok := conn.key2NodeMap.Load(hashKey)
 	if stick && !ok {
+		conn.rwMutex.RUnlock()
 		// if request is stateful, hash key must exist in key2NodeMap
 		return nil, fmt.Errorf("it is a stateful request， but cannot find hash key(%s) in key2NodeMap", hashKey)
 	}
 	if ok {
 		// if exist
 		serverNode := node.(string)
-		conn.rwMutex.Lock(serverNode, true)
 		clientConn, err := conn.loadOrCreateClientConnByNode(serverNode)
-		conn.rwMutex.UnLock(serverNode, true)
+		conn.rwMutex.RUnlock()
 		if err != nil {
 			return nil, err
 		}
 		return clientConn, nil
 	}
 	logger.With("conn", conn.name).Infof("no server node associated with hash key %s was found, start find candidate", hashKey)
+	conn.rwMutex.RUnlock()
 	// if absence
+	conn.rwMutex.Lock()
+	defer conn.rwMutex.Unlock()
 	client, err := conn.findCandidateClientConn(hashKey)
 	if err != nil {
 		return nil, errors.Wrapf(err, "prob candidate client conn for hash key %s", hashKey)
 	}
-	conn.rwMutex.Lock(client.node, false)
-	defer conn.rwMutex.UnLock(client.node, false)
 	conn.key2NodeMap.Store(hashKey, client.node)
 	conn.node2ClientMap.Store(client.node, client.Ref)
 	conn.accessNodeMap.Store(client.node, time.Now())
@@ -363,19 +373,21 @@ func (conn *Connection) TryMigrate(key string, cause error, exclusiveNodes []str
 		}
 	}
 	currentNode := ""
+	conn.rwMutex.RLock()
 	if currentNode, ok := conn.key2NodeMap.Load(key); ok {
 		preNode = currentNode.(string)
 		exclusiveNodes = append(exclusiveNodes, currentNode.(string))
 	} else {
 		logger.With("conn", conn.name).Warnf("failed to find server node for hash key %s", key)
 	}
+	conn.rwMutex.RUnlock()
+	conn.rwMutex.Lock()
+	defer conn.rwMutex.Unlock()
 	client, err := conn.findCandidateClientConn(key, exclusiveNodes...)
 	if err != nil {
 		return "", errors.Wrapf(err, "find candidate client conn for hash key %s", key)
 	}
 	logger.With("conn", conn.name).Infof("successfully migrate hash key %s from server node %s to %s", key, currentNode, client.node)
-	conn.rwMutex.Lock(client.node, false)
-	defer conn.rwMutex.UnLock(client.node, false)
 	conn.key2NodeMap.Store(key, client.node)
 	conn.node2ClientMap.Store(client.node, client.Ref)
 	conn.accessNodeMap.Store(client.node, time.Now())
@@ -383,9 +395,10 @@ func (conn *Connection) TryMigrate(key string, cause error, exclusiveNodes []str
 }
 
 func (conn *Connection) Close() error {
+	conn.rwMutex.Lock()
+	defer conn.rwMutex.Unlock()
 	for i := range conn.serverNodes {
 		serverNode := conn.serverNodes[i].GetEndpoint()
-		conn.rwMutex.Lock(serverNode, false)
 		conn.hashRing.RemoveNode(serverNode)
 		value, ok := conn.node2ClientMap.Load(serverNode)
 		if ok {
@@ -406,19 +419,18 @@ func (conn *Connection) Close() error {
 			return true
 		})
 		conn.accessNodeMap.Delete(serverNode)
-		conn.rwMutex.UnLock(serverNode, false)
 	}
 	conn.cancelFun()
 	return nil
 }
 
 func (conn *Connection) UpdateState(addrs []dfnet.NetAddr) {
-	// TODO lock
-	conn.serverNodes = addrs
 	var addresses []string
 	for _, addr := range addrs {
 		addresses = append(addresses, addr.GetEndpoint())
 	}
-
+	conn.rwMutex.Lock()
+	defer conn.rwMutex.Unlock()
+	conn.serverNodes = addrs
 	conn.hashRing = hashring.New(addresses)
 }
diff --git a/pkg/rpc/client_util.go b/pkg/rpc/client_util.go
index 03324f49..d6ddf92e 100644
--- a/pkg/rpc/client_util.go
+++ b/pkg/rpc/client_util.go
@@ -47,7 +47,7 @@ func (conn *Connection) startGC() {
 			startTime := time.Now()
 
 			// TODO use anther locker, @santong
-			//conn.rwMutex.Lock()
+			conn.rwMutex.Lock()
 			// range all connections and determine whether they are expired
 			conn.accessNodeMap.Range(func(node, accessTime interface{}) bool {
 				serverNode := node.(string)
@@ -61,7 +61,7 @@ func (conn *Connection) startGC() {
 				return true
 			})
 			// TODO use anther locker, @santong
-			//conn.rwMutex.Unlock()
+			conn.rwMutex.Unlock()
 			// slow GC detected, report it with a log warning
 			if timeElapse := time.Since(startTime); timeElapse > conn.gcConnTimeout {
 				logger.GrpcLogger.With("conn", conn.name).Warnf("gc %d conns, cost: %.3f seconds", removedConnCount, timeElapse.Seconds())
@@ -81,8 +81,6 @@ func (conn *Connection) startGC() {
 
 // gcConn gc keys and clients associated with server node
 func (conn *Connection) gcConn(node string) {
-	conn.rwMutex.Lock(node, false)
-	defer conn.rwMutex.UnLock(node, false)
 	logger.GrpcLogger.With("conn", conn.name).Infof("gc keys and clients associated with server node: %s starting", node)
 	value, ok := conn.node2ClientMap.Load(node)
 	if ok {
diff --git a/pkg/rpc/dfdaemon/client/client.go b/pkg/rpc/dfdaemon/client/client.go
index beb1f8d7..a23f2a0a 100644
--- a/pkg/rpc/dfdaemon/client/client.go
+++ b/pkg/rpc/dfdaemon/client/client.go
@@ -101,7 +101,7 @@ func (dc *daemonClient) getDaemonClientWithTarget(target string) (dfdaemon.Daemo
 func (dc *daemonClient) Download(ctx context.Context, req *dfdaemon.DownRequest, opts ...grpc.CallOption) (*DownResultStream, error) {
 	req.Uuid = uuid.New().String()
 	// generate taskID
-	taskID := idgen.TaskID(req.Url, req.UrlMeta.Filter, req.UrlMeta, req.UrlMeta.Tag)
+	taskID := idgen.TaskID(req.Url, req.UrlMeta)
 	return newDownResultStream(ctx, dc, taskID, req, opts)
 }
 
diff --git a/pkg/rpc/dfdaemon/dfdaemon_grpc.pb.go b/pkg/rpc/dfdaemon/dfdaemon_grpc.pb.go
index 851f7c11..c5e63251 100644
--- a/pkg/rpc/dfdaemon/dfdaemon_grpc.pb.go
+++ b/pkg/rpc/dfdaemon/dfdaemon_grpc.pb.go
@@ -13,6 +13,7 @@ import (
 
 // This is a compile-time assertion to ensure that this generated file
 // is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
 const _ = grpc.SupportPackageIsVersion7
 
 // DaemonClient is the client API for Daemon service.
@@ -36,7 +37,7 @@ func NewDaemonClient(cc grpc.ClientConnInterface) DaemonClient {
 }
 
 func (c *daemonClient) Download(ctx context.Context, in *DownRequest, opts ...grpc.CallOption) (Daemon_DownloadClient, error) {
-	stream, err := c.cc.NewStream(ctx, &_Daemon_serviceDesc.Streams[0], "/dfdaemon.Daemon/Download", opts...)
+	stream, err := c.cc.NewStream(ctx, &Daemon_ServiceDesc.Streams[0], "/dfdaemon.Daemon/Download", opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -121,7 +122,7 @@ type UnsafeDaemonServer interface {
 }
 
 func RegisterDaemonServer(s grpc.ServiceRegistrar, srv DaemonServer) {
-	s.RegisterService(&_Daemon_serviceDesc, srv)
+	s.RegisterService(&Daemon_ServiceDesc, srv)
 }
 
 func _Daemon_Download_Handler(srv interface{}, stream grpc.ServerStream) error {
@@ -181,7 +182,10 @@ func _Daemon_CheckHealth_Handler(srv interface{}, ctx context.Context, dec func(
 	return interceptor(ctx, in, info, handler)
 }
 
-var _Daemon_serviceDesc = grpc.ServiceDesc{
+// Daemon_ServiceDesc is the grpc.ServiceDesc for Daemon service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var Daemon_ServiceDesc = grpc.ServiceDesc{
 	ServiceName: "dfdaemon.Daemon",
 	HandlerType: (*DaemonServer)(nil),
 	Methods: []grpc.MethodDesc{
diff --git a/pkg/rpc/examples/cdnsystem/client/main.go b/pkg/rpc/examples/cdnsystem/client/main.go
index abc72594..c21ee64e 100644
--- a/pkg/rpc/examples/cdnsystem/client/main.go
+++ b/pkg/rpc/examples/cdnsystem/client/main.go
@@ -21,6 +21,7 @@ import (
 
 	"d7y.io/dragonfly/v2/internal/dflog/logcore"
 	"d7y.io/dragonfly/v2/pkg/basic/dfnet"
+	"d7y.io/dragonfly/v2/pkg/rpc/base"
 	_ "d7y.io/dragonfly/v2/pkg/rpc/scheduler/server"
 
 	"context"
@@ -49,7 +50,9 @@ func main() {
 			psc, _ := c.ObtainSeeds(context.TODO(), &cdnsystem.SeedRequest{
 				TaskId: "test2",
 				Url:    "https://desktop.docker.com/mac/stable/amd64/Docker.dmg",
-				Filter: "",
+				UrlMeta: &base.UrlMeta{
+					Filter: "",
+				},
 			})
 
 			//psc, _ := c.ObtainSeeds(context.TODO(), &cdnsystem.SeedRequest{
diff --git a/pkg/rpc/manager/manager.pb.go b/pkg/rpc/manager/manager.pb.go
index 1335791a..2c48a248 100644
--- a/pkg/rpc/manager/manager.pb.go
+++ b/pkg/rpc/manager/manager.pb.go
@@ -940,7 +940,7 @@ func (x *UpdateSchedulerRequest) GetPort() int32 {
 	return 0
 }
 
-type AddSchedulerClusterToSchedulerClusterRequest struct {
+type AddSchedulerToSchedulerClusterRequest struct {
 	state         protoimpl.MessageState
 	sizeCache     protoimpl.SizeCache
 	unknownFields protoimpl.UnknownFields
@@ -950,8 +950,8 @@ type AddSchedulerClusterToSchedulerClusterRequest struct {
 	SchedulerClusterId uint64     `protobuf:"varint,3,opt,name=scheduler_cluster_id,json=schedulerClusterId,proto3" json:"scheduler_cluster_id,omitempty"`
 }
 
-func (x *AddSchedulerClusterToSchedulerClusterRequest) Reset() {
-	*x = AddSchedulerClusterToSchedulerClusterRequest{}
+func (x *AddSchedulerToSchedulerClusterRequest) Reset() {
+	*x = AddSchedulerToSchedulerClusterRequest{}
 	if protoimpl.UnsafeEnabled {
 		mi := &file_pkg_rpc_manager_manager_proto_msgTypes[10]
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -959,13 +959,13 @@ func (x *AddSchedulerClusterToSchedulerClusterRequest) Reset() {
 	}
 }
 
-func (x *AddSchedulerClusterToSchedulerClusterRequest) String() string {
+func (x *AddSchedulerToSchedulerClusterRequest) String() string {
 	return protoimpl.X.MessageStringOf(x)
 }
 
-func (*AddSchedulerClusterToSchedulerClusterRequest) ProtoMessage() {}
+func (*AddSchedulerToSchedulerClusterRequest) ProtoMessage() {}
 
-func (x *AddSchedulerClusterToSchedulerClusterRequest) ProtoReflect() protoreflect.Message {
+func (x *AddSchedulerToSchedulerClusterRequest) ProtoReflect() protoreflect.Message {
 	mi := &file_pkg_rpc_manager_manager_proto_msgTypes[10]
 	if protoimpl.UnsafeEnabled && x != nil {
 		ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
@@ -977,26 +977,26 @@ func (x *AddSchedulerClusterToSchedulerClusterRequest) ProtoReflect() protorefle
 	return mi.MessageOf(x)
 }
 
-// Deprecated: Use AddSchedulerClusterToSchedulerClusterRequest.ProtoReflect.Descriptor instead.
-func (*AddSchedulerClusterToSchedulerClusterRequest) Descriptor() ([]byte, []int) {
+// Deprecated: Use AddSchedulerToSchedulerClusterRequest.ProtoReflect.Descriptor instead.
+func (*AddSchedulerToSchedulerClusterRequest) Descriptor() ([]byte, []int) {
 	return file_pkg_rpc_manager_manager_proto_rawDescGZIP(), []int{10}
 }
 
-func (x *AddSchedulerClusterToSchedulerClusterRequest) GetSourceType() SourceType {
+func (x *AddSchedulerToSchedulerClusterRequest) GetSourceType() SourceType {
 	if x != nil {
 		return x.SourceType
 	}
 	return SourceType_SCHEDULER_SOURCE
 }
 
-func (x *AddSchedulerClusterToSchedulerClusterRequest) GetSchedulerId() uint64 {
+func (x *AddSchedulerToSchedulerClusterRequest) GetSchedulerId() uint64 {
 	if x != nil {
 		return x.SchedulerId
 	}
 	return 0
 }
 
-func (x *AddSchedulerClusterToSchedulerClusterRequest) GetSchedulerClusterId() uint64 {
+func (x *AddSchedulerToSchedulerClusterRequest) GetSchedulerClusterId() uint64 {
 	if x != nil {
 		return x.SchedulerClusterId
 	}
@@ -1317,97 +1317,95 @@ var file_pkg_rpc_manager_manager_proto_rawDesc = []byte{
 	0x69, 0x70, 0x18, 0x08, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x70,
 	0x01, 0x52, 0x02, 0x69, 0x70, 0x12, 0x20, 0x0a, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x09, 0x20,
 	0x01, 0x28, 0x05, 0x42, 0x0c, 0xfa, 0x42, 0x09, 0x1a, 0x07, 0x10, 0xff, 0xff, 0x03, 0x28, 0x80,
-	0x08, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0xd5, 0x01, 0x0a, 0x2c, 0x41, 0x64, 0x64, 0x53,
-	0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x54,
-	0x6f, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65,
-	0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3e, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72,
-	0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, 0x2e,
-	0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79,
-	0x70, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x73, 0x6f,
-	0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x2a, 0x0a, 0x0c, 0x73, 0x63, 0x68, 0x65,
-	0x64, 0x75, 0x6c, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x07,
-	0xfa, 0x42, 0x04, 0x32, 0x02, 0x40, 0x01, 0x52, 0x0b, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
-	0x65, 0x72, 0x49, 0x64, 0x12, 0x39, 0x0a, 0x14, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65,
-	0x72, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01,
-	0x28, 0x04, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x32, 0x02, 0x40, 0x01, 0x52, 0x12, 0x73, 0x63, 0x68,
-	0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x22,
-	0xa8, 0x02, 0x0a, 0x15, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65,
-	0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3e, 0x0a, 0x0b, 0x73, 0x6f, 0x75,
-	0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13,
-	0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54,
-	0x79, 0x70, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x73,
-	0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x09, 0x68, 0x6f, 0x73,
-	0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42,
-	0x04, 0x72, 0x02, 0x68, 0x01, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12,
-	0x17, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04,
-	0x72, 0x02, 0x70, 0x01, 0x52, 0x02, 0x69, 0x70, 0x12, 0x53, 0x0a, 0x09, 0x68, 0x6f, 0x73, 0x74,
-	0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6d, 0x61,
-	0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75,
-	0x6c, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x2e, 0x48, 0x6f, 0x73, 0x74,
-	0x49, 0x6e, 0x66, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x9a, 0x01,
-	0x02, 0x30, 0x01, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x3b, 0x0a,
-	0x0d, 0x48, 0x6f, 0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10,
-	0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79,
-	0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x4c, 0x0a, 0x16, 0x4c, 0x69,
-	0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70,
-	0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a, 0x0a, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65,
-	0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67,
-	0x65, 0x72, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x0a, 0x73, 0x63,
-	0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x73, 0x22, 0x78, 0x0a, 0x10, 0x4b, 0x65, 0x65, 0x70,
-	0x41, 0x6c, 0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3e, 0x0a, 0x0b,
-	0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28,
-	0x0e, 0x32, 0x13, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x6f, 0x75, 0x72,
-	0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01,
-	0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x09,
-	0x68, 0x6f, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42,
-	0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x68, 0x01, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x4e, 0x61,
-	0x6d, 0x65, 0x2a, 0x45, 0x0a, 0x0a, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65,
-	0x12, 0x14, 0x0a, 0x10, 0x53, 0x43, 0x48, 0x45, 0x44, 0x55, 0x4c, 0x45, 0x52, 0x5f, 0x53, 0x4f,
-	0x55, 0x52, 0x43, 0x45, 0x10, 0x00, 0x12, 0x11, 0x0a, 0x0d, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54,
-	0x5f, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x43, 0x44, 0x4e,
-	0x5f, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x10, 0x02, 0x32, 0xd8, 0x04, 0x0a, 0x07, 0x4d, 0x61,
-	0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x2e, 0x0a, 0x06, 0x47, 0x65, 0x74, 0x43, 0x44, 0x4e, 0x12,
-	0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x44, 0x4e,
-	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65,
-	0x72, 0x2e, 0x43, 0x44, 0x4e, 0x12, 0x34, 0x0a, 0x09, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43,
-	0x44, 0x4e, 0x12, 0x19, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x55, 0x70, 0x64,
-	0x61, 0x74, 0x65, 0x43, 0x44, 0x4e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e,
-	0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x44, 0x4e, 0x12, 0x50, 0x0a, 0x12, 0x41,
-	0x64, 0x64, 0x43, 0x44, 0x4e, 0x54, 0x6f, 0x43, 0x44, 0x4e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65,
-	0x72, 0x12, 0x22, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, 0x64, 0x64, 0x43,
-	0x44, 0x4e, 0x54, 0x6f, 0x43, 0x44, 0x4e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65,
+	0x08, 0x52, 0x04, 0x70, 0x6f, 0x72, 0x74, 0x22, 0xce, 0x01, 0x0a, 0x25, 0x41, 0x64, 0x64, 0x53,
+	0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x54, 0x6f, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75,
+	0x6c, 0x65, 0x72, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
+	0x74, 0x12, 0x3e, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70, 0x65,
+	0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72,
+	0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x08, 0xfa, 0x42, 0x05,
+	0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70,
+	0x65, 0x12, 0x2a, 0x0a, 0x0c, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x5f, 0x69,
+	0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x04, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x32, 0x02, 0x40, 0x01,
+	0x52, 0x0b, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x49, 0x64, 0x12, 0x39, 0x0a,
+	0x14, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x5f, 0x63, 0x6c, 0x75, 0x73, 0x74,
+	0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x04, 0x42, 0x07, 0xfa, 0x42, 0x04,
+	0x32, 0x02, 0x40, 0x01, 0x52, 0x12, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x43,
+	0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x49, 0x64, 0x22, 0xa8, 0x02, 0x0a, 0x15, 0x4c, 0x69, 0x73,
+	0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 0x74, 0x12, 0x3e, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f, 0x74, 0x79, 0x70,
+	0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65,
+	0x72, 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x42, 0x08, 0xfa, 0x42,
+	0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79,
+	0x70, 0x65, 0x12, 0x24, 0x0a, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18,
+	0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x68, 0x01, 0x52, 0x08,
+	0x68, 0x6f, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x12, 0x17, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x03,
+	0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x70, 0x01, 0x52, 0x02, 0x69,
+	0x70, 0x12, 0x53, 0x0a, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x69, 0x6e, 0x66, 0x6f, 0x18, 0x04,
+	0x20, 0x03, 0x28, 0x0b, 0x32, 0x2c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x4c,
+	0x69, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x2e, 0x48, 0x6f, 0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x45, 0x6e, 0x74,
+	0x72, 0x79, 0x42, 0x08, 0xfa, 0x42, 0x05, 0x9a, 0x01, 0x02, 0x30, 0x01, 0x52, 0x08, 0x68, 0x6f,
+	0x73, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x1a, 0x3b, 0x0a, 0x0d, 0x48, 0x6f, 0x73, 0x74, 0x49, 0x6e,
+	0x66, 0x6f, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01,
+	0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c,
+	0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a,
+	0x02, 0x38, 0x01, 0x22, 0x4c, 0x0a, 0x16, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64,
+	0x75, 0x6c, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x32, 0x0a,
+	0x0a, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28,
+	0x0b, 0x32, 0x12, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x63, 0x68, 0x65,
+	0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x0a, 0x73, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72,
+	0x73, 0x22, 0x78, 0x0a, 0x10, 0x4b, 0x65, 0x65, 0x70, 0x41, 0x6c, 0x69, 0x76, 0x65, 0x52, 0x65,
+	0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x3e, 0x0a, 0x0b, 0x73, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x5f,
+	0x74, 0x79, 0x70, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x13, 0x2e, 0x6d, 0x61, 0x6e,
+	0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x42,
+	0x08, 0xfa, 0x42, 0x05, 0x82, 0x01, 0x02, 0x10, 0x01, 0x52, 0x0a, 0x73, 0x6f, 0x75, 0x72, 0x63,
+	0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x24, 0x0a, 0x09, 0x68, 0x6f, 0x73, 0x74, 0x5f, 0x6e, 0x61,
+	0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x42, 0x07, 0xfa, 0x42, 0x04, 0x72, 0x02, 0x68,
+	0x01, 0x52, 0x08, 0x68, 0x6f, 0x73, 0x74, 0x4e, 0x61, 0x6d, 0x65, 0x2a, 0x45, 0x0a, 0x0a, 0x53,
+	0x6f, 0x75, 0x72, 0x63, 0x65, 0x54, 0x79, 0x70, 0x65, 0x12, 0x14, 0x0a, 0x10, 0x53, 0x43, 0x48,
+	0x45, 0x44, 0x55, 0x4c, 0x45, 0x52, 0x5f, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45, 0x10, 0x00, 0x12,
+	0x11, 0x0a, 0x0d, 0x43, 0x4c, 0x49, 0x45, 0x4e, 0x54, 0x5f, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45,
+	0x10, 0x01, 0x12, 0x0e, 0x0a, 0x0a, 0x43, 0x44, 0x4e, 0x5f, 0x53, 0x4f, 0x55, 0x52, 0x43, 0x45,
+	0x10, 0x02, 0x32, 0xca, 0x04, 0x0a, 0x07, 0x4d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x12, 0x2e,
+	0x0a, 0x06, 0x47, 0x65, 0x74, 0x43, 0x44, 0x4e, 0x12, 0x16, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67,
+	0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x43, 0x44, 0x4e, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74,
+	0x1a, 0x0c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x43, 0x44, 0x4e, 0x12, 0x34,
+	0x0a, 0x09, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x44, 0x4e, 0x12, 0x19, 0x2e, 0x6d, 0x61,
+	0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x43, 0x44, 0x4e, 0x52,
+	0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x0c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72,
+	0x2e, 0x43, 0x44, 0x4e, 0x12, 0x50, 0x0a, 0x12, 0x41, 0x64, 0x64, 0x43, 0x44, 0x4e, 0x54, 0x6f,
+	0x43, 0x44, 0x4e, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x12, 0x22, 0x2e, 0x6d, 0x61, 0x6e,
+	0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, 0x64, 0x64, 0x43, 0x44, 0x4e, 0x54, 0x6f, 0x43, 0x44, 0x4e,
+	0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 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, 0x40, 0x0a, 0x0c, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68,
+	0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x12, 0x1c, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72,
+	0x2e, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x71,
+	0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53,
+	0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x12, 0x46, 0x0a, 0x0f, 0x55, 0x70, 0x64, 0x61,
+	0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x12, 0x1f, 0x2e, 0x6d, 0x61,
+	0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65,
+	0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6d,
+	0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72,
+	0x12, 0x68, 0x0a, 0x1e, 0x41, 0x64, 0x64, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72,
+	0x54, 0x6f, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x43, 0x6c, 0x75, 0x73, 0x74,
+	0x65, 0x72, 0x12, 0x2e, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, 0x64, 0x64,
+	0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x54, 0x6f, 0x53, 0x63, 0x68, 0x65, 0x64,
+	0x75, 0x6c, 0x65, 0x72, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65,
+	0x73, 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, 0x51, 0x0a, 0x0e, 0x4c, 0x69,
+	0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x73, 0x12, 0x1e, 0x2e, 0x6d,
+	0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64,
+	0x75, 0x6c, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x1f, 0x2e, 0x6d,
+	0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64,
+	0x75, 0x6c, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e, 0x73, 0x65, 0x12, 0x40, 0x0a,
+	0x09, 0x4b, 0x65, 0x65, 0x70, 0x41, 0x6c, 0x69, 0x76, 0x65, 0x12, 0x19, 0x2e, 0x6d, 0x61, 0x6e,
+	0x61, 0x67, 0x65, 0x72, 0x2e, 0x4b, 0x65, 0x65, 0x70, 0x41, 0x6c, 0x69, 0x76, 0x65, 0x52, 0x65,
 	0x71, 0x75, 0x65, 0x73, 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, 0x40, 0x0a,
-	0x0c, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x12, 0x1c, 0x2e,
-	0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x47, 0x65, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64,
-	0x75, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6d, 0x61,
-	0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x12,
-	0x46, 0x0a, 0x0f, 0x55, 0x70, 0x64, 0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c,
-	0x65, 0x72, 0x12, 0x1f, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x55, 0x70, 0x64,
-	0x61, 0x74, 0x65, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x52, 0x65, 0x71, 0x75,
-	0x65, 0x73, 0x74, 0x1a, 0x12, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x53, 0x63,
-	0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x12, 0x76, 0x0a, 0x25, 0x41, 0x64, 0x64, 0x53, 0x63,
-	0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x54, 0x6f,
-	0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72,
-	0x12, 0x35, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x41, 0x64, 0x64, 0x53, 0x63,
-	0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72, 0x54, 0x6f,
-	0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x43, 0x6c, 0x75, 0x73, 0x74, 0x65, 0x72,
-	0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 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,
-	0x51, 0x0a, 0x0e, 0x4c, 0x69, 0x73, 0x74, 0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72,
-	0x73, 0x12, 0x1e, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74,
-	0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x73, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73,
-	0x74, 0x1a, 0x1f, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x4c, 0x69, 0x73, 0x74,
-	0x53, 0x63, 0x68, 0x65, 0x64, 0x75, 0x6c, 0x65, 0x72, 0x73, 0x52, 0x65, 0x73, 0x70, 0x6f, 0x6e,
-	0x73, 0x65, 0x12, 0x40, 0x0a, 0x09, 0x4b, 0x65, 0x65, 0x70, 0x41, 0x6c, 0x69, 0x76, 0x65, 0x12,
-	0x19, 0x2e, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x2e, 0x4b, 0x65, 0x65, 0x70, 0x41, 0x6c,
-	0x69, 0x76, 0x65, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 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, 0x28, 0x01, 0x42, 0x25, 0x5a, 0x23, 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, 0x6d, 0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f,
-	0x74, 0x6f, 0x33,
+	0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2e, 0x45, 0x6d, 0x70, 0x74, 0x79, 0x28, 0x01, 0x42,
+	0x25, 0x5a, 0x23, 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, 0x6d,
+	0x61, 0x6e, 0x61, 0x67, 0x65, 0x72, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33,
 }
 
 var (
@@ -1425,23 +1423,23 @@ func file_pkg_rpc_manager_manager_proto_rawDescGZIP() []byte {
 var file_pkg_rpc_manager_manager_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
 var file_pkg_rpc_manager_manager_proto_msgTypes = make([]protoimpl.MessageInfo, 15)
 var file_pkg_rpc_manager_manager_proto_goTypes = []interface{}{
-	(SourceType)(0),                                      // 0: manager.SourceType
-	(*CDNCluster)(nil),                                   // 1: manager.CDNCluster
-	(*SecurityGroup)(nil),                                // 2: manager.SecurityGroup
-	(*CDN)(nil),                                          // 3: manager.CDN
-	(*GetCDNRequest)(nil),                                // 4: manager.GetCDNRequest
-	(*UpdateCDNRequest)(nil),                             // 5: manager.UpdateCDNRequest
-	(*AddCDNToCDNClusterRequest)(nil),                    // 6: manager.AddCDNToCDNClusterRequest
-	(*SchedulerCluster)(nil),                             // 7: manager.SchedulerCluster
-	(*Scheduler)(nil),                                    // 8: manager.Scheduler
-	(*GetSchedulerRequest)(nil),                          // 9: manager.GetSchedulerRequest
-	(*UpdateSchedulerRequest)(nil),                       // 10: manager.UpdateSchedulerRequest
-	(*AddSchedulerClusterToSchedulerClusterRequest)(nil), // 11: manager.AddSchedulerClusterToSchedulerClusterRequest
-	(*ListSchedulersRequest)(nil),                        // 12: manager.ListSchedulersRequest
-	(*ListSchedulersResponse)(nil),                       // 13: manager.ListSchedulersResponse
-	(*KeepAliveRequest)(nil),                             // 14: manager.KeepAliveRequest
-	nil,                                                  // 15: manager.ListSchedulersRequest.HostInfoEntry
-	(*emptypb.Empty)(nil),                                // 16: google.protobuf.Empty
+	(SourceType)(0),                               // 0: manager.SourceType
+	(*CDNCluster)(nil),                            // 1: manager.CDNCluster
+	(*SecurityGroup)(nil),                         // 2: manager.SecurityGroup
+	(*CDN)(nil),                                   // 3: manager.CDN
+	(*GetCDNRequest)(nil),                         // 4: manager.GetCDNRequest
+	(*UpdateCDNRequest)(nil),                      // 5: manager.UpdateCDNRequest
+	(*AddCDNToCDNClusterRequest)(nil),             // 6: manager.AddCDNToCDNClusterRequest
+	(*SchedulerCluster)(nil),                      // 7: manager.SchedulerCluster
+	(*Scheduler)(nil),                             // 8: manager.Scheduler
+	(*GetSchedulerRequest)(nil),                   // 9: manager.GetSchedulerRequest
+	(*UpdateSchedulerRequest)(nil),                // 10: manager.UpdateSchedulerRequest
+	(*AddSchedulerToSchedulerClusterRequest)(nil), // 11: manager.AddSchedulerToSchedulerClusterRequest
+	(*ListSchedulersRequest)(nil),                 // 12: manager.ListSchedulersRequest
+	(*ListSchedulersResponse)(nil),                // 13: manager.ListSchedulersResponse
+	(*KeepAliveRequest)(nil),                      // 14: manager.KeepAliveRequest
+	nil,                                           // 15: manager.ListSchedulersRequest.HostInfoEntry
+	(*emptypb.Empty)(nil),                         // 16: google.protobuf.Empty
 }
 var file_pkg_rpc_manager_manager_proto_depIdxs = []int32{
 	2,  // 0: manager.CDNCluster.security_group:type_name -> manager.SecurityGroup
@@ -1454,7 +1452,7 @@ var file_pkg_rpc_manager_manager_proto_depIdxs = []int32{
 	3,  // 7: manager.Scheduler.cdns:type_name -> manager.CDN
 	0,  // 8: manager.GetSchedulerRequest.source_type:type_name -> manager.SourceType
 	0,  // 9: manager.UpdateSchedulerRequest.source_type:type_name -> manager.SourceType
-	0,  // 10: manager.AddSchedulerClusterToSchedulerClusterRequest.source_type:type_name -> manager.SourceType
+	0,  // 10: manager.AddSchedulerToSchedulerClusterRequest.source_type:type_name -> manager.SourceType
 	0,  // 11: manager.ListSchedulersRequest.source_type:type_name -> manager.SourceType
 	15, // 12: manager.ListSchedulersRequest.host_info:type_name -> manager.ListSchedulersRequest.HostInfoEntry
 	8,  // 13: manager.ListSchedulersResponse.schedulers:type_name -> manager.Scheduler
@@ -1464,7 +1462,7 @@ var file_pkg_rpc_manager_manager_proto_depIdxs = []int32{
 	6,  // 17: manager.Manager.AddCDNToCDNCluster:input_type -> manager.AddCDNToCDNClusterRequest
 	9,  // 18: manager.Manager.GetScheduler:input_type -> manager.GetSchedulerRequest
 	10, // 19: manager.Manager.UpdateScheduler:input_type -> manager.UpdateSchedulerRequest
-	11, // 20: manager.Manager.AddSchedulerClusterToSchedulerCluster:input_type -> manager.AddSchedulerClusterToSchedulerClusterRequest
+	11, // 20: manager.Manager.AddSchedulerToSchedulerCluster:input_type -> manager.AddSchedulerToSchedulerClusterRequest
 	12, // 21: manager.Manager.ListSchedulers:input_type -> manager.ListSchedulersRequest
 	14, // 22: manager.Manager.KeepAlive:input_type -> manager.KeepAliveRequest
 	3,  // 23: manager.Manager.GetCDN:output_type -> manager.CDN
@@ -1472,7 +1470,7 @@ var file_pkg_rpc_manager_manager_proto_depIdxs = []int32{
 	16, // 25: manager.Manager.AddCDNToCDNCluster:output_type -> google.protobuf.Empty
 	8,  // 26: manager.Manager.GetScheduler:output_type -> manager.Scheduler
 	8,  // 27: manager.Manager.UpdateScheduler:output_type -> manager.Scheduler
-	16, // 28: manager.Manager.AddSchedulerClusterToSchedulerCluster:output_type -> google.protobuf.Empty
+	16, // 28: manager.Manager.AddSchedulerToSchedulerCluster:output_type -> google.protobuf.Empty
 	13, // 29: manager.Manager.ListSchedulers:output_type -> manager.ListSchedulersResponse
 	16, // 30: manager.Manager.KeepAlive:output_type -> google.protobuf.Empty
 	23, // [23:31] is the sub-list for method output_type
@@ -1609,7 +1607,7 @@ func file_pkg_rpc_manager_manager_proto_init() {
 			}
 		}
 		file_pkg_rpc_manager_manager_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} {
-			switch v := v.(*AddSchedulerClusterToSchedulerClusterRequest); i {
+			switch v := v.(*AddSchedulerToSchedulerClusterRequest); i {
 			case 0:
 				return &v.state
 			case 1:
diff --git a/pkg/rpc/manager/manager.pb.validate.go b/pkg/rpc/manager/manager.pb.validate.go
index 60248060..5c7dbddc 100644
--- a/pkg/rpc/manager/manager.pb.validate.go
+++ b/pkg/rpc/manager/manager.pb.validate.go
@@ -1099,16 +1099,16 @@ var _ interface {
 	ErrorName() string
 } = UpdateSchedulerRequestValidationError{}
 
-// Validate checks the field values on
-// AddSchedulerClusterToSchedulerClusterRequest with the rules defined in the
-// proto definition for this message. If any rules are violated, an error is returned.
-func (m *AddSchedulerClusterToSchedulerClusterRequest) Validate() error {
+// Validate checks the field values on AddSchedulerToSchedulerClusterRequest
+// with the rules defined in the proto definition for this message. If any
+// rules are violated, an error is returned.
+func (m *AddSchedulerToSchedulerClusterRequest) Validate() error {
 	if m == nil {
 		return nil
 	}
 
 	if _, ok := SourceType_name[int32(m.GetSourceType())]; !ok {
-		return AddSchedulerClusterToSchedulerClusterRequestValidationError{
+		return AddSchedulerToSchedulerClusterRequestValidationError{
 			field:  "SourceType",
 			reason: "value must be one of the defined enum values",
 		}
@@ -1125,11 +1125,10 @@ func (m *AddSchedulerClusterToSchedulerClusterRequest) Validate() error {
 	return nil
 }
 
-// AddSchedulerClusterToSchedulerClusterRequestValidationError is the
-// validation error returned by
-// AddSchedulerClusterToSchedulerClusterRequest.Validate if the designated
-// constraints aren't met.
-type AddSchedulerClusterToSchedulerClusterRequestValidationError struct {
+// AddSchedulerToSchedulerClusterRequestValidationError is the validation error
+// returned by AddSchedulerToSchedulerClusterRequest.Validate if the
+// designated constraints aren't met.
+type AddSchedulerToSchedulerClusterRequestValidationError struct {
 	field  string
 	reason string
 	cause  error
@@ -1137,24 +1136,24 @@ type AddSchedulerClusterToSchedulerClusterRequestValidationError struct {
 }
 
 // Field function returns field value.
-func (e AddSchedulerClusterToSchedulerClusterRequestValidationError) Field() string { return e.field }
+func (e AddSchedulerToSchedulerClusterRequestValidationError) Field() string { return e.field }
 
 // Reason function returns reason value.
-func (e AddSchedulerClusterToSchedulerClusterRequestValidationError) Reason() string { return e.reason }
+func (e AddSchedulerToSchedulerClusterRequestValidationError) Reason() string { return e.reason }
 
 // Cause function returns cause value.
-func (e AddSchedulerClusterToSchedulerClusterRequestValidationError) Cause() error { return e.cause }
+func (e AddSchedulerToSchedulerClusterRequestValidationError) Cause() error { return e.cause }
 
 // Key function returns key value.
-func (e AddSchedulerClusterToSchedulerClusterRequestValidationError) Key() bool { return e.key }
+func (e AddSchedulerToSchedulerClusterRequestValidationError) Key() bool { return e.key }
 
 // ErrorName returns error name.
-func (e AddSchedulerClusterToSchedulerClusterRequestValidationError) ErrorName() string {
-	return "AddSchedulerClusterToSchedulerClusterRequestValidationError"
+func (e AddSchedulerToSchedulerClusterRequestValidationError) ErrorName() string {
+	return "AddSchedulerToSchedulerClusterRequestValidationError"
 }
 
 // Error satisfies the builtin error interface
-func (e AddSchedulerClusterToSchedulerClusterRequestValidationError) Error() string {
+func (e AddSchedulerToSchedulerClusterRequestValidationError) Error() string {
 	cause := ""
 	if e.cause != nil {
 		cause = fmt.Sprintf(" | caused by: %v", e.cause)
@@ -1166,14 +1165,14 @@ func (e AddSchedulerClusterToSchedulerClusterRequestValidationError) Error() str
 	}
 
 	return fmt.Sprintf(
-		"invalid %sAddSchedulerClusterToSchedulerClusterRequest.%s: %s%s",
+		"invalid %sAddSchedulerToSchedulerClusterRequest.%s: %s%s",
 		key,
 		e.field,
 		e.reason,
 		cause)
 }
 
-var _ error = AddSchedulerClusterToSchedulerClusterRequestValidationError{}
+var _ error = AddSchedulerToSchedulerClusterRequestValidationError{}
 
 var _ interface {
 	Field() string
@@ -1181,7 +1180,7 @@ var _ interface {
 	Key() bool
 	Cause() error
 	ErrorName() string
-} = AddSchedulerClusterToSchedulerClusterRequestValidationError{}
+} = AddSchedulerToSchedulerClusterRequestValidationError{}
 
 // Validate checks the field values on ListSchedulersRequest with the rules
 // defined in the proto definition for this message. If any rules are
diff --git a/pkg/rpc/manager/manager.proto b/pkg/rpc/manager/manager.proto
index 646c0889..b9fd873f 100644
--- a/pkg/rpc/manager/manager.proto
+++ b/pkg/rpc/manager/manager.proto
@@ -117,7 +117,7 @@ message UpdateSchedulerRequest {
   int32 port = 9 [(validate.rules).int32 = {gte: 1024, lt: 65535}];
 }
 
-message AddSchedulerClusterToSchedulerClusterRequest {
+message AddSchedulerToSchedulerClusterRequest {
   SourceType source_type = 1 [(validate.rules).enum.defined_only = true];
   uint64 scheduler_id = 2 [(validate.rules).uint64 = {ignore_empty: true}];
   uint64 scheduler_cluster_id = 3 [(validate.rules).uint64 = {ignore_empty: true}];
@@ -151,8 +151,8 @@ service Manager {
   rpc GetScheduler(GetSchedulerRequest)returns(Scheduler);
   // Update scheduler configuration
   rpc UpdateScheduler(UpdateSchedulerRequest) returns(Scheduler);
-  // AddSchedulerClusterToSchedulerCluster add scheduler to scheduler cluster
-  rpc AddSchedulerClusterToSchedulerCluster(AddSchedulerClusterToSchedulerClusterRequest) returns(google.protobuf.Empty);
+  // AddSchedulerToSchedulerCluster add scheduler to scheduler cluster
+  rpc AddSchedulerToSchedulerCluster(AddSchedulerToSchedulerClusterRequest) returns(google.protobuf.Empty);
   // List acitve schedulers configuration
   rpc ListSchedulers(ListSchedulersRequest)returns(ListSchedulersResponse);
   // KeepAlive with manager
diff --git a/pkg/rpc/manager/manager_grpc.pb.go b/pkg/rpc/manager/manager_grpc.pb.go
index b0ab3eb9..dae349b2 100644
--- a/pkg/rpc/manager/manager_grpc.pb.go
+++ b/pkg/rpc/manager/manager_grpc.pb.go
@@ -12,6 +12,7 @@ import (
 
 // This is a compile-time assertion to ensure that this generated file
 // is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
 const _ = grpc.SupportPackageIsVersion7
 
 // ManagerClient is the client API for Manager service.
@@ -28,8 +29,8 @@ type ManagerClient interface {
 	GetScheduler(ctx context.Context, in *GetSchedulerRequest, opts ...grpc.CallOption) (*Scheduler, error)
 	// Update scheduler configuration
 	UpdateScheduler(ctx context.Context, in *UpdateSchedulerRequest, opts ...grpc.CallOption) (*Scheduler, error)
-	// AddSchedulerClusterToSchedulerCluster add scheduler to scheduler cluster
-	AddSchedulerClusterToSchedulerCluster(ctx context.Context, in *AddSchedulerClusterToSchedulerClusterRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
+	// AddSchedulerToSchedulerCluster add scheduler to scheduler cluster
+	AddSchedulerToSchedulerCluster(ctx context.Context, in *AddSchedulerToSchedulerClusterRequest, opts ...grpc.CallOption) (*emptypb.Empty, error)
 	// List acitve schedulers configuration
 	ListSchedulers(ctx context.Context, in *ListSchedulersRequest, opts ...grpc.CallOption) (*ListSchedulersResponse, error)
 	// KeepAlive with manager
@@ -89,9 +90,9 @@ func (c *managerClient) UpdateScheduler(ctx context.Context, in *UpdateScheduler
 	return out, nil
 }
 
-func (c *managerClient) AddSchedulerClusterToSchedulerCluster(ctx context.Context, in *AddSchedulerClusterToSchedulerClusterRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+func (c *managerClient) AddSchedulerToSchedulerCluster(ctx context.Context, in *AddSchedulerToSchedulerClusterRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
 	out := new(emptypb.Empty)
-	err := c.cc.Invoke(ctx, "/manager.Manager/AddSchedulerClusterToSchedulerCluster", in, out, opts...)
+	err := c.cc.Invoke(ctx, "/manager.Manager/AddSchedulerToSchedulerCluster", in, out, opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -108,7 +109,7 @@ func (c *managerClient) ListSchedulers(ctx context.Context, in *ListSchedulersRe
 }
 
 func (c *managerClient) KeepAlive(ctx context.Context, opts ...grpc.CallOption) (Manager_KeepAliveClient, error) {
-	stream, err := c.cc.NewStream(ctx, &_Manager_serviceDesc.Streams[0], "/manager.Manager/KeepAlive", opts...)
+	stream, err := c.cc.NewStream(ctx, &Manager_ServiceDesc.Streams[0], "/manager.Manager/KeepAlive", opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -155,8 +156,8 @@ type ManagerServer interface {
 	GetScheduler(context.Context, *GetSchedulerRequest) (*Scheduler, error)
 	// Update scheduler configuration
 	UpdateScheduler(context.Context, *UpdateSchedulerRequest) (*Scheduler, error)
-	// AddSchedulerClusterToSchedulerCluster add scheduler to scheduler cluster
-	AddSchedulerClusterToSchedulerCluster(context.Context, *AddSchedulerClusterToSchedulerClusterRequest) (*emptypb.Empty, error)
+	// AddSchedulerToSchedulerCluster add scheduler to scheduler cluster
+	AddSchedulerToSchedulerCluster(context.Context, *AddSchedulerToSchedulerClusterRequest) (*emptypb.Empty, error)
 	// List acitve schedulers configuration
 	ListSchedulers(context.Context, *ListSchedulersRequest) (*ListSchedulersResponse, error)
 	// KeepAlive with manager
@@ -183,8 +184,8 @@ func (UnimplementedManagerServer) GetScheduler(context.Context, *GetSchedulerReq
 func (UnimplementedManagerServer) UpdateScheduler(context.Context, *UpdateSchedulerRequest) (*Scheduler, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method UpdateScheduler not implemented")
 }
-func (UnimplementedManagerServer) AddSchedulerClusterToSchedulerCluster(context.Context, *AddSchedulerClusterToSchedulerClusterRequest) (*emptypb.Empty, error) {
-	return nil, status.Errorf(codes.Unimplemented, "method AddSchedulerClusterToSchedulerCluster not implemented")
+func (UnimplementedManagerServer) AddSchedulerToSchedulerCluster(context.Context, *AddSchedulerToSchedulerClusterRequest) (*emptypb.Empty, error) {
+	return nil, status.Errorf(codes.Unimplemented, "method AddSchedulerToSchedulerCluster not implemented")
 }
 func (UnimplementedManagerServer) ListSchedulers(context.Context, *ListSchedulersRequest) (*ListSchedulersResponse, error) {
 	return nil, status.Errorf(codes.Unimplemented, "method ListSchedulers not implemented")
@@ -202,7 +203,7 @@ type UnsafeManagerServer interface {
 }
 
 func RegisterManagerServer(s grpc.ServiceRegistrar, srv ManagerServer) {
-	s.RegisterService(&_Manager_serviceDesc, srv)
+	s.RegisterService(&Manager_ServiceDesc, srv)
 }
 
 func _Manager_GetCDN_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
@@ -295,20 +296,20 @@ func _Manager_UpdateScheduler_Handler(srv interface{}, ctx context.Context, dec
 	return interceptor(ctx, in, info, handler)
 }
 
-func _Manager_AddSchedulerClusterToSchedulerCluster_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
-	in := new(AddSchedulerClusterToSchedulerClusterRequest)
+func _Manager_AddSchedulerToSchedulerCluster_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
+	in := new(AddSchedulerToSchedulerClusterRequest)
 	if err := dec(in); err != nil {
 		return nil, err
 	}
 	if interceptor == nil {
-		return srv.(ManagerServer).AddSchedulerClusterToSchedulerCluster(ctx, in)
+		return srv.(ManagerServer).AddSchedulerToSchedulerCluster(ctx, in)
 	}
 	info := &grpc.UnaryServerInfo{
 		Server:     srv,
-		FullMethod: "/manager.Manager/AddSchedulerClusterToSchedulerCluster",
+		FullMethod: "/manager.Manager/AddSchedulerToSchedulerCluster",
 	}
 	handler := func(ctx context.Context, req interface{}) (interface{}, error) {
-		return srv.(ManagerServer).AddSchedulerClusterToSchedulerCluster(ctx, req.(*AddSchedulerClusterToSchedulerClusterRequest))
+		return srv.(ManagerServer).AddSchedulerToSchedulerCluster(ctx, req.(*AddSchedulerToSchedulerClusterRequest))
 	}
 	return interceptor(ctx, in, info, handler)
 }
@@ -357,7 +358,10 @@ func (x *managerKeepAliveServer) Recv() (*KeepAliveRequest, error) {
 	return m, nil
 }
 
-var _Manager_serviceDesc = grpc.ServiceDesc{
+// Manager_ServiceDesc is the grpc.ServiceDesc for Manager service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var Manager_ServiceDesc = grpc.ServiceDesc{
 	ServiceName: "manager.Manager",
 	HandlerType: (*ManagerServer)(nil),
 	Methods: []grpc.MethodDesc{
@@ -382,8 +386,8 @@ var _Manager_serviceDesc = grpc.ServiceDesc{
 			Handler:    _Manager_UpdateScheduler_Handler,
 		},
 		{
-			MethodName: "AddSchedulerClusterToSchedulerCluster",
-			Handler:    _Manager_AddSchedulerClusterToSchedulerCluster_Handler,
+			MethodName: "AddSchedulerToSchedulerCluster",
+			Handler:    _Manager_AddSchedulerToSchedulerCluster_Handler,
 		},
 		{
 			MethodName: "ListSchedulers",
diff --git a/pkg/rpc/scheduler/client/client.go b/pkg/rpc/scheduler/client/client.go
index a715426c..fb51f101 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(5 * time.Minute),
+			rpc.WithConnExpireTime(30 * time.Minute),
 			rpc.WithDialOption(opts),
 		}),
 	}
@@ -85,7 +85,7 @@ func (sc *schedulerClient) doRegisterPeerTask(ctx context.Context, ptr *schedule
 		schedulerNode string
 		res           interface{}
 	)
-	key := idgen.TaskID(ptr.Url, ptr.Filter, ptr.UrlMeta, ptr.BizId)
+	key := idgen.TaskID(ptr.Url, ptr.UrlMeta)
 	logger.WithTaskAndPeerID(key, ptr.PeerId).Infof("generate hash key taskId: %s and start to register peer task for peer_id(%s) url(%s)", key, ptr.PeerId,
 		ptr.Url)
 	reg := func() (interface{}, error) {
diff --git a/pkg/rpc/scheduler/scheduler.pb.go b/pkg/rpc/scheduler/scheduler.pb.go
index 8bb21c5f..c59b9a3e 100644
--- a/pkg/rpc/scheduler/scheduler.pb.go
+++ b/pkg/rpc/scheduler/scheduler.pb.go
@@ -44,21 +44,16 @@ type PeerTaskRequest struct {
 
 	// universal resource locator for different kind of storage
 	Url string `protobuf:"bytes,1,opt,name=url,proto3" json:"url,omitempty"`
-	// filter is a regular expression
-	// used to generate same task id for different urls
-	Filter string `protobuf:"bytes,2,opt,name=filter,proto3" json:"filter,omitempty"`
-	// biz id is used to generate different task ids for same url
-	BizId string `protobuf:"bytes,3,opt,name=biz_id,json=bizId,proto3" json:"biz_id,omitempty"`
 	// url meta info
-	UrlMeta *base.UrlMeta `protobuf:"bytes,4,opt,name=url_meta,json=urlMeta,proto3" json:"url_meta,omitempty"`
+	UrlMeta *base.UrlMeta `protobuf:"bytes,2,opt,name=url_meta,json=urlMeta,proto3" json:"url_meta,omitempty"`
 	// peer's id and must be global uniqueness
-	PeerId string `protobuf:"bytes,5,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"`
+	PeerId string `protobuf:"bytes,3,opt,name=peer_id,json=peerId,proto3" json:"peer_id,omitempty"`
 	// peer host info
-	PeerHost *PeerHost `protobuf:"bytes,6,opt,name=peer_host,json=peerHost,proto3" json:"peer_host,omitempty"`
+	PeerHost *PeerHost `protobuf:"bytes,4,opt,name=peer_host,json=peerHost,proto3" json:"peer_host,omitempty"`
 	// current host load
-	HostLoad *base.HostLoad `protobuf:"bytes,7,opt,name=host_load,json=hostLoad,proto3" json:"host_load,omitempty"`
+	HostLoad *base.HostLoad `protobuf:"bytes,5,opt,name=host_load,json=hostLoad,proto3" json:"host_load,omitempty"`
 	// whether this request is caused by migration
-	IsMigrating bool `protobuf:"varint,8,opt,name=is_migrating,json=isMigrating,proto3" json:"is_migrating,omitempty"`
+	IsMigrating bool `protobuf:"varint,6,opt,name=is_migrating,json=isMigrating,proto3" json:"is_migrating,omitempty"`
 }
 
 func (x *PeerTaskRequest) Reset() {
@@ -100,20 +95,6 @@ func (x *PeerTaskRequest) GetUrl() string {
 	return ""
 }
 
-func (x *PeerTaskRequest) GetFilter() string {
-	if x != nil {
-		return x.Filter
-	}
-	return ""
-}
-
-func (x *PeerTaskRequest) GetBizId() string {
-	if x != nil {
-		return x.BizId
-	}
-	return ""
-}
-
 func (x *PeerTaskRequest) GetUrlMeta() *base.UrlMeta {
 	if x != nil {
 		return x.UrlMeta
@@ -919,146 +900,143 @@ var file_pkg_rpc_scheduler_scheduler_proto_rawDesc = []byte{
 	0x70, 0x6b, 0x67, 0x2f, 0x72, 0x70, 0x63, 0x2f, 0x62, 0x61, 0x73, 0x65, 0x2f, 0x62, 0x61, 0x73,
 	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, 0x97, 0x02, 0x0a, 0x0f, 0x50, 0x65, 0x65, 0x72, 0x54, 0x61, 0x73,
+	0x72, 0x6f, 0x74, 0x6f, 0x22, 0xe8, 0x01, 0x0a, 0x0f, 0x50, 0x65, 0x65, 0x72, 0x54, 0x61, 0x73,
 	0x6b, 0x52, 0x65, 0x71, 0x75, 0x65, 0x73, 0x74, 0x12, 0x10, 0x0a, 0x03, 0x75, 0x72, 0x6c, 0x18,
-	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x16, 0x0a, 0x06, 0x66, 0x69,
-	0x6c, 0x74, 0x65, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x66, 0x69, 0x6c, 0x74,
-	0x65, 0x72, 0x12, 0x15, 0x0a, 0x06, 0x62, 0x69, 0x7a, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x05, 0x62, 0x69, 0x7a, 0x49, 0x64, 0x12, 0x28, 0x0a, 0x08, 0x75, 0x72, 0x6c,
-	0x5f, 0x6d, 0x65, 0x74, 0x61, 0x18, 0x04, 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, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x05,
-	0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x30, 0x0a, 0x09,
-	0x70, 0x65, 0x65, 0x72, 0x5f, 0x68, 0x6f, 0x73, 0x74, 0x18, 0x06, 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, 0x07, 0x20, 0x01, 0x28,
+	0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x75, 0x72, 0x6c, 0x12, 0x28, 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, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x09, 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,
+	0xcd, 0x01, 0x0a, 0x0e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x75,
+	0x6c, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x2e, 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,
+	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,
+	0x71, 0x0a, 0x0b, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x50, 0x69, 0x65, 0x63, 0x65, 0x12, 0x17,
+	0x0a, 0x07, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x06, 0x64, 0x73, 0x74, 0x50, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x61,
+	0x64, 0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 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, 0xfd, 0x01, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x48, 0x6f, 0x73, 0x74, 0x12,
+	0x12, 0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75,
+	0x75, 0x69, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52,
+	0x02, 0x69, 0x70, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x70, 0x63, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18,
+	0x03, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x72, 0x70, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1b,
+	0x0a, 0x09, 0x64, 0x6f, 0x77, 0x6e, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28,
+	0x05, 0x52, 0x08, 0x64, 0x6f, 0x77, 0x6e, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x68,
+	0x6f, 0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 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, 0xbd, 0x02, 0x0a, 0x0b, 0x50, 0x69, 0x65, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75,
+	0x6c, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20,
+	0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x73,
+	0x72, 0x63, 0x5f, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 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, 0x1b, 0x0a,
+	0x09, 0x70, 0x69, 0x65, 0x63, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05,
+	0x52, 0x08, 0x70, 0x69, 0x65, 0x63, 0x65, 0x4e, 0x75, 0x6d, 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, 0x1e,
+	0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x62,
+	0x61, 0x73, 0x65, 0x2e, 0x43, 0x6f, 0x64, 0x65, 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, 0x21, 0x0a, 0x0c, 0x69,
-	0x73, 0x5f, 0x6d, 0x69, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x18, 0x08, 0x20, 0x01, 0x28,
-	0x08, 0x52, 0x0b, 0x69, 0x73, 0x4d, 0x69, 0x67, 0x72, 0x61, 0x74, 0x69, 0x6e, 0x67, 0x22, 0xcd,
-	0x01, 0x0a, 0x0e, 0x52, 0x65, 0x67, 0x69, 0x73, 0x74, 0x65, 0x72, 0x52, 0x65, 0x73, 0x75, 0x6c,
+	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, 0xd3, 0x02, 0x0a, 0x0a, 0x50, 0x65, 0x65, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x65,
 	0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01,
-	0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x2e, 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, 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, 0x71,
-	0x0a, 0x0b, 0x53, 0x69, 0x6e, 0x67, 0x6c, 0x65, 0x50, 0x69, 0x65, 0x63, 0x65, 0x12, 0x17, 0x0a,
-	0x07, 0x64, 0x73, 0x74, 0x5f, 0x70, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06,
-	0x64, 0x73, 0x74, 0x50, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x08, 0x64, 0x73, 0x74, 0x5f, 0x61, 0x64,
-	0x64, 0x72, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 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, 0xfd, 0x01, 0x0a, 0x08, 0x50, 0x65, 0x65, 0x72, 0x48, 0x6f, 0x73, 0x74, 0x12, 0x12,
-	0x0a, 0x04, 0x75, 0x75, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x75, 0x75,
-	0x69, 0x64, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x02,
-	0x69, 0x70, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x70, 0x63, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x03,
-	0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x72, 0x70, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1b, 0x0a,
-	0x09, 0x64, 0x6f, 0x77, 0x6e, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05,
-	0x52, 0x08, 0x64, 0x6f, 0x77, 0x6e, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x1b, 0x0a, 0x09, 0x68, 0x6f,
-	0x73, 0x74, 0x5f, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, 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, 0xbd, 0x02, 0x0a, 0x0b, 0x50, 0x69, 0x65, 0x63, 0x65, 0x52, 0x65, 0x73, 0x75, 0x6c,
-	0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01,
 	0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x72,
-	0x63, 0x5f, 0x70, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 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, 0x1b, 0x0a, 0x09,
-	0x70, 0x69, 0x65, 0x63, 0x65, 0x5f, 0x6e, 0x75, 0x6d, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 0x52,
-	0x08, 0x70, 0x69, 0x65, 0x63, 0x65, 0x4e, 0x75, 0x6d, 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, 0x1e, 0x0a,
-	0x04, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x08, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x62, 0x61,
-	0x73, 0x65, 0x2e, 0x43, 0x6f, 0x64, 0x65, 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, 0xd3, 0x02, 0x0a, 0x0a, 0x50, 0x65, 0x65, 0x72, 0x50, 0x61, 0x63, 0x6b, 0x65, 0x74,
-	0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
-	0x09, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x73, 0x72, 0x63,
-	0x5f, 0x70, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x72, 0x63, 0x50,
-	0x69, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x5f, 0x63,
-	0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 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, 0x5f, 0x70, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x73, 0x72, 0x63,
+	0x50, 0x69, 0x64, 0x12, 0x25, 0x0a, 0x0e, 0x70, 0x61, 0x72, 0x61, 0x6c, 0x6c, 0x65, 0x6c, 0x5f,
+	0x63, 0x6f, 0x75, 0x6e, 0x74, 0x18, 0x04, 0x20, 0x01, 0x28, 0x05, 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, 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, 0x1e, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x18,
-	0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x43, 0x6f, 0x64,
-	0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x1a, 0x4e, 0x0a, 0x08, 0x44, 0x65, 0x73, 0x74, 0x50,
-	0x65, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x02, 0x69, 0x70, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x70, 0x63, 0x5f, 0x70, 0x6f, 0x72, 0x74, 0x18,
-	0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x72, 0x70, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12, 0x17,
-	0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52,
-	0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x22, 0xb1, 0x02, 0x0a, 0x0a, 0x50, 0x65, 0x65, 0x72,
-	0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x69,
-	0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64, 0x12,
-	0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09,
-	0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x72, 0x63, 0x5f,
-	0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 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, 0x10, 0x0a, 0x03, 0x75, 0x72,
-	0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 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, 0x03, 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, 0x1e, 0x0a, 0x04, 0x63,
-	0x6f, 0x64, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x62, 0x61, 0x73, 0x65,
-	0x2e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x3e, 0x0a, 0x0a, 0x50,
-	0x65, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73,
-	0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b,
-	0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20,
-	0x01, 0x28, 0x09, 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,
+	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, 0x1e, 0x0a, 0x04, 0x63, 0x6f, 0x64, 0x65,
+	0x18, 0x07, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x62, 0x61, 0x73, 0x65, 0x2e, 0x43, 0x6f,
+	0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x1a, 0x4e, 0x0a, 0x08, 0x44, 0x65, 0x73, 0x74,
+	0x50, 0x65, 0x65, 0x72, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x70, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x02, 0x69, 0x70, 0x12, 0x19, 0x0a, 0x08, 0x72, 0x70, 0x63, 0x5f, 0x70, 0x6f, 0x72, 0x74,
+	0x18, 0x02, 0x20, 0x01, 0x28, 0x05, 0x52, 0x07, 0x72, 0x70, 0x63, 0x50, 0x6f, 0x72, 0x74, 0x12,
+	0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09,
+	0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x22, 0xb1, 0x02, 0x0a, 0x0a, 0x50, 0x65, 0x65,
+	0x72, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61, 0x73, 0x6b, 0x5f,
+	0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x73, 0x6b, 0x49, 0x64,
+	0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02, 0x20, 0x01, 0x28,
+	0x09, 0x52, 0x06, 0x70, 0x65, 0x65, 0x72, 0x49, 0x64, 0x12, 0x15, 0x0a, 0x06, 0x73, 0x72, 0x63,
+	0x5f, 0x69, 0x70, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 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, 0x10, 0x0a, 0x03, 0x75,
+	0x72, 0x6c, 0x18, 0x06, 0x20, 0x01, 0x28, 0x09, 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, 0x03, 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, 0x1e, 0x0a, 0x04,
+	0x63, 0x6f, 0x64, 0x65, 0x18, 0x0b, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x0a, 0x2e, 0x62, 0x61, 0x73,
+	0x65, 0x2e, 0x43, 0x6f, 0x64, 0x65, 0x52, 0x04, 0x63, 0x6f, 0x64, 0x65, 0x22, 0x3e, 0x0a, 0x0a,
+	0x50, 0x65, 0x65, 0x72, 0x54, 0x61, 0x72, 0x67, 0x65, 0x74, 0x12, 0x17, 0x0a, 0x07, 0x74, 0x61,
+	0x73, 0x6b, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x06, 0x74, 0x61, 0x73,
+	0x6b, 0x49, 0x64, 0x12, 0x17, 0x0a, 0x07, 0x70, 0x65, 0x65, 0x72, 0x5f, 0x69, 0x64, 0x18, 0x02,
+	0x20, 0x01, 0x28, 0x09, 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,
-	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,
+	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 390d5b2a..c5735263 100644
--- a/pkg/rpc/scheduler/scheduler.pb.validate.go
+++ b/pkg/rpc/scheduler/scheduler.pb.validate.go
@@ -53,10 +53,6 @@ func (m *PeerTaskRequest) Validate() error {
 
 	// no validation rules for Url
 
-	// no validation rules for Filter
-
-	// no validation rules for BizId
-
 	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 d5b118f9..3d540bfb 100644
--- a/pkg/rpc/scheduler/scheduler.proto
+++ b/pkg/rpc/scheduler/scheduler.proto
@@ -26,21 +26,16 @@ option go_package = "d7y.io/dragonfly/v2/pkg/rpc/scheduler";
 message PeerTaskRequest{
   // universal resource locator for different kind of storage
   string url = 1;
-  // filter is a regular expression
-  // used to generate same task id for different urls
-  string filter = 2;
-  // biz id is used to generate different task ids for same url
-  string biz_id = 3;
   // url meta info
-  base.UrlMeta url_meta = 4;
+  base.UrlMeta url_meta = 2;
   // peer's id and must be global uniqueness
-  string peer_id = 5;
+  string peer_id = 3;
   // peer host info
-  PeerHost peer_host = 6;
+  PeerHost peer_host = 4;
   // current host load
-  base.HostLoad host_load = 7;
+  base.HostLoad host_load = 5;
   // whether this request is caused by migration
-  bool is_migrating = 8;
+  bool is_migrating = 6;
 }
 
 message RegisterResult{
diff --git a/pkg/rpc/scheduler/scheduler_grpc.pb.go b/pkg/rpc/scheduler/scheduler_grpc.pb.go
index 2ac29781..a1b1c414 100644
--- a/pkg/rpc/scheduler/scheduler_grpc.pb.go
+++ b/pkg/rpc/scheduler/scheduler_grpc.pb.go
@@ -12,6 +12,7 @@ import (
 
 // This is a compile-time assertion to ensure that this generated file
 // is compatible with the grpc package it is being compiled against.
+// Requires gRPC-Go v1.32.0 or later.
 const _ = grpc.SupportPackageIsVersion7
 
 // SchedulerClient is the client API for Scheduler service.
@@ -48,7 +49,7 @@ func (c *schedulerClient) RegisterPeerTask(ctx context.Context, in *PeerTaskRequ
 }
 
 func (c *schedulerClient) ReportPieceResult(ctx context.Context, opts ...grpc.CallOption) (Scheduler_ReportPieceResultClient, error) {
-	stream, err := c.cc.NewStream(ctx, &_Scheduler_serviceDesc.Streams[0], "/scheduler.Scheduler/ReportPieceResult", opts...)
+	stream, err := c.cc.NewStream(ctx, &Scheduler_ServiceDesc.Streams[0], "/scheduler.Scheduler/ReportPieceResult", opts...)
 	if err != nil {
 		return nil, err
 	}
@@ -139,7 +140,7 @@ type UnsafeSchedulerServer interface {
 }
 
 func RegisterSchedulerServer(s grpc.ServiceRegistrar, srv SchedulerServer) {
-	s.RegisterService(&_Scheduler_serviceDesc, srv)
+	s.RegisterService(&Scheduler_ServiceDesc, srv)
 }
 
 func _Scheduler_RegisterPeerTask_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
@@ -222,7 +223,10 @@ func _Scheduler_LeaveTask_Handler(srv interface{}, ctx context.Context, dec func
 	return interceptor(ctx, in, info, handler)
 }
 
-var _Scheduler_serviceDesc = grpc.ServiceDesc{
+// Scheduler_ServiceDesc is the grpc.ServiceDesc for Scheduler service.
+// It's only intended for direct use with grpc.RegisterService,
+// and not to be introspected or modified (even as a copy)
+var Scheduler_ServiceDesc = grpc.ServiceDesc{
 	ServiceName: "scheduler.Scheduler",
 	HandlerType: (*SchedulerServer)(nil),
 	Methods: []grpc.MethodDesc{
diff --git a/pkg/structure/sortedlist/sorted_list.go b/pkg/structure/sortedlist/sorted_list.go
index 80e168be..efd8b828 100644
--- a/pkg/structure/sortedlist/sorted_list.go
+++ b/pkg/structure/sortedlist/sorted_list.go
@@ -132,7 +132,9 @@ func (l *SortedList) RangeLimit(limit int, fn func(Item) bool) {
 	}
 	l.l.RLock()
 	defer l.l.RUnlock()
-
+	if len(l.buckets) == 0 {
+		return
+	}
 	count := 0
 	for i := l.left; i <= l.right; i++ {
 		buc := l.buckets[i]
@@ -160,7 +162,9 @@ func (l *SortedList) RangeReverseLimit(limit int, fn func(Item) bool) {
 	}
 	l.l.RLock()
 	defer l.l.RUnlock()
-
+	if len(l.buckets) == 0 {
+		return
+	}
 	count := 0
 	for i := l.right; i >= l.left; i-- {
 		for j := len(l.buckets[i].buckets) - 1; j >= 0; j-- {
diff --git a/scheduler/config/config.go b/scheduler/config/config.go
index a57b49bf..4a85f30c 100644
--- a/scheduler/config/config.go
+++ b/scheduler/config/config.go
@@ -113,7 +113,7 @@ func NewDefaultSchedulerConfig() *SchedulerConfig {
 		Scheduler:            "basic",
 		CDNLoad:              100,
 		ClientLoad:           10,
-		OpenMonitor:          false,
+		OpenMonitor:          true,
 		GC:                   NewDefaultGCConfig(),
 	}
 }
diff --git a/scheduler/config/mocks/manager_client_mock.go b/scheduler/config/mocks/manager_client_mock.go
index 2550be5f..e1958c31 100644
--- a/scheduler/config/mocks/manager_client_mock.go
+++ b/scheduler/config/mocks/manager_client_mock.go
@@ -58,24 +58,24 @@ func (mr *MockManagerClientMockRecorder) AddCDNToCDNCluster(ctx, in interface{},
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddCDNToCDNCluster", reflect.TypeOf((*MockManagerClient)(nil).AddCDNToCDNCluster), varargs...)
 }
 
-// AddSchedulerClusterToSchedulerCluster mocks base method.
-func (m *MockManagerClient) AddSchedulerClusterToSchedulerCluster(ctx context.Context, in *manager.AddSchedulerClusterToSchedulerClusterRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
+// AddSchedulerToSchedulerCluster mocks base method.
+func (m *MockManagerClient) AddSchedulerToSchedulerCluster(ctx context.Context, in *manager.AddSchedulerToSchedulerClusterRequest, opts ...grpc.CallOption) (*emptypb.Empty, error) {
 	m.ctrl.T.Helper()
 	varargs := []interface{}{ctx, in}
 	for _, a := range opts {
 		varargs = append(varargs, a)
 	}
-	ret := m.ctrl.Call(m, "AddSchedulerClusterToSchedulerCluster", varargs...)
+	ret := m.ctrl.Call(m, "AddSchedulerToSchedulerCluster", varargs...)
 	ret0, _ := ret[0].(*emptypb.Empty)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// AddSchedulerClusterToSchedulerCluster indicates an expected call of AddSchedulerClusterToSchedulerCluster.
-func (mr *MockManagerClientMockRecorder) AddSchedulerClusterToSchedulerCluster(ctx, in interface{}, opts ...interface{}) *gomock.Call {
+// AddSchedulerToSchedulerCluster indicates an expected call of AddSchedulerToSchedulerCluster.
+func (mr *MockManagerClientMockRecorder) AddSchedulerToSchedulerCluster(ctx, in interface{}, opts ...interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
 	varargs := append([]interface{}{ctx, in}, opts...)
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddSchedulerClusterToSchedulerCluster", reflect.TypeOf((*MockManagerClient)(nil).AddSchedulerClusterToSchedulerCluster), varargs...)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddSchedulerToSchedulerCluster", reflect.TypeOf((*MockManagerClient)(nil).AddSchedulerToSchedulerCluster), varargs...)
 }
 
 // GetCDN mocks base method.
@@ -373,19 +373,19 @@ func (mr *MockManagerServerMockRecorder) AddCDNToCDNCluster(arg0, arg1 interface
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddCDNToCDNCluster", reflect.TypeOf((*MockManagerServer)(nil).AddCDNToCDNCluster), arg0, arg1)
 }
 
-// AddSchedulerClusterToSchedulerCluster mocks base method.
-func (m *MockManagerServer) AddSchedulerClusterToSchedulerCluster(arg0 context.Context, arg1 *manager.AddSchedulerClusterToSchedulerClusterRequest) (*emptypb.Empty, error) {
+// AddSchedulerToSchedulerCluster mocks base method.
+func (m *MockManagerServer) AddSchedulerToSchedulerCluster(arg0 context.Context, arg1 *manager.AddSchedulerToSchedulerClusterRequest) (*emptypb.Empty, error) {
 	m.ctrl.T.Helper()
-	ret := m.ctrl.Call(m, "AddSchedulerClusterToSchedulerCluster", arg0, arg1)
+	ret := m.ctrl.Call(m, "AddSchedulerToSchedulerCluster", arg0, arg1)
 	ret0, _ := ret[0].(*emptypb.Empty)
 	ret1, _ := ret[1].(error)
 	return ret0, ret1
 }
 
-// AddSchedulerClusterToSchedulerCluster indicates an expected call of AddSchedulerClusterToSchedulerCluster.
-func (mr *MockManagerServerMockRecorder) AddSchedulerClusterToSchedulerCluster(arg0, arg1 interface{}) *gomock.Call {
+// AddSchedulerToSchedulerCluster indicates an expected call of AddSchedulerToSchedulerCluster.
+func (mr *MockManagerServerMockRecorder) AddSchedulerToSchedulerCluster(arg0, arg1 interface{}) *gomock.Call {
 	mr.mock.ctrl.T.Helper()
-	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddSchedulerClusterToSchedulerCluster", reflect.TypeOf((*MockManagerServer)(nil).AddSchedulerClusterToSchedulerCluster), arg0, arg1)
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "AddSchedulerToSchedulerCluster", reflect.TypeOf((*MockManagerServer)(nil).AddSchedulerToSchedulerCluster), arg0, arg1)
 }
 
 // GetCDN mocks base method.
diff --git a/scheduler/core/evaluator/basic/basic_evaluator.go b/scheduler/core/evaluator/basic/basic_evaluator.go
index 12f33e3b..cf9e6626 100644
--- a/scheduler/core/evaluator/basic/basic_evaluator.go
+++ b/scheduler/core/evaluator/basic/basic_evaluator.go
@@ -82,7 +82,7 @@ func (eval *baseEvaluator) IsBadNode(peer *types.Peer) bool {
 		return true
 	}
 
-	if peer.IsWaiting() {
+	if peer.IsBlocking() {
 		return false
 	}
 
diff --git a/scheduler/core/events.go b/scheduler/core/events.go
index 979abc1c..aee72229 100644
--- a/scheduler/core/events.go
+++ b/scheduler/core/events.go
@@ -162,20 +162,21 @@ var _ event = peerDownloadPieceFailEvent{}
 
 func (e peerDownloadPieceFailEvent) apply(s *state) {
 	switch e.pr.Code {
-	case dfcodes.PeerTaskNotFound:
-		handlePeerLeave(e.peer, s)
-		return
-	case dfcodes.ClientPieceRequestFail, dfcodes.ClientPieceDownloadFail:
+	case dfcodes.PeerTaskNotFound, dfcodes.ClientPieceRequestFail, dfcodes.ClientPieceDownloadFail:
+		// TODO PeerTaskNotFound remove dest peer task, ClientPieceDownloadFail add blank list
 		handleReplaceParent(e.peer, s)
 		return
 	case dfcodes.CdnTaskNotFound, dfcodes.CdnError, dfcodes.CdnTaskRegistryFail, dfcodes.CdnTaskDownloadFail:
-		if err := s.cdnManager.StartSeedTask(context.Background(), e.peer.Task); err != nil {
-			logger.Errorf("start seed task fail: %v", err)
-			e.peer.Task.SetStatus(types.TaskStatusFailed)
-			handleSeedTaskFail(e.peer.Task)
-			return
-		}
-		logger.Debugf("===== successfully obtain seeds from cdn, task: %+v =====", e.peer.Task)
+		go func(task *types.Task) {
+			task.SetStatus(types.TaskStatusRunning)
+			if err := s.cdnManager.StartSeedTask(context.Background(), task); err != nil {
+				logger.Errorf("start seed task fail: %v", err)
+				task.SetStatus(types.TaskStatusFailed)
+				handleSeedTaskFail(task)
+				return
+			}
+			logger.Debugf("===== successfully obtain seeds from cdn, task: %+v =====", e.peer.Task)
+		}(e.peer.Task)
 	default:
 		handleReplaceParent(e.peer, s)
 		return
@@ -231,6 +232,10 @@ func (e peerDownloadSuccessEvent) apply(s *state) {
 		}
 		child.PacketChan <- constructSuccessPeerPacket(child, e.peer, nil)
 	}
+	if e.peer.PacketChan != nil {
+		close(e.peer.PacketChan)
+		e.peer.PacketChan = nil
+	}
 }
 
 func (e peerDownloadSuccessEvent) hashKey() string {
@@ -262,6 +267,10 @@ func (e peerDownloadFailEvent) apply(s *state) {
 		child.PacketChan <- constructSuccessPeerPacket(child, parent, candidates)
 		return true
 	})
+	if e.peer.PacketChan != nil {
+		close(e.peer.PacketChan)
+		e.peer.PacketChan = nil
+	}
 	s.peerManager.Delete(e.peer.PeerID)
 }
 
diff --git a/scheduler/core/monitor.go b/scheduler/core/monitor.go
index 2d982128..f6b5e6ac 100644
--- a/scheduler/core/monitor.go
+++ b/scheduler/core/monitor.go
@@ -23,10 +23,10 @@ import (
 	"strings"
 	"time"
 
-	logger "d7y.io/dragonfly/v2/internal/dflog"
 	"d7y.io/dragonfly/v2/scheduler/daemon"
 	"d7y.io/dragonfly/v2/scheduler/types"
 	"github.com/olekukonko/tablewriter"
+	"go.uber.org/zap"
 	"k8s.io/client-go/util/workqueue"
 )
 
@@ -38,14 +38,17 @@ const (
 type monitor struct {
 	downloadMonitorQueue workqueue.DelayingInterface
 	peerManager          daemon.PeerMgr
-	verbose              bool
 	done                 chan struct{}
+	log                  *zap.SugaredLogger
 }
 
 func newMonitor(peerManager daemon.PeerMgr) *monitor {
+	config := zap.NewDevelopmentConfig()
+	logger, _ := config.Build()
 	return &monitor{
 		downloadMonitorQueue: workqueue.NewDelayingQueue(),
 		peerManager:          peerManager,
+		log:                  logger.Sugar(),
 	}
 }
 
@@ -54,7 +57,7 @@ func (m *monitor) start() {
 	for {
 		select {
 		case <-ticker.C:
-			logger.Debugf(m.printDebugInfo())
+			m.log.Info(m.printDebugInfo())
 		case <-m.done:
 			return
 		}
@@ -71,7 +74,6 @@ func (m *monitor) printDebugInfo() string {
 	buffer := bytes.NewBuffer([]byte{})
 	table := tablewriter.NewWriter(buffer)
 	table.SetHeader([]string{"PeerID", "URL", "parent node", "status", "start time", "Finished Piece Num", "Finished", "Free Load"})
-
 	m.peerManager.ListPeers().Range(func(key interface{}, value interface{}) (ok bool) {
 		ok = true
 		peer := value.(*types.Peer)
@@ -85,7 +87,9 @@ func (m *monitor) printDebugInfo() string {
 			parentNode = peer.GetParent().PeerID
 		}
 
-		table.Append([]string{peer.PeerID, peer.Task.URL, parentNode, peer.GetStatus().String(), peer.CreateTime.String(), strconv.Itoa(int(peer.GetFinishedNum())),
+		table.Append([]string{peer.PeerID, peer.Task.URL[len(peer.Task.URL)-15 : len(peer.Task.URL)-5], parentNode, peer.GetStatus().String(),
+			peer.CreateTime.String(),
+			strconv.Itoa(int(peer.GetFinishedNum())),
 			strconv.FormatBool(peer.IsSuccess()), strconv.Itoa(peer.Host.GetFreeUploadLoad())})
 		return
 	})
@@ -117,15 +121,15 @@ func (m *monitor) printDebugInfo() string {
 		printTree(root, nil)
 	}
 
-	msg := "============\n" + strings.Join(msgs, "\n") + "\n==============="
+	msg := "============\n" + strings.Join(append(msgs, strconv.Itoa(table.NumLines())), "\n") + "\n==============="
 	return msg
 }
 
 func (m *monitor) RefreshDownloadMonitor(peer *types.Peer) {
-	logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("downloadMonitorWorkingLoop refresh ")
+	m.log.With("taskID", peer.Task.TaskID, "peerID", peer.PeerID).Debugf("downloadMonitorWorkingLoop refresh ")
 	if !peer.IsRunning() {
 		m.downloadMonitorQueue.AddAfter(peer, time.Second*2)
-	} else if peer.IsWaiting() {
+	} else if peer.IsBlocking() {
 		m.downloadMonitorQueue.AddAfter(peer, time.Second*2)
 	} else {
 		delay := time.Millisecond * time.Duration(peer.GetCost()*10)
@@ -141,13 +145,13 @@ func (m *monitor) downloadMonitorWorkingLoop() {
 	for {
 		v, shutdown := m.downloadMonitorQueue.Get()
 		if shutdown {
-			logger.Infof("download monitor working loop closed")
+			m.log.Infof("download monitor working loop closed")
 			break
 		}
 		//if m.downloadMonitorCallBack != nil {
 		peer := v.(*types.Peer)
 		if peer != nil {
-			logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("downloadMonitorWorkingLoop status[%d]", peer.GetStatus())
+			m.log.With("taskID", peer.Task.TaskID, "peerID", peer.PeerID).Debugf("downloadMonitorWorkingLoop status[%d]", peer.GetStatus())
 			if peer.IsSuccess() || peer.Host.CDN {
 				// clear from monitor
 			} else {
@@ -158,7 +162,7 @@ func (m *monitor) downloadMonitorWorkingLoop() {
 						//pt.SendError(dferrors.New(dfcodes.SchedPeerGone, "report time out"))
 					}
 					//m.downloadMonitorCallBack(peer)
-				} else if !peer.IsWaiting() {
+				} else if !peer.IsBlocking() {
 					//m.downloadMonitorCallBack(peer)
 				} else {
 					if time.Now().After(peer.GetLastAccessTime().Add(PeerForceGoneTimeout)) {
diff --git a/scheduler/core/scheduler/basic/basic_scheduler.go b/scheduler/core/scheduler/basic/basic_scheduler.go
index 1b952aa4..a2309bb6 100644
--- a/scheduler/core/scheduler/basic/basic_scheduler.go
+++ b/scheduler/core/scheduler/basic/basic_scheduler.go
@@ -108,8 +108,8 @@ func (s *Scheduler) ScheduleChildren(peer *types.Peer) (children []*types.Peer)
 func (s *Scheduler) ScheduleParent(peer *types.Peer) (*types.Peer, []*types.Peer, bool) {
 	logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debug("start scheduler parent flow")
 	if !s.evaluator.NeedAdjustParent(peer) {
-		logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("peer does not need to replace the parent node, peer is %v and current parent is %v",
-			peer, peer.GetParent())
+		//logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("peer does not need to replace the parent node, peer is %v and current parent is %v",
+		//	peer, peer.GetParent())
 		if peer.GetParent() == nil {
 			return nil, nil, false
 		}
@@ -123,9 +123,9 @@ func (s *Scheduler) ScheduleParent(peer *types.Peer) (*types.Peer, []*types.Peer
 		worth := s.evaluator.Evaluate(candidate, peer)
 
 		// scheduler the same parent, worth reduce a half
-		if peer.GetParent() != nil && peer.GetParent().PeerID == candidate.PeerID {
-			worth = worth / 2.0
-		}
+		//if peer.GetParent() != nil && peer.GetParent().PeerID == candidate.PeerID {
+		//	worth = worth / 2.0
+		//}
 
 		if worth > value {
 			value = worth
@@ -145,49 +145,103 @@ func (s *Scheduler) ScheduleParent(peer *types.Peer) (*types.Peer, []*types.Peer
 func (s *Scheduler) selectCandidateChildren(peer *types.Peer, limit int) (list []*types.Peer) {
 	return s.peerManager.Pick(peer.Task, limit, func(candidateNode *types.Peer) bool {
 		if candidateNode == nil {
-			logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("*candidate child peer is not selected because it is nil")
+			logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("******candidate child peer is not selected because it is nil")
+			return false
+		}
+		if candidateNode.IsDone() {
+			logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("******candidate child peer %s is not selected because it has done",
+				candidateNode.PeerID)
+			return false
+		}
+		if candidateNode.IsLeave() {
+			logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("******candidate child peer %s is not selected because it has left",
+				candidateNode.PeerID)
 			return false
 		}
-		if candidateNode.IsDone() || candidateNode.IsLeave() || candidateNode == peer {
-			logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("*candidate child peer %s is not selected because it is %+v",
-				candidateNode.PeerID, candidateNode)
+		if candidateNode == peer {
+			logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("******candidate child peer %s is not selected because it and peer are the same",
+				candidateNode.PeerID)
+			return false
+		}
+		if candidateNode.IsAncestorOf(peer) {
+			logger.WithTaskAndPeerID(peer.Task.TaskID,
+				peer.PeerID).Debugf("******candidate child peer %s is not selected because peer's ancestor is candidate peer", candidateNode.PeerID)
+			return false
+		}
+		if candidateNode.GetFinishedNum() > peer.GetFinishedNum() {
+			logger.WithTaskAndPeerID(peer.Task.TaskID,
+				peer.PeerID).Debugf("******candidate child peer %s is not selected because it finished number of download is more than peer's",
+				candidateNode.PeerID)
 			return false
 		}
 		if candidateNode.Host != nil && candidateNode.Host.CDN {
-			logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("candidate child peer %s is not selected because it is a cdn host", candidateNode.PeerID)
+			logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("******candidate child peer %s is not selected because it is a cdn host",
+				candidateNode.PeerID)
 			return false
 		}
 		if candidateNode.GetParent() == nil {
-			logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("candidate child peer %s is selected because it has not parent",
+			logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("******candidate child peer %s is selected because it has not parent",
 				candidateNode.PeerID)
 			return true
 		}
 
 		if candidateNode.GetParent() != nil && s.evaluator.IsBadNode(candidateNode.GetParent()) {
 			logger.WithTaskAndPeerID(peer.Task.TaskID,
-				peer.PeerID).Debugf("candidate child peer %s is selected because it has parent and parent status is not health", candidateNode.PeerID)
+				peer.PeerID).Debugf("******candidate child peer %s is selected because it has parent and parent status is not health", candidateNode.PeerID)
 			return true
 		}
-		logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("=candidate child peer %s is not selected because it is %+v",
-			candidateNode.PeerID, candidateNode)
+		logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("******candidate child peer %s is selected", candidateNode.PeerID)
 		return false
 	})
 }
 
 func (s *Scheduler) selectCandidateParents(peer *types.Peer, limit int) (list []*types.Peer) {
+	if !peer.Task.CanSchedule() {
+		return nil
+	}
 	return s.peerManager.PickReverse(peer.Task, limit, func(candidateNode *types.Peer) bool {
 		if candidateNode == nil {
-			logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("candidate parent peer is not selected because it is nil")
+			logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("++++++candidate parent peer is not selected because it is nil")
+			return false
+		}
+		if s.evaluator.IsBadNode(candidateNode) {
+			logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("++++++candidate parent peer %s is not selected because it is badNode",
+				candidateNode.PeerID)
+			return false
+		}
+		if candidateNode.IsLeave() {
+			logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("++++++candidate parent peer %s is not selected because it has already left",
+				candidateNode.PeerID)
+			return false
+		}
+		if candidateNode == peer {
+			logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("++++++candidate parent peer %s is not selected because it and peer are the same",
+				candidateNode.PeerID)
+			return false
+		}
+		if candidateNode.IsDescendantOf(peer) {
+			logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("++++++candidate parent peer %s is not selected because it's ancestor is peer",
+				candidateNode.PeerID)
 			return false
 		}
-		if s.evaluator.IsBadNode(candidateNode) || candidateNode.IsLeave() || candidateNode == peer || candidateNode.Host.
-			GetFreeUploadLoad() <= 0 {
-			logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("candidate parent peer %s is not selected because it is %+v",
-				candidateNode.PeerID, candidateNode)
+		if candidateNode.Host.GetFreeUploadLoad() <= 0 {
+			logger.WithTaskAndPeerID(peer.Task.TaskID,
+				peer.PeerID).Debugf("++++++candidate parent peer %s is not selected because it's free upload load equal to less than zero",
+				candidateNode.PeerID)
+			return false
+		}
+		if candidateNode.IsWaiting() {
+			logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("++++++candidate parent peer %s is not selected because it's status is waiting",
+				candidateNode.PeerID)
+			return false
+		}
+		if candidateNode.GetFinishedNum() < peer.GetFinishedNum() {
+			logger.WithTaskAndPeerID(peer.Task.TaskID,
+				peer.PeerID).Debugf("++++++candidate parent peer %s is not selected because it finished number of download is smaller than peer's",
+				candidateNode.PeerID)
 			return false
 		}
-		logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("candidate parent peer %s is selected because it is %+v",
-			candidateNode.PeerID, candidateNode)
+		logger.WithTaskAndPeerID(peer.Task.TaskID, peer.PeerID).Debugf("++++++candidate parent peer %s is selected", candidateNode.PeerID)
 		return true
 	})
 }
diff --git a/scheduler/core/scheduler_service.go b/scheduler/core/scheduler_service.go
index 3c16b500..defba62e 100644
--- a/scheduler/core/scheduler_service.go
+++ b/scheduler/core/scheduler_service.go
@@ -119,16 +119,16 @@ func (s *SchedulerService) Stop() {
 	})
 }
 
-func (s *SchedulerService) GenerateTaskID(url string, filter string, meta *base.UrlMeta, bizID string, peerID string) (taskID string) {
+func (s *SchedulerService) GenerateTaskID(url string, meta *base.UrlMeta, peerID string) (taskID string) {
 	if s.config.ABTest {
-		return idgen.TwinsTaskID(url, filter, meta, bizID, peerID)
+		return idgen.TwinsTaskID(url, meta, peerID)
 	}
-	return idgen.TaskID(url, filter, meta, bizID)
+	return idgen.TaskID(url, meta)
 }
 
 func (s *SchedulerService) ScheduleParent(peer *types.Peer) (parent *types.Peer, err error) {
-	parent, candidates, hasParent := s.sched.ScheduleParent(peer)
-	logger.Debugf("schedule parent result: parent %v, candidates:%v", parent, candidates)
+	parent, _, hasParent := s.sched.ScheduleParent(peer)
+	//logger.Debugf("schedule parent result: parent %v, candidates:%v", parent, candidates)
 	if !hasParent || parent == nil {
 		return nil, errors.Errorf("no parent peer available for peer %v", peer.PeerID)
 	}
@@ -178,10 +178,12 @@ func (s *SchedulerService) GetOrCreateTask(ctx context.Context, task *types.Task
 	// notify peer tasks
 	synclock.Lock(task.TaskID, false)
 	defer synclock.UnLock(task.TaskID, false)
-	if !task.IsHealth() {
+	if task.IsHealth() && task.GetLastTriggerTime().Add(s.config.AccessWindow).After(time.Now()) {
+		return task, nil
+	}
+	if task.IsFrozen() {
 		task.SetStatus(types.TaskStatusRunning)
 	}
-
 	go func() {
 		if err := s.cdnManager.StartSeedTask(ctx, task); err != nil {
 			if !task.IsSuccess() {
diff --git a/scheduler/daemon/cdn/d7y/manager.go b/scheduler/daemon/cdn/d7y/manager.go
index 1f67cdc7..083d0900 100644
--- a/scheduler/daemon/cdn/d7y/manager.go
+++ b/scheduler/daemon/cdn/d7y/manager.go
@@ -94,7 +94,6 @@ func (cm *manager) StartSeedTask(ctx context.Context, task *types.Task) error {
 	stream, err := cm.client.ObtainSeeds(context.Background(), &cdnsystem.SeedRequest{
 		TaskId:  task.TaskID,
 		Url:     task.URL,
-		Filter:  task.Filter,
 		UrlMeta: task.URLMeta,
 	})
 	if err != nil {
@@ -145,6 +144,7 @@ func (cm *manager) receivePiece(task *types.Task, stream *client.PieceSeedStream
 			if err != nil || cdnPeer == nil {
 				return err
 			}
+			task.SetStatus(types.TaskStatusSeeding)
 			cdnPeer.Touch()
 			if piece.Done {
 				task.PieceTotal = piece.TotalPieceCount
diff --git a/scheduler/daemon/peer/manager.go b/scheduler/daemon/peer/manager.go
index f8e74177..b6e77252 100644
--- a/scheduler/daemon/peer/manager.go
+++ b/scheduler/daemon/peer/manager.go
@@ -72,6 +72,7 @@ func (m *manager) Delete(peerID string) {
 		peer.Task.DeletePeer(peer)
 		if peer.PacketChan != nil {
 			close(peer.PacketChan)
+			logger.Infof("close peer %s stream", peerID)
 			peer.PacketChan = nil
 		}
 		m.peerMap.Delete(peerID)
diff --git a/scheduler/server/server.go b/scheduler/server/server.go
index 5995178a..e69b24ea 100644
--- a/scheduler/server/server.go
+++ b/scheduler/server/server.go
@@ -173,7 +173,7 @@ func (s *Server) register(ctx context.Context) error {
 
 	schedulerClusterID := s.config.Manager.SchedulerClusterID
 	if schedulerClusterID != 0 {
-		if _, err := s.managerClient.AddSchedulerClusterToSchedulerCluster(ctx, &manager.AddSchedulerClusterToSchedulerClusterRequest{
+		if _, err := s.managerClient.AddSchedulerToSchedulerCluster(ctx, &manager.AddSchedulerToSchedulerClusterRequest{
 			SchedulerId:        scheduler.Id,
 			SchedulerClusterId: schedulerClusterID,
 		}); err != nil {
diff --git a/scheduler/server/service/scheduler_server.go b/scheduler/server/service/scheduler_server.go
index f0bc7793..d190dca0 100644
--- a/scheduler/server/service/scheduler_server.go
+++ b/scheduler/server/service/scheduler_server.go
@@ -57,8 +57,8 @@ func (s *SchedulerServer) RegisterPeerTask(ctx context.Context, request *schedul
 		logger.Errorf("validate register request failed: %v", err)
 		return
 	}
-	taskID := s.service.GenerateTaskID(request.Url, request.Filter, request.UrlMeta, request.BizId, request.PeerId)
-	task := types.NewTask(taskID, request.Url, request.Filter, request.BizId, request.UrlMeta)
+	taskID := s.service.GenerateTaskID(request.Url, request.UrlMeta, request.PeerId)
+	task := types.NewTask(taskID, request.Url, request.UrlMeta.Filter, request.UrlMeta)
 	task, err = s.service.GetOrCreateTask(ctx, task)
 	if err != nil {
 		err = dferrors.Newf(dfcodes.SchedCDNSeedFail, "create task failed: %v", err)
@@ -86,7 +86,9 @@ func (s *SchedulerServer) RegisterPeerTask(ctx context.Context, request *schedul
 		}
 		parent, schErr := s.service.ScheduleParent(peer)
 		if schErr != nil {
-			err = dferrors.Newf(dfcodes.SchedPeerScheduleFail, "failed to schedule peer %v: %v", peer.PeerID, schErr)
+			resp.SizeScope = base.SizeScope_NORMAL
+			resp.TaskId = taskID
+			//err = dferrors.Newf(dfcodes.SchedPeerScheduleFail, "failed to schedule peer %v: %v", peer.PeerID, schErr)
 			return
 		}
 		singlePiece := task.GetPiece(0)
diff --git a/scheduler/types/peer.go b/scheduler/types/peer.go
index 32d1b2dc..0675ee42 100644
--- a/scheduler/types/peer.go
+++ b/scheduler/types/peer.go
@@ -114,20 +114,22 @@ func (peer *Peer) Touch() {
 }
 
 func (peer *Peer) associateChild(child *Peer) {
+	peer.lock.Lock()
 	peer.children.Store(child.PeerID, child)
 	peer.Host.IncUploadLoad()
+	peer.lock.Unlock()
 	peer.Task.peers.Update(peer)
 }
 
 func (peer *Peer) disassociateChild(child *Peer) {
+	peer.lock.Lock()
 	peer.children.Delete(child.PeerID)
 	peer.Host.DecUploadLoad()
+	peer.lock.Unlock()
 	peer.Task.peers.Update(peer)
 }
 
 func (peer *Peer) ReplaceParent(parent *Peer) {
-	peer.lock.Lock()
-	defer peer.lock.Unlock()
 	oldParent := peer.parent
 	if oldParent != nil {
 		oldParent.disassociateChild(peer)
@@ -159,15 +161,17 @@ func (peer *Peer) GetCost() int {
 
 func (peer *Peer) AddPieceInfo(finishedCount int32, cost int) {
 	peer.lock.Lock()
-	defer peer.lock.Unlock()
 	if finishedCount > peer.finishedNum.Load() {
 		peer.finishedNum.Store(finishedCount)
 		peer.costHistory = append(peer.costHistory, cost)
 		if len(peer.costHistory) > 20 {
 			peer.costHistory = peer.costHistory[len(peer.costHistory)-20:]
 		}
+		peer.lock.Unlock()
 		peer.Task.peers.Update(peer)
+		return
 	}
+	peer.lock.Unlock()
 }
 
 func (peer *Peer) GetDepth() int {
@@ -196,11 +200,16 @@ func (peer *Peer) GetTreeRoot() *Peer {
 	return node
 }
 
-// if ancestor is ancestor of peer
-func (peer *Peer) IsAncestor(ancestor *Peer) bool {
+// if peer is offspring of ancestor
+func (peer *Peer) IsDescendantOf(ancestor *Peer) bool {
 	if ancestor == nil {
 		return false
 	}
+	// TODO avoid circulation
+	peer.lock.RLock()
+	ancestor.lock.RLock()
+	defer ancestor.lock.RUnlock()
+	defer peer.lock.RUnlock()
 	node := peer
 	for node != nil {
 		if node.parent == nil || node.Host.CDN {
@@ -213,7 +222,27 @@ func (peer *Peer) IsAncestor(ancestor *Peer) bool {
 	return false
 }
 
-func (peer *Peer) IsWaiting() bool {
+func (peer *Peer) IsAncestorOf(offspring *Peer) bool {
+	if offspring == nil {
+		return false
+	}
+	offspring.lock.RLock()
+	peer.lock.RLock()
+	defer peer.lock.RUnlock()
+	defer offspring.lock.RUnlock()
+	node := offspring
+	for node != nil {
+		if node.parent == nil || node.Host.CDN {
+			return false
+		} else if node.PeerID == peer.PeerID {
+			return true
+		}
+		node = node.parent
+	}
+	return false
+}
+
+func (peer *Peer) IsBlocking() bool {
 	peer.lock.RLock()
 	defer peer.lock.RUnlock()
 	if peer.parent == nil {
@@ -235,10 +264,6 @@ func (peer *Peer) getFreeLoad() int {
 	return peer.Host.GetFreeUploadLoad()
 }
 
-func (peer *Peer) GetFinishNum() int32 {
-	return peer.finishedNum.Load()
-}
-
 func GetDiffPieceNum(src *Peer, dst *Peer) int32 {
 	diff := src.finishedNum.Load() - dst.finishedNum.Load()
 	if diff > 0 {
@@ -279,6 +304,10 @@ func (peer *Peer) IsRunning() bool {
 	return peer.status == PeerStatusRunning
 }
 
+func (peer *Peer) IsWaiting() bool {
+	return peer.status == PeerStatusWaiting
+}
+
 func (peer *Peer) IsSuccess() bool {
 	return peer.status == PeerStatusSuccess
 }
diff --git a/scheduler/types/task.go b/scheduler/types/task.go
index 2c069ed0..605388d0 100644
--- a/scheduler/types/task.go
+++ b/scheduler/types/task.go
@@ -48,6 +48,7 @@ func (status TaskStatus) String() string {
 const (
 	TaskStatusWaiting TaskStatus = iota
 	TaskStatusRunning
+	TaskStatusSeeding
 	TaskStatusSuccess
 	TaskStatusCDNRegisterFail
 	TaskStatusFailed
@@ -59,7 +60,6 @@ type Task struct {
 	TaskID          string
 	URL             string
 	Filter          string
-	BizID           string
 	URLMeta         *base.UrlMeta
 	DirectPiece     []byte
 	CreateTime      time.Time
@@ -73,12 +73,11 @@ type Task struct {
 	// TODO add cdnPeers
 }
 
-func NewTask(taskID, url, filter, bizID string, meta *base.UrlMeta) *Task {
+func NewTask(taskID, url, filter string, meta *base.UrlMeta) *Task {
 	return &Task{
 		TaskID:    taskID,
 		URL:       url,
 		Filter:    filter,
-		BizID:     bizID,
 		URLMeta:   meta,
 		pieceList: make(map[int32]*PieceInfo),
 		peers:     sortedlist.NewSortedList(),
@@ -105,14 +104,12 @@ func (task *Task) GetPiece(pieceNum int32) *PieceInfo {
 }
 
 func (task *Task) AddPeer(peer *Peer) {
-	task.lock.Lock()
-	defer task.lock.Unlock()
 	task.peers.UpdateOrAdd(peer)
 }
 
 func (task *Task) DeletePeer(peer *Peer) {
-	task.lock.Lock()
-	defer task.lock.Unlock()
+	//task.lock.Lock()
+	//defer task.lock.Unlock()
 	task.peers.Delete(peer)
 }
 
@@ -173,6 +170,10 @@ func (task *Task) IsFrozen() bool {
 		task.status == TaskStatusSourceError || task.status == TaskStatusCDNRegisterFail
 }
 
+func (task *Task) CanSchedule() bool {
+	return task.status == TaskStatusSeeding || task.status == TaskStatusSuccess
+}
+
 func (task *Task) IsWaiting() bool {
 	return task.status == TaskStatusWaiting
 }


Test patch:
diff --git a/cdnsystem/daemon/cdn/manager_test.go b/cdnsystem/daemon/cdn/manager_test.go
index 75428231..4bddb1f5 100644
--- a/cdnsystem/daemon/cdn/manager_test.go
+++ b/cdnsystem/daemon/cdn/manager_test.go
@@ -67,7 +67,7 @@ func (suite *CDNManagerTestSuite) SetupSuite() {
 
 var dragonflyURL = "http://dragonfly.io.com?a=a&b=b&c=c"
 
-var taskID = idgen.TaskID(dragonflyURL, "a&b", &base.UrlMeta{Digest: "f1e2488bba4d1267948d9e2f7008571c"}, "dragonfly")
+var taskID = idgen.TaskID(dragonflyURL, &base.UrlMeta{Digest: "f1e2488bba4d1267948d9e2f7008571c", Tag: "dragonfly", Filter: "a&b"})
 
 func (suite *CDNManagerTestSuite) TearDownSuite() {
 	if suite.workHome != "" {
diff --git a/cdnsystem/daemon/task/manager_test.go b/cdnsystem/daemon/task/manager_test.go
index 72bc89ea..7530047f 100644
--- a/cdnsystem/daemon/task/manager_test.go
+++ b/cdnsystem/daemon/task/manager_test.go
@@ -40,7 +40,7 @@ type TaskManagerTestSuite struct {
 
 func (suite *TaskManagerTestSuite) TestRegister() {
 	dragonflyURL := "http://dragonfly.io.com?a=a&b=b&c=c"
-	taskID := idgen.TaskID(dragonflyURL, "a&b", &base.UrlMeta{Digest: "f1e2488bba4d1267948d9e2f7008571c"}, "dragonfly")
+	taskID := idgen.TaskID(dragonflyURL, &base.UrlMeta{Filter: "a&b", Tag: "dragonfly", Digest: "f1e2488bba4d1267948d9e2f7008571c"})
 	ctrl := gomock.NewController(suite.T())
 	cdnMgr := mock.NewMockCDNMgr(ctrl)
 	progressMgr := mock.NewMockSeedProgressMgr(ctrl)
diff --git a/client/daemon/peer/peertask_file_test.go b/client/daemon/peer/peertask_file_test.go
index 93c168cf..cb9ff1b2 100644
--- a/client/daemon/peer/peertask_file_test.go
+++ b/client/daemon/peer/peertask_file_test.go
@@ -26,6 +26,7 @@ import (
 	"testing"
 	"time"
 
+	"d7y.io/dragonfly/v2/pkg/rpc/base"
 	rangers "d7y.io/dragonfly/v2/pkg/util/rangeutils"
 
 	"d7y.io/dragonfly/v2/client/clientutil"
@@ -102,9 +103,10 @@ func TestFilePeerTask_BackSource_WithContentLength(t *testing.T) {
 	}
 	req := &FilePeerTaskRequest{
 		PeerTaskRequest: scheduler.PeerTaskRequest{
-			Url:      "http://localhost/test/data",
-			Filter:   "",
-			BizId:    "d7y-test",
+			Url: "http://localhost/test/data",
+			UrlMeta: &base.UrlMeta{
+				Tag: "d7y-test",
+			},
 			PeerId:   peerID,
 			PeerHost: &scheduler.PeerHost{},
 		},
@@ -212,9 +214,10 @@ func TestFilePeerTask_BackSource_WithoutContentLength(t *testing.T) {
 	}
 	req := &FilePeerTaskRequest{
 		PeerTaskRequest: scheduler.PeerTaskRequest{
-			Url:      "http://localhost/test/data",
-			Filter:   "",
-			BizId:    "d7y-test",
+			Url: "http://localhost/test/data",
+			UrlMeta: &base.UrlMeta{
+				Tag: "d7y-test",
+			},
 			PeerId:   peerID,
 			PeerHost: &scheduler.PeerHost{},
 		},
diff --git a/client/daemon/peer/peertask_manager_test.go b/client/daemon/peer/peertask_manager_test.go
index 29875da8..d105ad4d 100644
--- a/client/daemon/peer/peertask_manager_test.go
+++ b/client/daemon/peer/peertask_manager_test.go
@@ -203,9 +203,10 @@ func TestPeerTaskManager_StartFilePeerTask(t *testing.T) {
 	}
 	progress, _, err := ptm.StartFilePeerTask(context.Background(), &FilePeerTaskRequest{
 		PeerTaskRequest: scheduler.PeerTaskRequest{
-			Url:      "http://localhost/test/data",
-			Filter:   "",
-			BizId:    "d7y-test",
+			Url: "http://localhost/test/data",
+			UrlMeta: &base.UrlMeta{
+				Tag: "d7y-test",
+			},
 			PeerId:   peerID,
 			PeerHost: &scheduler.PeerHost{},
 		},
@@ -277,9 +278,10 @@ func TestPeerTaskManager_StartStreamPeerTask(t *testing.T) {
 	}
 
 	r, _, err := ptm.StartStreamPeerTask(context.Background(), &scheduler.PeerTaskRequest{
-		Url:      "http://localhost/test/data",
-		Filter:   "",
-		BizId:    "d7y-test",
+		Url: "http://localhost/test/data",
+		UrlMeta: &base.UrlMeta{
+			Tag: "d7y-test",
+		},
 		PeerId:   peerID,
 		PeerHost: &scheduler.PeerHost{},
 	})
diff --git a/client/daemon/peer/peertask_stream_test.go b/client/daemon/peer/peertask_stream_test.go
index 31c191bb..1d483147 100644
--- a/client/daemon/peer/peertask_stream_test.go
+++ b/client/daemon/peer/peertask_stream_test.go
@@ -25,6 +25,7 @@ import (
 	"testing"
 	"time"
 
+	"d7y.io/dragonfly/v2/pkg/rpc/base"
 	rangers "d7y.io/dragonfly/v2/pkg/util/rangeutils"
 
 	"d7y.io/dragonfly/v2/pkg/source"
@@ -99,9 +100,10 @@ func TestStreamPeerTask_BackSource_WithContentLength(t *testing.T) {
 		},
 	}
 	req := &scheduler.PeerTaskRequest{
-		Url:      url,
-		Filter:   "",
-		BizId:    "d7y-test",
+		Url: url,
+		UrlMeta: &base.UrlMeta{
+			Tag: "d7y-test",
+		},
 		PeerId:   peerID,
 		PeerHost: &scheduler.PeerHost{},
 	}
@@ -197,9 +199,10 @@ func TestStreamPeerTask_BackSource_WithoutContentLength(t *testing.T) {
 		},
 	}
 	req := &scheduler.PeerTaskRequest{
-		Url:      url,
-		Filter:   "",
-		BizId:    "d7y-test",
+		Url: url,
+		UrlMeta: &base.UrlMeta{
+			Tag: "d7y-test",
+		},
 		PeerId:   peerID,
 		PeerHost: &scheduler.PeerHost{},
 	}
diff --git a/internal/idgen/task_id_test.go b/internal/idgen/task_id_test.go
index f0246333..d3fa14ee 100644
--- a/internal/idgen/task_id_test.go
+++ b/internal/idgen/task_id_test.go
@@ -27,53 +27,49 @@ func TestTaskID(t *testing.T) {
 	tests := []struct {
 		name   string
 		url    string
-		filter string
 		meta   *base.UrlMeta
-		bizID  string
 		expect func(t *testing.T, d interface{})
 	}{
 		{
-			name:   "generate taskID with url",
-			url:    "https://example.com",
-			filter: "",
-			meta:   nil,
-			bizID:  "",
+			name: "generate taskID with url",
+			url:  "https://example.com",
+			meta: nil,
 			expect: func(t *testing.T, d interface{}) {
 				assert := assert.New(t)
 				assert.Equal("100680ad546ce6a577f42f52df33b4cfdca756859e664b8d7de329b150d09ce9", d)
 			},
 		},
 		{
-			name:   "generate taskID with meta",
-			url:    "https://example.com",
-			filter: "",
+			name: "generate taskID with meta",
+			url:  "https://example.com",
 			meta: &base.UrlMeta{
 				Range:  "foo",
 				Digest: "bar",
+				Tag:    "",
 			},
-			bizID: "",
 			expect: func(t *testing.T, d interface{}) {
 				assert := assert.New(t)
 				assert.Equal("aeee0e0a2a0c75130582641353c539aaf9011a0088b31347f7588e70e449a3e0", d)
 			},
 		},
 		{
-			name:   "generate taskID with filter",
-			url:    "https://example.com?foo=foo&bar=bar",
-			filter: "foo&bar",
-			meta:   nil,
-			bizID:  "",
+			name: "generate taskID with filter",
+			url:  "https://example.com?foo=foo&bar=bar",
+			meta: &base.UrlMeta{
+				Tag:    "foo",
+				Filter: "foo&bar",
+			},
 			expect: func(t *testing.T, d interface{}) {
 				assert := assert.New(t)
-				assert.Equal("100680ad546ce6a577f42f52df33b4cfdca756859e664b8d7de329b150d09ce9", d)
+				assert.Equal("2773851c628744fb7933003195db436ce397c1722920696c4274ff804d86920b", d)
 			},
 		},
 		{
-			name:   "generate taskID with bizID",
-			url:    "https://example.com",
-			filter: "",
-			meta:   nil,
-			bizID:  "foo",
+			name: "generate taskID with tag",
+			url:  "https://example.com",
+			meta: &base.UrlMeta{
+				Tag: "foo",
+			},
 			expect: func(t *testing.T, d interface{}) {
 				assert := assert.New(t)
 				assert.Equal("2773851c628744fb7933003195db436ce397c1722920696c4274ff804d86920b", d)
@@ -83,7 +79,7 @@ func TestTaskID(t *testing.T) {
 
 	for _, tc := range tests {
 		t.Run(tc.name, func(t *testing.T) {
-			data := TaskID(tc.url, tc.filter, tc.meta, tc.bizID)
+			data := TaskID(tc.url, tc.meta)
 			tc.expect(t, data)
 		})
 	}
@@ -93,18 +89,14 @@ func TestTwinsTaskID(t *testing.T) {
 	tests := []struct {
 		name   string
 		url    string
-		filter string
 		meta   *base.UrlMeta
-		bizID  string
 		peerID string
 		expect func(t *testing.T, d interface{})
 	}{
 		{
 			name:   "generate taskID with url",
 			url:    "https://example.com",
-			filter: "",
-			meta:   nil,
-			bizID:  "",
+			meta:   &base.UrlMeta{},
 			peerID: "foo",
 			expect: func(t *testing.T, d interface{}) {
 				assert := assert.New(t)
@@ -112,14 +104,12 @@ func TestTwinsTaskID(t *testing.T) {
 			},
 		},
 		{
-			name:   "generate taskID with meta",
-			url:    "https://example.com",
-			filter: "",
+			name: "generate taskID with meta",
+			url:  "https://example.com",
 			meta: &base.UrlMeta{
 				Range:  "foo",
 				Digest: "bar",
 			},
-			bizID:  "",
 			peerID: "foo",
 			expect: func(t *testing.T, d interface{}) {
 				assert := assert.New(t)
@@ -127,11 +117,11 @@ func TestTwinsTaskID(t *testing.T) {
 			},
 		},
 		{
-			name:   "generate taskID with filter",
-			url:    "https://example.com?foo=foo&bar=bar",
-			filter: "foo&bar",
-			meta:   nil,
-			bizID:  "",
+			name: "generate taskID with filter",
+			url:  "https://example.com?foo=foo&bar=bar",
+			meta: &base.UrlMeta{
+				Filter: "foo&bar",
+			},
 			peerID: "foo",
 			expect: func(t *testing.T, d interface{}) {
 				assert := assert.New(t)
@@ -139,11 +129,11 @@ func TestTwinsTaskID(t *testing.T) {
 			},
 		},
 		{
-			name:   "generate taskID with bizID",
-			url:    "https://example.com",
-			filter: "",
-			meta:   nil,
-			bizID:  "foo",
+			name: "generate taskID with tag",
+			url:  "https://example.com",
+			meta: &base.UrlMeta{
+				Tag: "foo",
+			},
 			peerID: "foo",
 			expect: func(t *testing.T, d interface{}) {
 				assert := assert.New(t)
@@ -153,9 +143,7 @@ func TestTwinsTaskID(t *testing.T) {
 		{
 			name:   "generate twinsA taskID",
 			url:    "https://example.com",
-			filter: "",
-			meta:   nil,
-			bizID:  "",
+			meta:   &base.UrlMeta{},
 			peerID: "bar",
 			expect: func(t *testing.T, d interface{}) {
 				assert := assert.New(t)
@@ -166,7 +154,7 @@ func TestTwinsTaskID(t *testing.T) {
 
 	for _, tc := range tests {
 		t.Run(tc.name, func(t *testing.T) {
-			data := TwinsTaskID(tc.url, tc.filter, tc.meta, tc.bizID, tc.peerID)
+			data := TwinsTaskID(tc.url, tc.meta, tc.peerID)
 			tc.expect(t, data)
 		})
 	}