Repository: dragonflyoss/dragonfly

Issue:
AutoIssueCert loses control when opt.Security. CACert is not empty
### Bug report:

https://github.com/dragonflyoss/Dragonfly2/blob/505d53b83c3000eff62cfda00a062c11b2b77bae/client/daemon/daemon.go#L154

The meaning of AutoIssueCert is as follows, but when CACert is not empty, tls is still used for peer to connect to the manager

type GlobalSecurityOption struct {
	// AutoIssueCert indicates to issue client certificates for all grpc call
	// if AutoIssueCert is false, any other option in Security will be ignored
	AutoIssueCert bool `mapstructure:"autoIssueCert" yaml:"autoIssueCert"`
	// CACert is the root CA certificate for all grpc tls handshake, it can be path or PEM format string
	CACert types.PEMContent `mapstructure:"caCert" yaml:"caCert"`
	// TLSVerify indicates to verify client certificates.
	TLSVerify bool `mapstructure:"tlsVerify" yaml:"tlsVerify"`
	// TLSPolicy controls the grpc shandshake behaviors:
	// force: both ClientHandshake and ServerHandshake are only support tls
	// prefer: ServerHandshake supports tls and insecure (non-tls), ClientHandshake will only support tls
	// default: ServerHandshake supports tls and insecure (non-tls), ClientHandshake will only support insecure (non-tls)
	TLSPolicy string `mapstructure:"tlsPolicy" yaml:"tlsPolicy"`
	// CertSpec is the desired state of certificate.
	CertSpec *CertSpec `mapstructure:"certSpec" yaml:"certSpec"`
}

### Expected behavior:

when AutoIssueCert=false and CACert="a ca cert", dfdaemon still use non-tls to connect the manager

### How to reproduce it:
 
set AutoIssueCert=false and CACert="a ca cert" in dfdaemon's global security config

Hints from issue comments:
@karlhjm: Why is it necessary to hard code "withTLS" to disable TLS for peerListener? Shouldn't withTLS be configured through TLSVerify or TLSPolicy?

https://github.com/dragonflyoss/Dragonfly2/blob/505d53b83c3000eff62cfda00a062c11b2b77bae/client/daemon/daemon.go#L512

https://github.com/dragonflyoss/Dragonfly2/blob/505d53b83c3000eff62cfda00a062c11b2b77bae/client/daemon/daemon.go#L608@gaius-qi: @karlhjm Please use latest version of the rust client, refer to https://github.com/dragonflyoss/client.

mTLS: https://d7y.io/docs/next/operations/best-practices/security/#mutual-tls.

Solution patch:
diff --git a/.github/workflows/compatibility-e2e-v2.yml b/.github/workflows/compatibility-e2e-v2.yml
index 38b67f23..2006fc8c 100644
--- a/.github/workflows/compatibility-e2e-v2.yml
+++ b/.github/workflows/compatibility-e2e-v2.yml
@@ -28,19 +28,19 @@ jobs:
         include:
           - module: manager
             image: manager
-            image-tag: v2.1.53
+            image-tag: v2.1.55
             chart-name: manager
           - module: scheduler
             image: scheduler
-            image-tag: v2.1.53
+            image-tag: v2.1.55
             chart-name: scheduler
           - module: client
             image: client
-            image-tag: v0.1.96
+            image-tag: v0.1.100
             chart-name: client
           - module: seed-client
             image: client
-            image-tag: v0.1.96
+            image-tag: v0.1.100
             chart-name: seed-client
 
     steps:
diff --git a/.github/workflows/scorecards.yml b/.github/workflows/scorecards.yml
new file mode 100644
index 00000000..d2967a88
--- /dev/null
+++ b/.github/workflows/scorecards.yml
@@ -0,0 +1,69 @@
+name: Scorecard supply-chain security
+on:
+  # For Branch-Protection check. Only the default branch is supported. See
+  # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection
+  branch_protection_rule:
+  # To guarantee Maintained check is occasionally updated. See
+  # https://github.com/ossf/scorecard/blob/main/docs/checks.md#maintained
+  schedule:
+    - cron: '15 20 * * 3'
+  push:
+    branches: [ "main" ]
+
+# Declare default permissions as read only.
+permissions: read-all
+
+jobs:
+  analysis:
+    name: Scorecard analysis
+    runs-on: ubuntu-latest
+    permissions:
+      # Needed to upload the results to code-scanning dashboard.
+      security-events: write
+      # Needed to publish results and get a badge (see publish_results below).
+      id-token: write
+      # Uncomment the permissions below if installing in a private repository.
+      # contents: read
+      # actions: read
+
+    steps:
+      - name: "Checkout code"
+        uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+        with:
+          persist-credentials: false
+
+      - name: "Run analysis"
+        uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
+        with:
+          results_file: results.sarif
+          results_format: sarif
+          # (Optional) "write" PAT token. Uncomment the `repo_token` line below if:
+          # - you want to enable the Branch-Protection check on a *public* repository, or
+          # - you are installing Scorecard on a *private* repository
+          # To create the PAT, follow the steps in https://github.com/ossf/scorecard-action?tab=readme-ov-file#authentication-with-fine-grained-pat-optional.
+          # repo_token: ${{ secrets.SCORECARD_TOKEN }}
+
+          # Public repositories:
+          #   - Publish results to OpenSSF REST API for easy access by consumers
+          #   - Allows the repository to include the Scorecard badge.
+          #   - See https://github.com/ossf/scorecard-action#publishing-results.
+          # For private repositories:
+          #   - `publish_results` will always be set to `false`, regardless
+          #     of the value entered here.
+          publish_results: true
+
+      # Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
+      # format to the repository Actions tab.
+      - name: "Upload artifact"
+        uses: actions/upload-artifact@97a0fba1372883ab732affbe8f94b823f91727db # v3.pre.node20
+        with:
+          name: SARIF file
+          path: results.sarif
+          retention-days: 5
+
+      # Upload the results to GitHub's code scanning dashboard (optional).
+      # Commenting out will disable upload of results to your repo's Code Scanning dashboard
+      - name: "Upload to code-scanning"
+        uses: github/codeql-action/upload-sarif@v3
+        with:
+          sarif_file: results.sarif
diff --git a/.goreleaser.yml b/.goreleaser.yml
index b3fba437..6e12952d 100644
--- a/.goreleaser.yml
+++ b/.goreleaser.yml
@@ -141,7 +141,7 @@ checksum:
   name_template: "checksums.txt"
 
 snapshot:
-  name_template: "{{ .Tag }}-next"
+  version_template: "{{ .Tag }}-next"
 
 changelog:
   sort: asc
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e243ab0b..6019d7e5 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -112,7 +112,7 @@
 - add unit test for Header.get ([#2568](https://github.com/dragonflyoss/Dragonfly2/issues/2568))
 - add unit test for Header.has ([#2555](https://github.com/dragonflyoss/Dragonfly2/issues/2555))
 - add unit test for Request.Context() ([#2554](https://github.com/dragonflyoss/Dragonfly2/issues/2554))
-- trainer serivce unit tests ([#2545](https://github.com/dragonflyoss/Dragonfly2/issues/2545))
+- trainer service unit tests ([#2545](https://github.com/dragonflyoss/Dragonfly2/issues/2545))
 - add unit test for model and digest ([#2538](https://github.com/dragonflyoss/Dragonfly2/issues/2538))
 - optimize TestDigest_HashFile ([#2515](https://github.com/dragonflyoss/Dragonfly2/issues/2515))
 - improve hash file encode test case in digest test ([#2513](https://github.com/dragonflyoss/Dragonfly2/issues/2513))
@@ -688,7 +688,7 @@
 - update d7y.io/api package and change cpu percent validation ([#2236](https://github.com/dragonflyoss/Dragonfly2/issues/2236))
 - add authinfo injector ([#2149](https://github.com/dragonflyoss/Dragonfly2/issues/2149))
 - when the cache is missing, change the error log to a warning log ([#2235](https://github.com/dragonflyoss/Dragonfly2/issues/2235))
--  if the scheduler feature is not in feature flags, then it will stop providing the featrue ([#2234](https://github.com/dragonflyoss/Dragonfly2/issues/2234))
+-  if the scheduler feature is not in feature flags, then it will stop providing the feature ([#2234](https://github.com/dragonflyoss/Dragonfly2/issues/2234))
 - add train interval and trainer addresses ([#2223](https://github.com/dragonflyoss/Dragonfly2/issues/2223))
 - add logger.CoreLogger to searcher plugin ([#2232](https://github.com/dragonflyoss/Dragonfly2/issues/2232))
 - add log to searcher plugin ([#2231](https://github.com/dragonflyoss/Dragonfly2/issues/2231))
@@ -1853,7 +1853,7 @@
 - update d7y.io/api package and change cpu percent validation ([#2236](https://github.com/dragonflyoss/Dragonfly2/issues/2236))
 - add authinfo injector ([#2149](https://github.com/dragonflyoss/Dragonfly2/issues/2149))
 - when the cache is missing, change the error log to a warning log ([#2235](https://github.com/dragonflyoss/Dragonfly2/issues/2235))
--  if the scheduler feature is not in feature flags, then it will stop providing the featrue ([#2234](https://github.com/dragonflyoss/Dragonfly2/issues/2234))
+-  if the scheduler feature is not in feature flags, then it will stop providing the feature ([#2234](https://github.com/dragonflyoss/Dragonfly2/issues/2234))
 - add train interval and trainer addresses ([#2223](https://github.com/dragonflyoss/Dragonfly2/issues/2223))
 
 ### Fix
diff --git a/README.md b/README.md
index c84a2e43..aa67c3c1 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@
 [![Twitter](https://img.shields.io/twitter/url?style=social&url=https%3A%2F%2Ftwitter.com%2Fdragonfly_oss)](https://twitter.com/dragonfly_oss)
 [![GoDoc](https://godoc.org/github.com/dragonflyoss/Dragonfly2?status.svg)](https://godoc.org/github.com/dragonflyoss/Dragonfly2)
 [![OpenSSF Best Practices](https://bestpractices.coreinfrastructure.org/projects/7103/badge)](https://bestpractices.coreinfrastructure.org/projects/7103)
+[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/dragonflyoss/dragonfly2/badge)](https://scorecard.dev/viewer/?uri=github.com/dragonflyoss/dragonfly2)
 [![LICENSE](https://img.shields.io/github/license/dragonflyoss/Dragonfly2.svg?style=flat-square)](https://github.com/dragonflyoss/Dragonfly2/blob/main/LICENSE)
 
 Provide efficient, stable and secure file distribution and image acceleration
diff --git a/client-rs b/client-rs
index 8796c424..94952ae7 160000
--- a/client-rs
+++ b/client-rs
@@ -1 +1 @@
-Subproject commit 8796c42436e3374c43a353d19d5b90c2cde85a72
+Subproject commit 94952ae77cfcd89cd5b542e76a49acb207eab44f
diff --git a/client/config/dynconfig_local.go b/client/config/dynconfig_local.go
index 0dd583c1..8c4a9e6c 100644
--- a/client/config/dynconfig_local.go
+++ b/client/config/dynconfig_local.go
@@ -46,7 +46,7 @@ type dynconfigLocal struct {
 	transportCredentials credentials.TransportCredentials
 }
 
-// newDynconfigLocal returns a new local dynconfig instence.
+// newDynconfigLocal returns a new local dynconfig instance.
 func newDynconfigLocal(cfg *DaemonOption, creds credentials.TransportCredentials) (Dynconfig, error) {
 	return &dynconfigLocal{
 		config:               cfg,
diff --git a/client/config/dynconfig_manager.go b/client/config/dynconfig_manager.go
index f88217b5..735e20f4 100644
--- a/client/config/dynconfig_manager.go
+++ b/client/config/dynconfig_manager.go
@@ -57,7 +57,7 @@ type dynconfigManager struct {
 	mu                   sync.Mutex
 }
 
-// newDynconfigManager returns a new manager dynconfig instence.
+// newDynconfigManager returns a new manager dynconfig instance.
 func newDynconfigManager(cfg *DaemonOption, rawManagerClient managerclient.V1, cacheDir string, creds credentials.TransportCredentials) (Dynconfig, error) {
 	cachePath := filepath.Join(cacheDir, cacheFileName)
 	d, err := internaldynconfig.New[DynconfigData](
diff --git a/client/daemon/daemon.go b/client/daemon/daemon.go
index 5a53b60d..ab2cd5f9 100644
--- a/client/daemon/daemon.go
+++ b/client/daemon/daemon.go
@@ -151,13 +151,13 @@ func New(opt *config.DaemonOption, d dfpath.Dfpath) (Daemon, error) {
 	if opt.Scheduler.Manager.Enable {
 		var grpcCredentials credentials.TransportCredentials
 
-		if opt.Security.CACert == "" {
-			grpcCredentials = insecure.NewCredentials()
-		} else {
+		if opt.Security.AutoIssueCert {
 			grpcCredentials, err = loadManagerGPRCTLSCredentials(opt.Security)
 			if err != nil {
 				return nil, err
 			}
+		} else {
+			grpcCredentials = insecure.NewCredentials()
 		}
 
 		managerClient, err = managerclient.GetV1ByNetAddrs(
diff --git a/client/daemon/metrics/metrics.go b/client/daemon/metrics/metrics.go
index a56b458d..582bd87e 100644
--- a/client/daemon/metrics/metrics.go
+++ b/client/daemon/metrics/metrics.go
@@ -34,7 +34,7 @@ const (
 	// Failed download task type is source
 	FailTypeBackSource = "source"
 
-	// Failed download task type is init, indecates not yet register to scheduler
+	// Failed download task type is init, indicates not yet register to scheduler
 	FailTypeInit = "init"
 
 	// SeedPeerDownload type is p2p
diff --git a/client/daemon/peer/peertask_reuse.go b/client/daemon/peer/peertask_reuse.go
index 8ef3f558..a2bfc9d0 100644
--- a/client/daemon/peer/peertask_reuse.go
+++ b/client/daemon/peer/peertask_reuse.go
@@ -21,6 +21,7 @@ import (
 	"fmt"
 	"io"
 	"os"
+	"strings"
 	"time"
 
 	"github.com/go-http-utils/headers"
@@ -226,6 +227,10 @@ func (ptm *peerTaskManager) storePartialFile(ctx context.Context, request *FileT
 	return nil
 }
 
+func hasRangeEnd(rg string) bool {
+	return !strings.HasSuffix(rg, "-")
+}
+
 func (ptm *peerTaskManager) tryReuseStreamPeerTask(ctx context.Context, taskID string,
 	request *StreamTaskRequest) (io.ReadCloser, map[string]string, bool) {
 	var (
@@ -328,13 +333,20 @@ func (ptm *peerTaskManager) tryReuseStreamPeerTask(ctx context.Context, taskID s
 		attr[headers.ContentRange] = fmt.Sprintf("bytes %d-%d/%d", reuseRange.Start,
 			reuseRange.Start+reuseRange.Length-1, reuse.ContentLength)
 	} else if request.Range != nil {
-		// the length is from reuse task, ensure it equal with request
-		if length != request.Range.Length {
-			log.Errorf("target task length %d did not match range length %d", length, request.Range.Length)
-			return nil, nil, false
+		// skip check length for no range end case
+		if !hasRangeEnd(request.URLMeta.Range) {
+			// no range end, indicate start + length = total size
+			attr[headers.ContentRange] = fmt.Sprintf("bytes %d-%d/%d", request.Range.Start,
+				request.Range.Start+length-1, request.Range.Start+length)
+		} else {
+			// the length is from reuse task, ensure it equal with request
+			if length != request.Range.Length {
+				log.Errorf("target task length %d did not match range length %d", length, request.Range.Length)
+				return nil, nil, false
+			}
+			attr[headers.ContentRange] = fmt.Sprintf("bytes %d-%d/*", request.Range.Start,
+				request.Range.Start+length-1)
 		}
-		attr[headers.ContentRange] = fmt.Sprintf("bytes %d-%d/*", request.Range.Start,
-			request.Range.Start+request.Range.Length-1)
 	}
 
 	// TODO record time when file closed, need add a type to implement Close and WriteTo
diff --git a/client/daemon/transport/transport.go b/client/daemon/transport/transport.go
index 6ac6025b..d4fe6751 100644
--- a/client/daemon/transport/transport.go
+++ b/client/daemon/transport/transport.go
@@ -398,6 +398,8 @@ local:
 
 	var contentLength int64 = -1
 	if l, ok := attr[headers.ContentLength]; ok {
+		// for library like opencv, it depends on AcceptRanges, otherwise it will complain "partial file" error
+		hdr.Set(headers.AcceptRanges, "bytes")
 		if i, e := strconv.ParseInt(l, 10, 64); e == nil {
 			contentLength = i
 		}
@@ -408,8 +410,8 @@ local:
 		httpStatus = http.StatusOK
 	} else {
 		httpStatus = http.StatusPartialContent
-		if hdr.Get(headers.ContentRange) == "" && contentLength > 0 {
-			value := fmt.Sprintf("bytes %d-%d/%d", rg.Start, rg.Start+contentLength-1, rg.Start+contentLength)
+		if len(hdr.Get(headers.ContentRange)) == 0 && contentLength > 0 {
+			value := fmt.Sprintf("bytes %d-%d/*", rg.Start, rg.Start+contentLength-1)
 			hdr.Set(headers.ContentRange, value)
 		}
 	}
diff --git a/client/daemon/upload/types.go b/client/daemon/upload/types.go
index e9b62f6e..f6511f5f 100644
--- a/client/daemon/upload/types.go
+++ b/client/daemon/upload/types.go
@@ -21,6 +21,6 @@ type DownloadParams struct {
 	TaskID     string `uri:"task_id" binding:"required"`
 }
 
-type DownalodQuery struct {
+type DownloadQuery struct {
 	PeerID string `form:"peerId" binding:"required"`
 }
diff --git a/client/daemon/upload/upload_manager.go b/client/daemon/upload/upload_manager.go
index b9c9afe1..fc418ccd 100644
--- a/client/daemon/upload/upload_manager.go
+++ b/client/daemon/upload/upload_manager.go
@@ -88,7 +88,7 @@ func WithCertify(ct *certify.Certify) func(manager *uploadManager) {
 	}
 }
 
-// New returns a new Manager instence.
+// New returns a new Manager instance.
 func NewUploadManager(cfg *config.DaemonOption, storageManager storage.Manager, logDir string, opts ...Option) (Manager, error) {
 	um := &uploadManager{
 		storageManager: storageManager,
@@ -200,7 +200,7 @@ func (um *uploadManager) getDownload(ctx *gin.Context) {
 		return
 	}
 
-	var query DownalodQuery
+	var query DownloadQuery
 	if err := ctx.ShouldBindQuery(&query); err != nil {
 		ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()})
 		return
diff --git a/client/dfstore/dfstore.go b/client/dfstore/dfstore.go
index ef615eb0..dc747c00 100644
--- a/client/dfstore/dfstore.go
+++ b/client/dfstore/dfstore.go
@@ -61,7 +61,7 @@ type Dfstore interface {
 	// GetObjectMetadataRequestWithContext returns *http.Request of getting object metadata.
 	GetObjectMetadataRequestWithContext(ctx context.Context, input *GetObjectMetadataInput) (*http.Request, error)
 
-	// GetObjectMetadataWithContext returns matedata of object.
+	// GetObjectMetadataWithContext returns metadata of object.
 	GetObjectMetadataWithContext(ctx context.Context, input *GetObjectMetadataInput) (*pkgobjectstorage.ObjectMetadata, error)
 
 	// GetObjectRequestWithContext returns *http.Request of getting object.
diff --git a/go.mod b/go.mod
index d3e67c29..44f21364 100644
--- a/go.mod
+++ b/go.mod
@@ -3,14 +3,14 @@ module d7y.io/dragonfly/v2
 go 1.21
 
 require (
-	d7y.io/api/v2 v2.0.142
+	d7y.io/api/v2 v2.0.148
 	github.com/MysteriousPotato/go-lockable v1.0.0
 	github.com/RichardKnop/machinery v1.10.8
 	github.com/Showmax/go-fqdn v1.0.0
 	github.com/VividCortex/mysqlerr v1.0.0
 	github.com/aliyun/aliyun-oss-go-sdk v3.0.2+incompatible
 	github.com/appleboy/gin-jwt/v2 v2.9.2
-	github.com/aws/aws-sdk-go v1.54.19
+	github.com/aws/aws-sdk-go v1.55.5
 	github.com/bits-and-blooms/bitset v1.13.0
 	github.com/casbin/casbin/v2 v2.81.0
 	github.com/casbin/gorm-adapter/v3 v3.5.0
@@ -85,7 +85,7 @@ require (
 	golang.org/x/exp v0.0.0-20231214170342-aacd6d4b4611
 	golang.org/x/oauth2 v0.21.0
 	golang.org/x/sync v0.8.0
-	golang.org/x/sys v0.22.0
+	golang.org/x/sys v0.24.0
 	golang.org/x/time v0.5.0
 	google.golang.org/api v0.189.0
 	google.golang.org/grpc v1.65.0
@@ -129,7 +129,7 @@ require (
 	github.com/distribution/reference v0.5.0 // indirect
 	github.com/docker/go-metrics v0.0.1 // indirect
 	github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 // indirect
-	github.com/envoyproxy/protoc-gen-validate v1.0.4 // indirect
+	github.com/envoyproxy/protoc-gen-validate v1.1.0 // indirect
 	github.com/felixge/httpsnoop v1.0.4 // indirect
 	github.com/fsnotify/fsnotify v1.7.0 // indirect
 	github.com/gabriel-vasile/mimetype v1.4.4 // indirect
diff --git a/go.sum b/go.sum
index a0502370..bbd3d266 100644
--- a/go.sum
+++ b/go.sum
@@ -53,8 +53,8 @@ cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0Zeo
 cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk=
 cloud.google.com/go/storage v1.8.0/go.mod h1:Wv1Oy7z6Yz3DshWRJFhqM/UCfaWIRTdp0RXyy7KQOVs=
 cloud.google.com/go/storage v1.10.0/go.mod h1:FLPqc6j+Ki4BU591ie1oL6qBQGu2Bl/tZ9ullr3+Kg0=
-d7y.io/api/v2 v2.0.142 h1:u1gQZwCKJODdJB883J9e5SRK9VmOTmApX13FX/bR0Vk=
-d7y.io/api/v2 v2.0.142/go.mod h1:IakrltEphFvcLIQs3NVeb9PAe66MGDnd2/HMs9DKYu8=
+d7y.io/api/v2 v2.0.148 h1:11waj+EuaHdx95Fkr3hXJJckNGw9Hu5U0ohtCbpIirw=
+d7y.io/api/v2 v2.0.148/go.mod h1:hyEaaIglThVWRHODk2yHN/tpa1L+/nPgdQFwPsL6fNc=
 dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
 github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc=
 github.com/Azure/azure-sdk-for-go/sdk/azcore v1.0.0/go.mod h1:uGG2W01BaETf0Ozp+QxxKJdMBNRWPdstHG0Fmdwn1/U=
@@ -158,8 +158,8 @@ github.com/aws/aws-sdk-go v1.27.0/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN
 github.com/aws/aws-sdk-go v1.30.27/go.mod h1:5zCpMtNQVjRREroY7sYe8lOMRSxkhG6MZveU8YkpAk0=
 github.com/aws/aws-sdk-go v1.34.28/go.mod h1:H7NKnBqNVzoTJpGfLrQkkD+ytBA93eiDYi/+8rV9s48=
 github.com/aws/aws-sdk-go v1.37.16/go.mod h1:hcU610XS61/+aQV88ixoOzUoG7v3b31pl2zKMmprdro=
-github.com/aws/aws-sdk-go v1.54.19 h1:tyWV+07jagrNiCcGRzRhdtVjQs7Vy41NwsuOcl0IbVI=
-github.com/aws/aws-sdk-go v1.54.19/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
+github.com/aws/aws-sdk-go v1.55.5 h1:KKUZBfBoyqy5d3swXyiC7Q76ic40rYcbqH7qjh59kzU=
+github.com/aws/aws-sdk-go v1.55.5/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU=
 github.com/aws/aws-sdk-go-v2 v0.18.0/go.mod h1:JWVYvqSMppoMJC0x5wdwiImzgXTI9FuZwxzkQq9wy+g=
 github.com/aws/aws-sdk-go-v2 v1.8.1/go.mod h1:xEFuWz+3TYdlPRuo+CqATbeDWIWyaT5uAPwPaWtgse0=
 github.com/aws/aws-sdk-go-v2/service/acmpca v1.6.3/go.mod h1:b8TQvsqtuWslJ4o+eXiHV59P4t20d0EJJ/YVICGJu/o=
@@ -434,8 +434,8 @@ github.com/envoyproxy/go-control-plane v0.9.7/go.mod h1:cwu0lG7PUMfa9snN8LXBig5y
 github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
 github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
 github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
-github.com/envoyproxy/protoc-gen-validate v1.0.4 h1:gVPz/FMfvh57HdSJQyvBtF00j8JU4zdyUgIUNhlgg0A=
-github.com/envoyproxy/protoc-gen-validate v1.0.4/go.mod h1:qys6tmnRsYrQqIhm2bvKZH4Blx/1gTIZ2UKVY1M+Yew=
+github.com/envoyproxy/protoc-gen-validate v1.1.0 h1:tntQDh69XqOCOZsDz0lVJQez/2L6Uu2PdjCQwWCJ3bM=
+github.com/envoyproxy/protoc-gen-validate v1.1.0/go.mod h1:sXRDRVmzEbkM7CVcM06s9shE/m23dg3wzjl0UWqJ2q4=
 github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
 github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
 github.com/fatih/structs v1.1.0/go.mod h1:9NiDSp5zOcgEDl+j00MP/WkGVPOlPRLejGD8Ga6PJ7M=
@@ -1850,8 +1850,9 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
 golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg=
+golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
 golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
diff --git a/internal/job/constants.go b/internal/job/constants.go
index d977f443..d5d12e10 100644
--- a/internal/job/constants.go
+++ b/internal/job/constants.go
@@ -29,6 +29,12 @@ const (
 
 	// SyncPeersJob is the name of syncing peers job.
 	SyncPeersJob = "sync_peers"
+
+	// GetTaskJob is the name of getting task job.
+	GetTaskJob = "get_task"
+
+	// DeleteTaskJob is the name of deleting task job.
+	DeleteTaskJob = "delete_task"
 )
 
 // Machinery server configuration.
diff --git a/internal/job/types.go b/internal/job/types.go
index cdbdb55a..e7659665 100644
--- a/internal/job/types.go
+++ b/internal/job/types.go
@@ -16,16 +16,47 @@
 
 package job
 
+import "d7y.io/dragonfly/v2/scheduler/resource"
+
+// PreheatRequest defines the request parameters for preheating.
 type PreheatRequest struct {
 	URL                 string            `json:"url" validate:"required,url"`
 	Tag                 string            `json:"tag" validate:"omitempty"`
 	Digest              string            `json:"digest" validate:"omitempty"`
-	FilteredQueryParams string            `json:"filteredQueryParams" validate:"omitempty"`
+	FilteredQueryParams string            `json:"filtered_query_params" validate:"omitempty"`
 	Headers             map[string]string `json:"headers" validate:"omitempty"`
 	Application         string            `json:"application" validate:"omitempty"`
 	Priority            int32             `json:"priority" validate:"omitempty"`
-	PieceLength         uint32            `json:"pieceLength" validate:"omitempty"`
 }
 
+// PreheatResponse defines the response parameters for preheating.
 type PreheatResponse struct {
+	TaskID string `json:"task_id"`
+}
+
+// GetTaskRequest defines the request parameters for getting task.
+type GetTaskRequest struct {
+	TaskID string `json:"task_id" validate:"required"`
+}
+
+// GetTaskResponse defines the response parameters for getting task.
+type GetTaskResponse struct {
+	Peers []*resource.Peer `json:"peers"`
+}
+
+// DeleteTaskRequest defines the request parameters for deleting task.
+type DeleteTaskRequest struct {
+	TaskID string `json:"task_id" validate:"required"`
+}
+
+// DeleteTaskResponse defines the response parameters for deleting task.
+type DeleteTaskResponse struct {
+	SuccessPeers []*DeletePeerResponse `json:"success_peers"`
+	FailurePeers []*DeletePeerResponse `json:"failure_peers"`
+}
+
+// DeletePeerResponse represents the response after attempting to delete a peer.
+type DeletePeerResponse struct {
+	Peer        *resource.Peer `json:"peer"`
+	Description string         `json:"description"`
 }
diff --git a/manager/config/constant_otel.go b/manager/config/constant_otel.go
index 071c4f9b..f2a10ca0 100644
--- a/manager/config/constant_otel.go
+++ b/manager/config/constant_otel.go
@@ -19,9 +19,11 @@ package config
 import "go.opentelemetry.io/otel/attribute"
 
 const (
-	AttributeID          = attribute.Key("d7y.manager.id")
-	AttributePreheatType = attribute.Key("d7y.manager.preheat.type")
-	AttributePreheatURL  = attribute.Key("d7y.manager.preheat.url")
+	AttributeID           = attribute.Key("d7y.manager.id")
+	AttributePreheatType  = attribute.Key("d7y.manager.preheat.type")
+	AttributePreheatURL   = attribute.Key("d7y.manager.preheat.url")
+	AttributeDeleteTaskID = attribute.Key("d7y.manager.delete_task.id")
+	AttributeGetTaskID    = attribute.Key("d7y.manager.get_task.id")
 )
 
 const (
@@ -29,4 +31,6 @@ const (
 	SpanSyncPeers        = "sync-peers"
 	SpanGetLayers        = "get-layers"
 	SpanAuthWithRegistry = "auth-with-registry"
+	SpanDeleteTask       = "delete-task"
+	SpanGetTask          = "get-task"
 )
diff --git a/manager/console b/manager/console
index 78690c93..9b388891 160000
--- a/manager/console
+++ b/manager/console
@@ -1 +1 @@
-Subproject commit 78690c93b3d0c5268ceff1acc96f45a8e559c394
+Subproject commit 9b3888916971368ddfd692d5f0427e919df670d4
diff --git a/manager/handlers/job.go b/manager/handlers/job.go
index f96ae39a..8ebd8906 100644
--- a/manager/handlers/job.go
+++ b/manager/handlers/job.go
@@ -59,6 +59,34 @@ func (h *Handlers) CreateJob(ctx *gin.Context) {
 			return
 		}
 
+		ctx.JSON(http.StatusOK, job)
+	case job.GetTaskJob:
+		var json types.CreateGetTaskJobRequest
+		if err := ctx.ShouldBindBodyWith(&json, binding.JSON); err != nil {
+			ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()})
+			return
+		}
+
+		job, err := h.service.CreateGetTaskJob(ctx.Request.Context(), json)
+		if err != nil {
+			ctx.Error(err) // nolint: errcheck
+			return
+		}
+
+		ctx.JSON(http.StatusOK, job)
+	case job.DeleteTaskJob:
+		var json types.CreateDeleteTaskJobRequest
+		if err := ctx.ShouldBindBodyWith(&json, binding.JSON); err != nil {
+			ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": err.Error()})
+			return
+		}
+
+		job, err := h.service.CreateDeleteTaskJob(ctx.Request.Context(), json)
+		if err != nil {
+			ctx.Error(err) // nolint: errcheck
+			return
+		}
+
 		ctx.JSON(http.StatusOK, job)
 	default:
 		ctx.JSON(http.StatusUnprocessableEntity, gin.H{"errors": "Unknow type"})
diff --git a/manager/job/job.go b/manager/job/job.go
index bac8c7a6..1f698a41 100644
--- a/manager/job/job.go
+++ b/manager/job/job.go
@@ -40,6 +40,7 @@ type Job struct {
 	*internaljob.Job
 	Preheat
 	SyncPeers
+	Task
 }
 
 // New returns a new Job.
@@ -74,10 +75,12 @@ func New(cfg *config.Config, gdb *gorm.DB) (*Job, error) {
 		return nil, err
 	}
 
+	task := newTask(j)
 	return &Job{
 		Job:       j,
 		Preheat:   preheat,
 		SyncPeers: syncPeers,
+		Task:      task,
 	}, nil
 }
 
@@ -92,18 +95,18 @@ func (j *Job) Stop() {
 }
 
 // getSchedulerQueues gets scheduler queues.
-func getSchedulerQueues(schedulers []models.Scheduler) []internaljob.Queue {
+func getSchedulerQueues(schedulers []models.Scheduler) ([]internaljob.Queue, error) {
 	var queues []internaljob.Queue
 	for _, scheduler := range schedulers {
 		queue, err := internaljob.GetSchedulerQueue(scheduler.SchedulerClusterID, scheduler.Hostname)
 		if err != nil {
-			continue
+			return nil, err
 		}
 
 		queues = append(queues, queue)
 	}
 
-	return queues
+	return queues, nil
 }
 
 // getSchedulerQueue gets scheduler queue.
diff --git a/manager/job/mocks/task_mock.go b/manager/job/mocks/task_mock.go
new file mode 100644
index 00000000..82b59c26
--- /dev/null
+++ b/manager/job/mocks/task_mock.go
@@ -0,0 +1,73 @@
+// Code generated by MockGen. DO NOT EDIT.
+// Source: task.go
+//
+// Generated by this command:
+//
+//	mockgen -destination mocks/task_mock.go -source task.go -package mocks
+//
+
+// Package mocks is a generated GoMock package.
+package mocks
+
+import (
+	context "context"
+	reflect "reflect"
+
+	job "d7y.io/dragonfly/v2/internal/job"
+	models "d7y.io/dragonfly/v2/manager/models"
+	types "d7y.io/dragonfly/v2/manager/types"
+	gomock "go.uber.org/mock/gomock"
+)
+
+// MockTask is a mock of Task interface.
+type MockTask struct {
+	ctrl     *gomock.Controller
+	recorder *MockTaskMockRecorder
+}
+
+// MockTaskMockRecorder is the mock recorder for MockTask.
+type MockTaskMockRecorder struct {
+	mock *MockTask
+}
+
+// NewMockTask creates a new mock instance.
+func NewMockTask(ctrl *gomock.Controller) *MockTask {
+	mock := &MockTask{ctrl: ctrl}
+	mock.recorder = &MockTaskMockRecorder{mock}
+	return mock
+}
+
+// EXPECT returns an object that allows the caller to indicate expected use.
+func (m *MockTask) EXPECT() *MockTaskMockRecorder {
+	return m.recorder
+}
+
+// CreateDeleteTask mocks base method.
+func (m *MockTask) CreateDeleteTask(arg0 context.Context, arg1 []models.Scheduler, arg2 types.DeleteTaskArgs) (*job.GroupJobState, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CreateDeleteTask", arg0, arg1, arg2)
+	ret0, _ := ret[0].(*job.GroupJobState)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// CreateDeleteTask indicates an expected call of CreateDeleteTask.
+func (mr *MockTaskMockRecorder) CreateDeleteTask(arg0, arg1, arg2 any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateDeleteTask", reflect.TypeOf((*MockTask)(nil).CreateDeleteTask), arg0, arg1, arg2)
+}
+
+// CreateGetTask mocks base method.
+func (m *MockTask) CreateGetTask(arg0 context.Context, arg1 []models.Scheduler, arg2 types.GetTaskArgs) (*job.GroupJobState, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CreateGetTask", arg0, arg1, arg2)
+	ret0, _ := ret[0].(*job.GroupJobState)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// CreateGetTask indicates an expected call of CreateGetTask.
+func (mr *MockTaskMockRecorder) CreateGetTask(arg0, arg1, arg2 any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateGetTask", reflect.TypeOf((*MockTask)(nil).CreateGetTask), arg0, arg1, arg2)
+}
diff --git a/manager/job/preheat.go b/manager/job/preheat.go
index 19c66ebe..fe1bf438 100644
--- a/manager/job/preheat.go
+++ b/manager/job/preheat.go
@@ -109,7 +109,6 @@ func (p *preheat) CreatePreheat(ctx context.Context, schedulers []models.Schedul
 				URL:                 json.URL,
 				Tag:                 json.Tag,
 				FilteredQueryParams: json.FilteredQueryParams,
-				PieceLength:         json.PieceLength,
 				Headers:             json.Headers,
 			},
 		}
@@ -118,7 +117,11 @@ func (p *preheat) CreatePreheat(ctx context.Context, schedulers []models.Schedul
 	}
 
 	// Initialize queues.
-	queues := getSchedulerQueues(schedulers)
+	queues, err := getSchedulerQueues(schedulers)
+	if err != nil {
+		return nil, err
+	}
+
 	return p.createGroupJob(ctx, files, queues)
 }
 
@@ -223,7 +226,7 @@ func (p *preheat) getImageLayers(ctx context.Context, args types.PreheatArgs) ([
 	// set authorization header
 	header.Set("Authorization", client.GetAuthToken())
 
-	// prase image layers to preheat
+	// parse image layers to preheat
 	layers, err := p.parseLayers(manifests, args, header.Clone(), image)
 	if err != nil {
 		return nil, err
@@ -319,7 +322,6 @@ func (p *preheat) parseLayers(manifests []distribution.Manifest, args types.Preh
 				URL:                 image.blobsURL(v.Digest.String()),
 				Tag:                 args.Tag,
 				FilteredQueryParams: args.FilteredQueryParams,
-				PieceLength:         args.PieceLength,
 				Headers:             nethttp.HeaderToMap(header),
 			}
 
diff --git a/manager/job/task.go b/manager/job/task.go
new file mode 100644
index 00000000..5cfb8efd
--- /dev/null
+++ b/manager/job/task.go
@@ -0,0 +1,133 @@
+/*
+ *     Copyright 2024 The Dragonfly Authors
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//go:generate mockgen -destination mocks/task_mock.go -source task.go -package mocks
+
+package job
+
+import (
+	"context"
+	"fmt"
+	"time"
+
+	machineryv1tasks "github.com/RichardKnop/machinery/v1/tasks"
+	"github.com/google/uuid"
+	"go.opentelemetry.io/otel/trace"
+
+	logger "d7y.io/dragonfly/v2/internal/dflog"
+	internaljob "d7y.io/dragonfly/v2/internal/job"
+	"d7y.io/dragonfly/v2/manager/config"
+	"d7y.io/dragonfly/v2/manager/models"
+	"d7y.io/dragonfly/v2/manager/types"
+)
+
+// Task is an interface for manager tasks.
+type Task interface {
+	// CreateDeleteTask create a delete task job
+	CreateDeleteTask(context.Context, []models.Scheduler, types.DeleteTaskArgs) (*internaljob.GroupJobState, error)
+
+	// CreateGetTask create a get task job
+	CreateGetTask(context.Context, []models.Scheduler, types.GetTaskArgs) (*internaljob.GroupJobState, error)
+}
+
+// task is an implementation of Task.
+type task struct {
+	job *internaljob.Job
+}
+
+// newTask returns a new Task.
+func newTask(job *internaljob.Job) Task {
+	return &task{job}
+}
+
+// CreateDeleteTask create a delete task job
+func (t *task) CreateDeleteTask(ctx context.Context, schedulers []models.Scheduler, json types.DeleteTaskArgs) (*internaljob.GroupJobState, error) {
+	var span trace.Span
+	ctx, span = tracer.Start(ctx, config.SpanDeleteTask, trace.WithSpanKind(trace.SpanKindProducer))
+	span.SetAttributes(config.AttributeDeleteTaskID.String(json.TaskID))
+	defer span.End()
+
+	args, err := internaljob.MarshalRequest(json)
+	if err != nil {
+		logger.Errorf("delete task marshal request: %v, error: %v", args, err)
+		return nil, err
+	}
+
+	// Initialize queues.
+	queues, err := getSchedulerQueues(schedulers)
+	if err != nil {
+		return nil, err
+	}
+
+	return t.createGroupJob(ctx, internaljob.DeleteTaskJob, args, queues)
+}
+
+// CreateGetTask create a get task job
+func (t *task) CreateGetTask(ctx context.Context, schedulers []models.Scheduler, json types.GetTaskArgs) (*internaljob.GroupJobState, error) {
+	var span trace.Span
+	ctx, span = tracer.Start(ctx, config.SpanGetTask, trace.WithSpanKind(trace.SpanKindProducer))
+	span.SetAttributes(config.AttributeGetTaskID.String(json.TaskID))
+	defer span.End()
+
+	args, err := internaljob.MarshalRequest(json)
+	if err != nil {
+		logger.Errorf("list tasks marshal request: %v, error: %v", args, err)
+		return nil, err
+	}
+
+	// Initialize queues.
+	queues, err := getSchedulerQueues(schedulers)
+	if err != nil {
+		return nil, err
+	}
+
+	return t.createGroupJob(ctx, internaljob.GetTaskJob, args, queues)
+}
+
+// createGroupJob creates a group job.
+func (t *task) createGroupJob(ctx context.Context, name string, args []machineryv1tasks.Arg, queues []internaljob.Queue) (*internaljob.GroupJobState, error) {
+	var signatures []*machineryv1tasks.Signature
+	for _, queue := range queues {
+		signatures = append(signatures, &machineryv1tasks.Signature{
+			UUID:       fmt.Sprintf("task_%s", uuid.New().String()),
+			Name:       name,
+			RoutingKey: queue.String(),
+			Args:       args,
+		})
+	}
+
+	group, err := machineryv1tasks.NewGroup(signatures...)
+	if err != nil {
+		return nil, err
+	}
+
+	var tasks []machineryv1tasks.Signature
+	for _, signature := range signatures {
+		tasks = append(tasks, *signature)
+	}
+
+	logger.Infof("create task group %s in queues %v, tasks: %#v", group.GroupUUID, queues, tasks)
+	if _, err := t.job.Server.SendGroupWithContext(ctx, group, 0); err != nil {
+		logger.Errorf("create task group %s failed", group.GroupUUID, err)
+		return nil, err
+	}
+
+	return &internaljob.GroupJobState{
+		GroupUUID: group.GroupUUID,
+		State:     machineryv1tasks.StatePending,
+		CreatedAt: time.Now(),
+	}, nil
+}
diff --git a/manager/rpcserver/manager_server_v1.go b/manager/rpcserver/manager_server_v1.go
index c818b782..abab6775 100644
--- a/manager/rpcserver/manager_server_v1.go
+++ b/manager/rpcserver/manager_server_v1.go
@@ -177,7 +177,7 @@ func (s *managerServerV1) GetSeedPeer(ctx context.Context, req *managerv1.GetSee
 	return &pbSeedPeer, nil
 }
 
-// List acitve seed peers configuration.
+// List active seed peers configuration.
 func (s *managerServerV1) ListSeedPeers(ctx context.Context, req *managerv1.ListSeedPeersRequest) (*managerv1.ListSeedPeersResponse, error) {
 	log := logger.WithHostnameAndIP(req.Hostname, req.Ip)
 	log.Debugf("list seed peers, version %s, commit %s", req.Version, req.Commit)
@@ -536,7 +536,7 @@ func (s *managerServerV1) createScheduler(ctx context.Context, req *managerv1.Up
 	}, nil
 }
 
-// List acitve schedulers configuration.
+// List active schedulers configuration.
 func (s *managerServerV1) ListSchedulers(ctx context.Context, req *managerv1.ListSchedulersRequest) (*managerv1.ListSchedulersResponse, error) {
 	log := logger.WithHostnameAndIP(req.Hostname, req.Ip)
 	log.Debugf("list schedulers, version %s, commit %s", req.Version, req.Commit)
@@ -560,7 +560,7 @@ func (s *managerServerV1) ListSchedulers(ctx context.Context, req *managerv1.Lis
 		return nil, status.Error(codes.Internal, err.Error())
 	}
 
-	// Remove schedulers which not have scehdule featrue. As OceanBase does not support JSON type,
+	// Remove schedulers which not have schedule feature. As OceanBase does not support JSON type,
 	// it is not possible to use datatypes.JSONQuery for filtering.
 	var tmpSchedulerClusters []models.SchedulerCluster
 	for _, schedulerCluster := range schedulerClusters {
diff --git a/manager/rpcserver/manager_server_v2.go b/manager/rpcserver/manager_server_v2.go
index 00f18a96..a3ff1dc1 100644
--- a/manager/rpcserver/manager_server_v2.go
+++ b/manager/rpcserver/manager_server_v2.go
@@ -161,7 +161,7 @@ func (s *managerServerV2) GetSeedPeer(ctx context.Context, req *managerv2.GetSee
 	return &pbSeedPeer, nil
 }
 
-// List acitve seed peers configuration.
+// List active seed peers configuration.
 func (s *managerServerV2) ListSeedPeers(ctx context.Context, req *managerv2.ListSeedPeersRequest) (*managerv2.ListSeedPeersResponse, error) {
 	log := logger.WithHostnameAndIP(req.Hostname, req.Ip)
 	log.Debugf("list seed peers, version %s, commit %s", req.Version, req.Commit)
@@ -534,7 +534,7 @@ func (s *managerServerV2) createScheduler(ctx context.Context, req *managerv2.Up
 	}, nil
 }
 
-// List acitve schedulers configuration.
+// List active schedulers configuration.
 func (s *managerServerV2) ListSchedulers(ctx context.Context, req *managerv2.ListSchedulersRequest) (*managerv2.ListSchedulersResponse, error) {
 	log := logger.WithHostnameAndIP(req.Hostname, req.Ip)
 	log.Debugf("list schedulers, version %s, commit %s", req.Version, req.Commit)
@@ -557,7 +557,7 @@ func (s *managerServerV2) ListSchedulers(ctx context.Context, req *managerv2.Lis
 		return nil, status.Error(codes.Internal, err.Error())
 	}
 
-	// Remove schedulers which not have scehdule featrue. As OceanBase does not support JSON type,
+	// Remove schedulers which not have schedule feature. As OceanBase does not support JSON type,
 	// it is not possible to use datatypes.JSONQuery for filtering.
 	var tmpSchedulerClusters []models.SchedulerCluster
 	for _, schedulerCluster := range schedulerClusters {
diff --git a/manager/service/job.go b/manager/service/job.go
index f2836a05..a0f76deb 100644
--- a/manager/service/job.go
+++ b/manager/service/job.go
@@ -37,11 +37,87 @@ func (s *service) CreatePreheatJob(ctx context.Context, json types.CreatePreheat
 		return nil, err
 	}
 
-	if json.Args.PieceLength == 0 {
-		json.Args.PieceLength = types.DefaultPreheatJobPieceLength
+	groupJobState, err := s.job.CreatePreheat(ctx, candidateSchedulers, json.Args)
+	if err != nil {
+		return nil, err
 	}
 
-	groupJobState, err := s.job.CreatePreheat(ctx, candidateSchedulers, json.Args)
+	var candidateSchedulerClusters []models.SchedulerCluster
+	for _, candidateScheduler := range candidateSchedulers {
+		candidateSchedulerClusters = append(candidateSchedulerClusters, candidateScheduler.SchedulerCluster)
+	}
+
+	args, err := structure.StructToMap(json.Args)
+	if err != nil {
+		return nil, err
+	}
+
+	job := models.Job{
+		TaskID:            groupJobState.GroupUUID,
+		BIO:               json.BIO,
+		Type:              json.Type,
+		State:             groupJobState.State,
+		Args:              args,
+		UserID:            json.UserID,
+		SchedulerClusters: candidateSchedulerClusters,
+	}
+
+	if err := s.db.WithContext(ctx).Create(&job).Error; err != nil {
+		return nil, err
+	}
+
+	go s.pollingJob(context.Background(), job.ID, job.TaskID)
+
+	return &job, nil
+}
+
+func (s *service) CreateDeleteTaskJob(ctx context.Context, json types.CreateDeleteTaskJobRequest) (*models.Job, error) {
+	candidateSchedulers, err := s.findCandidateSchedulers(ctx, json.SchedulerClusterIDs)
+	if err != nil {
+		return nil, err
+	}
+
+	groupJobState, err := s.job.CreateDeleteTask(ctx, candidateSchedulers, json.Args)
+	if err != nil {
+		return nil, err
+	}
+
+	var candidateSchedulerClusters []models.SchedulerCluster
+	for _, candidateScheduler := range candidateSchedulers {
+		candidateSchedulerClusters = append(candidateSchedulerClusters, candidateScheduler.SchedulerCluster)
+	}
+
+	args, err := structure.StructToMap(json.Args)
+	if err != nil {
+		return nil, err
+	}
+
+	job := models.Job{
+		TaskID:            groupJobState.GroupUUID,
+		BIO:               json.BIO,
+		Type:              json.Type,
+		State:             groupJobState.State,
+		Args:              args,
+		UserID:            json.UserID,
+		SchedulerClusters: candidateSchedulerClusters,
+	}
+
+	if err := s.db.WithContext(ctx).Create(&job).Error; err != nil {
+		return nil, err
+	}
+
+	go s.pollingJob(context.Background(), job.ID, job.TaskID)
+
+	return &job, nil
+}
+
+func (s *service) CreateGetTaskJob(ctx context.Context, json types.CreateGetTaskJobRequest) (*models.Job, error) {
+	candidateSchedulers, err := s.findCandidateSchedulers(ctx, json.SchedulerClusterIDs)
+	if err != nil {
+		return nil, err
+	}
+
+	groupJobState, err := s.job.CreateGetTask(ctx, candidateSchedulers, json.Args)
 	if err != nil {
 		return nil, err
 	}
diff --git a/manager/service/mocks/service_mock.go b/manager/service/mocks/service_mock.go
index 77eba9d9..1303453f 100644
--- a/manager/service/mocks/service_mock.go
+++ b/manager/service/mocks/service_mock.go
@@ -175,6 +175,36 @@ func (mr *MockServiceMockRecorder) CreateConfig(arg0, arg1 any) *gomock.Call {
 	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateConfig", reflect.TypeOf((*MockService)(nil).CreateConfig), arg0, arg1)
 }
 
+// CreateDeleteTaskJob mocks base method.
+func (m *MockService) CreateDeleteTaskJob(arg0 context.Context, arg1 types.CreateDeleteTaskJobRequest) (*models.Job, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CreateDeleteTaskJob", arg0, arg1)
+	ret0, _ := ret[0].(*models.Job)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// CreateDeleteTaskJob indicates an expected call of CreateDeleteTaskJob.
+func (mr *MockServiceMockRecorder) CreateDeleteTaskJob(arg0, arg1 any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateDeleteTaskJob", reflect.TypeOf((*MockService)(nil).CreateDeleteTaskJob), arg0, arg1)
+}
+
+// CreateGetTaskJob mocks base method.
+func (m *MockService) CreateGetTaskJob(arg0 context.Context, arg1 types.CreateGetTaskJobRequest) (*models.Job, error) {
+	m.ctrl.T.Helper()
+	ret := m.ctrl.Call(m, "CreateGetTaskJob", arg0, arg1)
+	ret0, _ := ret[0].(*models.Job)
+	ret1, _ := ret[1].(error)
+	return ret0, ret1
+}
+
+// CreateGetTaskJob indicates an expected call of CreateGetTaskJob.
+func (mr *MockServiceMockRecorder) CreateGetTaskJob(arg0, arg1 any) *gomock.Call {
+	mr.mock.ctrl.T.Helper()
+	return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "CreateGetTaskJob", reflect.TypeOf((*MockService)(nil).CreateGetTaskJob), arg0, arg1)
+}
+
 // CreateOauth mocks base method.
 func (m *MockService) CreateOauth(arg0 context.Context, arg1 types.CreateOauthRequest) (*models.Oauth, error) {
 	m.ctrl.T.Helper()
diff --git a/manager/service/preheat.go b/manager/service/preheat.go
index cb4345a9..83f43ced 100644
--- a/manager/service/preheat.go
+++ b/manager/service/preheat.go
@@ -51,7 +51,6 @@ func (s *service) CreateV1Preheat(ctx context.Context, json types.CreateV1Prehea
 			Type:                json.Type,
 			URL:                 json.URL,
 			FilteredQueryParams: json.FilteredQueryParams,
-			PieceLength:         types.DefaultPreheatJobPieceLength,
 			Headers:             json.Headers,
 		},
 	})
diff --git a/manager/service/service.go b/manager/service/service.go
index bde2c0c8..fcbf6d63 100644
--- a/manager/service/service.go
+++ b/manager/service/service.go
@@ -114,6 +114,8 @@ type Service interface {
 	GetConfigs(context.Context, types.GetConfigsQuery) ([]models.Config, int64, error)
 
 	CreatePreheatJob(context.Context, types.CreatePreheatJobRequest) (*models.Job, error)
+	CreateDeleteTaskJob(context.Context, types.CreateDeleteTaskJobRequest) (*models.Job, error)
+	CreateGetTaskJob(context.Context, types.CreateGetTaskJobRequest) (*models.Job, error)
 	DestroyJob(context.Context, uint) error
 	UpdateJob(context.Context, uint, types.UpdateJobRequest) (*models.Job, error)
 	GetJob(context.Context, uint) (*models.Job, error)
@@ -150,7 +152,7 @@ type service struct {
 	objectStorage objectstorage.ObjectStorage
 }
 
-// NewREST returns a new REST instence
+// NewREST returns a new REST instance
 func New(cfg *config.Config, database *database.Database, cache *cache.Cache, job *job.Job, enforcer *casbin.Enforcer, objectStorage objectstorage.ObjectStorage) Service {
 	return &service{
 		config:        cfg,
diff --git a/manager/types/job.go b/manager/types/job.go
index 4d3a286c..7b436f66 100644
--- a/manager/types/job.go
+++ b/manager/types/job.go
@@ -16,11 +16,6 @@
 
 package types
 
-const (
-	// DefaultPreheatJobPieceLength is the default piece length for preheating.
-	DefaultPreheatJobPieceLength = 4 * 1024 * 1024
-)
-
 type CreateJobRequest struct {
 	BIO                 string         `json:"bio" binding:"omitempty"`
 	Type                string         `json:"type" binding:"required"`
@@ -68,10 +63,7 @@ type PreheatArgs struct {
 	Tag string `json:"tag" binding:"omitempty"`
 
 	// FilteredQueryParams is the filtered query params for preheating.
-	FilteredQueryParams string `json:"filteredQueryParams" binding:"omitempty"`
-
-	// PieceLength is the piece length for preheating.
-	PieceLength uint32 `json:"pieceLength" binding:"omitempty"`
+	FilteredQueryParams string `json:"filtered_query_params" binding:"omitempty"`
 
 	// Headers is the http headers for authentication.
 	Headers map[string]string `json:"headers" binding:"omitempty"`
@@ -85,3 +77,29 @@ type PreheatArgs struct {
 	// The image type preheating task can specify the image architecture type. eg: linux/amd64.
 	Platform string `json:"platform" binding:"omitempty"`
 }
+
+type CreateGetTaskJobRequest struct {
+	BIO                 string         `json:"bio" binding:"omitempty"`
+	Type                string         `json:"type" binding:"required"`
+	Args                GetTaskArgs    `json:"args" binding:"omitempty"`
+	Result              map[string]any `json:"result" binding:"omitempty"`
+	UserID              uint           `json:"user_id" binding:"omitempty"`
+	SchedulerClusterIDs []uint         `json:"scheduler_cluster_ids" binding:"omitempty"`
+}
+
+type GetTaskArgs struct {
+	TaskID string `json:"task_id" binding:"required"`
+}
+
+type CreateDeleteTaskJobRequest struct {
+	BIO                 string         `json:"bio" binding:"omitempty"`
+	Type                string         `json:"type" binding:"required"`
+	Args                DeleteTaskArgs `json:"args" binding:"omitempty"`
+	Result              map[string]any `json:"result" binding:"omitempty"`
+	UserID              uint           `json:"user_id" binding:"omitempty"`
+	SchedulerClusterIDs []uint         `json:"scheduler_cluster_ids" binding:"omitempty"`
+}
+
+type DeleteTaskArgs struct {
+	TaskID string `json:"task_id" binding:"required"`
+}
diff --git a/pkg/gc/gc.go b/pkg/gc/gc.go
index 11eed399..a3d0f4b2 100644
--- a/pkg/gc/gc.go
+++ b/pkg/gc/gc.go
@@ -59,7 +59,7 @@ func WithLogger(logger Logger) Option {
 	}
 }
 
-// New returns a new GC instence.
+// New returns a new GC instance.
 func New(options ...Option) GC {
 	g := &gc{
 		tasks:  &sync.Map{},
diff --git a/pkg/idgen/task_id.go b/pkg/idgen/task_id.go
index 2c03e371..993e6fe3 100644
--- a/pkg/idgen/task_id.go
+++ b/pkg/idgen/task_id.go
@@ -17,7 +17,6 @@
 package idgen
 
 import (
-	"fmt"
 	"strings"
 
 	commonv1 "d7y.io/api/v2/pkg/apis/common/v1"
@@ -92,11 +91,11 @@ func parseFilteredQueryParams(rawFilteredQueryParams string) []string {
 }
 
 // TaskIDV2 generates v2 version of task id.
-func TaskIDV2(url, digest, tag, application string, pieceLength int32, filteredQueryParams []string) string {
+func TaskIDV2(url, digest, tag, application string, filteredQueryParams []string) string {
 	url, err := neturl.FilterQueryParams(url, filteredQueryParams)
 	if err != nil {
 		url = ""
 	}
 
-	return pkgdigest.SHA256FromStrings(url, digest, tag, application, fmt.Sprint(pieceLength))
+	return pkgdigest.SHA256FromStrings(url, digest, tag, application)
 }
diff --git a/pkg/issuer/dragonfly.go b/pkg/issuer/dragonfly.go
index e33bb01d..56e41a9d 100644
--- a/pkg/issuer/dragonfly.go
+++ b/pkg/issuer/dragonfly.go
@@ -58,7 +58,7 @@ func WithValidityPeriod(d time.Duration) Option {
 	}
 }
 
-// NewDragonflyIssuer returns a new certify.Issuer instence.
+// NewDragonflyIssuer returns a new certify.Issuer instance.
 func NewDragonflyIssuer(securityClient securityclient.V1, opts ...Option) certify.Issuer {
 	i := &dragonflyIssuer{
 		securityClient: securityClient,
diff --git a/pkg/issuer/dragonfly_manager.go b/pkg/issuer/dragonfly_manager.go
index f11ef6be..66db9fc7 100644
--- a/pkg/issuer/dragonfly_manager.go
+++ b/pkg/issuer/dragonfly_manager.go
@@ -52,7 +52,7 @@ func WithManagerValidityPeriod(d time.Duration) ManagerOption {
 	}
 }
 
-// NewDragonflyManagerIssuer returns a new certify.Issuer instence.
+// NewDragonflyManagerIssuer returns a new certify.Issuer instance.
 func NewDragonflyManagerIssuer(tlsCACert *tls.Certificate, opts ...ManagerOption) certify.Issuer {
 	i := &dragonflyManagerIssuer{
 		tlsCACert:      tlsCACert,
diff --git a/pkg/rpc/dfdaemon/client/client_v2.go b/pkg/rpc/dfdaemon/client/client_v2.go
index f4c0c136..a92f1ea4 100644
--- a/pkg/rpc/dfdaemon/client/client_v2.go
+++ b/pkg/rpc/dfdaemon/client/client_v2.go
@@ -83,6 +83,41 @@ func GetV2(ctx context.Context, dynconfig config.DynconfigInterface, opts ...grp
 	}, nil
 }
 
+// GetV2ByAddr returns v2 version of the dfdaemon client by address.
+func GetV2ByAddr(ctx context.Context, target string, opts ...grpc.DialOption) (V2, error) {
+	conn, err := grpc.DialContext(
+		ctx,
+		target,
+		append([]grpc.DialOption{
+			grpc.WithIdleTimeout(0),
+			grpc.WithDefaultCallOptions(
+				grpc.MaxCallRecvMsgSize(math.MaxInt32),
+				grpc.MaxCallSendMsgSize(math.MaxInt32),
+			),
+			grpc.WithUnaryInterceptor(grpc_middleware.ChainUnaryClient(
+				grpc_prometheus.UnaryClientInterceptor,
+				grpc_zap.UnaryClientInterceptor(logger.GrpcLogger.Desugar()),
+				grpc_retry.UnaryClientInterceptor(
+					grpc_retry.WithMax(maxRetries),
+					grpc_retry.WithBackoff(grpc_retry.BackoffLinear(backoffWaitBetween)),
+				),
+			)),
+			grpc.WithStreamInterceptor(grpc_middleware.ChainStreamClient(
+				grpc_prometheus.StreamClientInterceptor,
+				grpc_zap.StreamClientInterceptor(logger.GrpcLogger.Desugar()),
+			)),
+		}, opts...)...,
+	)
+	if err != nil {
+		return nil, err
+	}
+
+	return &v2{
+		DfdaemonUploadClient: dfdaemonv2.NewDfdaemonUploadClient(conn),
+		ClientConn:           conn,
+	}, nil
+}
+
 // V2 is the interface for v2 version of the grpc client.
 type V2 interface {
 	// SyncPieces syncs pieces from the other peers.
diff --git a/pkg/rpc/manager/client/client_v1.go b/pkg/rpc/manager/client/client_v1.go
index 18f65b21..30d064b1 100644
--- a/pkg/rpc/manager/client/client_v1.go
+++ b/pkg/rpc/manager/client/client_v1.go
@@ -103,7 +103,7 @@ type V1 interface {
 	// Update scheduler configuration.
 	UpdateScheduler(context.Context, *managerv1.UpdateSchedulerRequest, ...grpc.CallOption) (*managerv1.Scheduler, error)
 
-	// List acitve schedulers configuration.
+	// List active schedulers configuration.
 	ListSchedulers(context.Context, *managerv1.ListSchedulersRequest, ...grpc.CallOption) (*managerv1.ListSchedulersResponse, error)
 
 	// Get object storage configuration.
@@ -132,7 +132,7 @@ type v1 struct {
 	*grpc.ClientConn
 }
 
-// List acitve seed peers configuration.
+// List active seed peers configuration.
 func (v *v1) ListSeedPeers(ctx context.Context, req *managerv1.ListSeedPeersRequest, opts ...grpc.CallOption) (*managerv1.ListSeedPeersResponse, error) {
 	ctx, cancel := context.WithTimeout(ctx, contextTimeout)
 	defer cancel()
@@ -164,7 +164,7 @@ func (v *v1) UpdateScheduler(ctx context.Context, req *managerv1.UpdateScheduler
 	return v.ManagerClient.UpdateScheduler(ctx, req, opts...)
 }
 
-// List acitve schedulers configuration.
+// List active schedulers configuration.
 func (v *v1) ListSchedulers(ctx context.Context, req *managerv1.ListSchedulersRequest, opts ...grpc.CallOption) (*managerv1.ListSchedulersResponse, error) {
 	ctx, cancel := context.WithTimeout(ctx, contextTimeout)
 	defer cancel()
@@ -205,7 +205,7 @@ func (v *v1) CreateModel(ctx context.Context, req *managerv1.CreateModelRequest,
 	return err
 }
 
-// List acitve schedulers configuration.
+// List active schedulers configuration.
 func (v *v1) KeepAlive(interval time.Duration, keepalive *managerv1.KeepAliveRequest, done <-chan struct{}, opts ...grpc.CallOption) {
 	log := logger.WithKeepAlive(keepalive.Hostname, keepalive.Ip, keepalive.SourceType.Enum().String(), keepalive.ClusterId)
 retry:
diff --git a/pkg/rpc/manager/client/client_v2.go b/pkg/rpc/manager/client/client_v2.go
index 4d9c12c5..67e82f5a 100644
--- a/pkg/rpc/manager/client/client_v2.go
+++ b/pkg/rpc/manager/client/client_v2.go
@@ -106,7 +106,7 @@ type V2 interface {
 	// Update scheduler configuration.
 	UpdateScheduler(context.Context, *managerv2.UpdateSchedulerRequest, ...grpc.CallOption) (*managerv2.Scheduler, error)
 
-	// List acitve schedulers configuration.
+	// List active schedulers configuration.
 	ListSchedulers(context.Context, *managerv2.ListSchedulersRequest, ...grpc.CallOption) (*managerv2.ListSchedulersResponse, error)
 
 	// List applications configuration.
@@ -126,7 +126,7 @@ type v2 struct {
 	*grpc.ClientConn
 }
 
-// List acitve seed peers configuration.
+// List active seed peers configuration.
 func (v *v2) ListSeedPeers(ctx context.Context, req *managerv2.ListSeedPeersRequest, opts ...grpc.CallOption) (*managerv2.ListSeedPeersResponse, error) {
 	ctx, cancel := context.WithTimeout(ctx, contextTimeout)
 	defer cancel()
@@ -167,7 +167,7 @@ func (v *v2) UpdateScheduler(ctx context.Context, req *managerv2.UpdateScheduler
 	return v.ManagerClient.UpdateScheduler(ctx, req, opts...)
 }
 
-// List acitve schedulers configuration.
+// List active schedulers configuration.
 func (v *v2) ListSchedulers(ctx context.Context, req *managerv2.ListSchedulersRequest, opts ...grpc.CallOption) (*managerv2.ListSchedulersResponse, error) {
 	ctx, cancel := context.WithTimeout(ctx, contextTimeout)
 	defer cancel()
@@ -183,7 +183,7 @@ func (v *v2) ListApplications(ctx context.Context, req *managerv2.ListApplicatio
 	return v.ManagerClient.ListApplications(ctx, req, opts...)
 }
 
-// List acitve schedulers configuration.
+// List active schedulers configuration.
 func (v *v2) KeepAlive(interval time.Duration, keepalive *managerv2.KeepAliveRequest, done <-chan struct{}, opts ...grpc.CallOption) {
 	log := logger.WithKeepAlive(keepalive.Hostname, keepalive.Ip, keepalive.SourceType.Enum().String(), keepalive.ClusterId)
 retry:
diff --git a/pkg/source/clients/httpprotocol/header.go b/pkg/source/clients/httpprotocol/header.go
index 97215760..ca9d218e 100644
--- a/pkg/source/clients/httpprotocol/header.go
+++ b/pkg/source/clients/httpprotocol/header.go
@@ -27,6 +27,7 @@ var PassThroughHeaders = map[string]struct{}{
 
 	headers.Authorization:   {},
 	headers.ContentType:     {},
+	headers.ContentRange:    {},
 	headers.ContentEncoding: {},
 	headers.WWWAuthenticate: {},
 }
diff --git a/pkg/source/response.go b/pkg/source/response.go
index a521a893..243ca1a6 100644
--- a/pkg/source/response.go
+++ b/pkg/source/response.go
@@ -37,7 +37,7 @@ type Response struct {
 	// Validate this response is okay to transfer in p2p network, like status 200 or 206 in http is valid to do this,
 	// otherwise return status code to original client
 	Validate func() error
-	// Temporary indecates the error whether the error is temporary, if is true, we can retry it later
+	// Temporary indicates the error whether the error is temporary, if is true, we can retry it later
 	Temporary bool
 }
 
diff --git a/pkg/types/constants.go b/pkg/types/constants.go
index f8272b9b..1f79bc74 100644
--- a/pkg/types/constants.go
+++ b/pkg/types/constants.go
@@ -49,7 +49,7 @@ const (
 	// ManagerMetricsName is name of manager metrics.
 	ManagerMetricsName = "manager"
 
-	// SchedulerMetricsName is name of scheduelr metrics.
+	// SchedulerMetricsName is name of Scheduler metrics.
 	SchedulerMetricsName = "scheduler"
 
 	// DfdaemonMetricsName is name of dfdaemon metrics.
diff --git a/scheduler/config/dynconfig.go b/scheduler/config/dynconfig.go
index 544b0426..63fcbf63 100644
--- a/scheduler/config/dynconfig.go
+++ b/scheduler/config/dynconfig.go
@@ -133,7 +133,7 @@ func WithTransportCredentials(creds credentials.TransportCredentials) DynconfigO
 	}
 }
 
-// NewDynconfig returns a new dynconfig instence.
+// NewDynconfig returns a new dynconfig instance.
 func NewDynconfig(rawManagerClient managerclient.V2, cacheDir string, cfg *Config, options ...DynconfigOption) (DynconfigInterface, error) {
 	cachePath := filepath.Join(cacheDir, cacheFileName)
 	d := &dynconfig{
diff --git a/scheduler/job/job.go b/scheduler/job/job.go
index e497cfdb..a0305262 100644
--- a/scheduler/job/job.go
+++ b/scheduler/job/job.go
@@ -39,6 +39,7 @@ import (
 	logger "d7y.io/dragonfly/v2/internal/dflog"
 	internaljob "d7y.io/dragonfly/v2/internal/job"
 	"d7y.io/dragonfly/v2/pkg/idgen"
+	dfdaemonclient "d7y.io/dragonfly/v2/pkg/rpc/dfdaemon/client"
 	"d7y.io/dragonfly/v2/scheduler/config"
 	"d7y.io/dragonfly/v2/scheduler/resource"
 )
@@ -46,6 +47,9 @@ import (
 const (
 	// preheatTimeout is timeout of preheating.
 	preheatTimeout = 20 * time.Minute
+
+	// deleteTaskTimeout is timeout of deleting task.
+	deleteTaskTimeout = 20 * time.Minute
 )
 
 // Job is an interface for job.
@@ -109,8 +113,10 @@ func New(cfg *config.Config, resource resource.Resource) (Job, error) {
 	}
 
 	namedJobFuncs := map[string]any{
-		internaljob.PreheatJob:   t.preheat,
-		internaljob.SyncPeersJob: t.syncPeers,
+		internaljob.PreheatJob:    t.preheat,
+		internaljob.SyncPeersJob:  t.syncPeers,
+		internaljob.GetTaskJob:    t.getTask,
+		internaljob.DeleteTaskJob: t.deleteTask,
 	}
 
 	if err := localJob.RegisterJob(namedJobFuncs); err != nil {
@@ -243,7 +249,7 @@ func (j *job) preheatV1(ctx context.Context, req *internaljob.PreheatRequest) er
 // preheatV2 preheats job by v2 grpc protocol.
 func (j *job) preheatV2(ctx context.Context, req *internaljob.PreheatRequest) error {
 	filteredQueryParams := strings.Split(req.FilteredQueryParams, idgen.FilteredQueryParamsSeparator)
-	taskID := idgen.TaskIDV2(req.URL, req.Digest, req.Tag, req.Application, int32(req.PieceLength), filteredQueryParams)
+	taskID := idgen.TaskIDV2(req.URL, req.Digest, req.Tag, req.Application, filteredQueryParams)
 
 	log := logger.WithTask(taskID, req.URL)
 	log.Infof("preheat(v2) %s tag: %s, filtered query params: %s, digest: %s, headers: %#v",
@@ -259,7 +265,6 @@ func (j *job) preheatV2(ctx context.Context, req *internaljob.PreheatRequest) er
 			Priority:            commonv2.Priority(req.Priority),
 			FilteredQueryParams: filteredQueryParams,
 			RequestHeader:       req.Headers,
-			PieceLength:         uint64(req.PieceLength),
 		}})
 	if err != nil {
 		logger.Errorf("preheat(v2) %s failed: %s", req.URL, err.Error())
@@ -297,3 +302,92 @@ func (j *job) syncPeers() (string, error) {
 
 	return internaljob.MarshalResponse(hosts)
 }
+
+// getTask is a job to get task.
+func (j *job) getTask(ctx context.Context, data string) (string, error) {
+	req := &internaljob.GetTaskRequest{}
+	if err := internaljob.UnmarshalRequest(data, req); err != nil {
+		logger.Errorf("unmarshal request err: %s, request body: %s", err.Error(), data)
+		return "", err
+	}
+
+	if err := validator.New().Struct(req); err != nil {
+		logger.Errorf("getTask %s validate failed: %s", req.TaskID, err.Error())
+		return "", err
+	}
+
+	task, ok := j.resource.TaskManager().Load(req.TaskID)
+	if !ok {
+		logger.Errorf("task %s not found", req.TaskID)
+		return "", fmt.Errorf("task %s not found", req.TaskID)
+	}
+
+	return internaljob.MarshalResponse(&internaljob.GetTaskResponse{
+		Peers: task.LoadPeers(),
+	})
+}
+
+// deleteTask is a job to delete task.
+func (j *job) deleteTask(ctx context.Context, data string) (string, error) {
+	ctx, cancel := context.WithTimeout(ctx, deleteTaskTimeout)
+	defer cancel()
+
+	req := &internaljob.DeleteTaskRequest{}
+	if err := internaljob.UnmarshalRequest(data, req); err != nil {
+		logger.Errorf("unmarshal request err: %s, request body: %s", err.Error(), data)
+		return "", err
+	}
+
+	if err := validator.New().Struct(req); err != nil {
+		logger.Errorf("deleteTask %s validate failed: %s", req.TaskID, err.Error())
+		return "", err
+	}
+
+	task, ok := j.resource.TaskManager().Load(req.TaskID)
+	if !ok {
+		logger.Errorf("task %s not found", req.TaskID)
+		return "", fmt.Errorf("task %s not found", req.TaskID)
+	}
+
+	successPeers := []*internaljob.DeletePeerResponse{}
+	failurePeers := []*internaljob.DeletePeerResponse{}
+
+	finishedPeers := task.LoadFinishedPeers()
+	for _, finishedPeer := range finishedPeers {
+		log := logger.WithPeer(finishedPeer.Host.ID, finishedPeer.Task.ID, finishedPeer.ID)
+
+		addr := fmt.Sprintf("%s:%d", finishedPeer.Host.IP, finishedPeer.Host.Port)
+		dfdaemonClient, err := dfdaemonclient.GetV2ByAddr(ctx, addr)
+		if err != nil {
+			log.Errorf("get client from %s failed: %s", addr, err.Error())
+			failurePeers = append(failurePeers, &internaljob.DeletePeerResponse{
+				Peer:        finishedPeer,
+				Description: err.Error(),
+			})
+
+			continue
+		}
+
+		if err = dfdaemonClient.DeleteCacheTask(ctx, &dfdaemonv2.DeleteCacheTaskRequest{
+			TaskId: req.TaskID,
+		}); err != nil {
+			logger.Errorf("delete task failed: %s", err.Error())
+			failurePeers = append(failurePeers, &internaljob.DeletePeerResponse{
+				Peer:        finishedPeer,
+				Description: err.Error(),
+			})
+
+			continue
+		}
+
+		successPeers = append(successPeers, &internaljob.DeletePeerResponse{
+			Peer:        finishedPeer,
+			Description: "",
+		})
+	}
+
+	return internaljob.MarshalResponse(&internaljob.DeleteTaskResponse{
+		FailurePeers: failurePeers,
+		SuccessPeers: successPeers,
+	})
+}
diff --git a/scheduler/metrics/metrics.go b/scheduler/metrics/metrics.go
index 602f63de..08cd9fb4 100644
--- a/scheduler/metrics/metrics.go
+++ b/scheduler/metrics/metrics.go
@@ -101,84 +101,84 @@ var (
 		Subsystem: types.SchedulerMetricsName,
 		Name:      "register_peer_total",
 		Help:      "Counter of the number of the register peer.",
-	}, []string{"priority", "task_type", "task_tag", "task_app", "host_type"})
+	}, []string{"priority", "task_type", "host_type"})
 
 	RegisterPeerFailureCount = promauto.NewCounterVec(prometheus.CounterOpts{
 		Namespace: types.MetricsNamespace,
 		Subsystem: types.SchedulerMetricsName,
 		Name:      "register_peer_failure_total",
 		Help:      "Counter of the number of failed of the register peer.",
-	}, []string{"priority", "task_type", "task_tag", "task_app", "host_type"})
+	}, []string{"priority", "task_type", "host_type"})
 
 	DownloadPeerStartedCount = promauto.NewCounterVec(prometheus.CounterOpts{
 		Namespace: types.MetricsNamespace,
 		Subsystem: types.SchedulerMetricsName,
 		Name:      "download_peer_started_total",
 		Help:      "Counter of the number of the download peer started.",
-	}, []string{"priority", "task_type", "task_tag", "task_app", "host_type"})
+	}, []string{"priority", "task_type", "host_type"})
 
 	DownloadPeerStartedFailureCount = promauto.NewCounterVec(prometheus.CounterOpts{
 		Namespace: types.MetricsNamespace,
 		Subsystem: types.SchedulerMetricsName,
 		Name:      "download_peer_started_failure_total",
 		Help:      "Counter of the number of failed of the download peer started.",
-	}, []string{"priority", "task_type", "task_tag", "task_app", "host_type"})
+	}, []string{"priority", "task_type", "host_type"})
 
 	DownloadPeerBackToSourceStartedCount = promauto.NewCounterVec(prometheus.CounterOpts{
 		Namespace: types.MetricsNamespace,
 		Subsystem: types.SchedulerMetricsName,
 		Name:      "download_peer_back_to_source_started_total",
 		Help:      "Counter of the number of the download peer back-to-source started.",
-	}, []string{"priority", "task_type", "task_tag", "task_app", "host_type"})
+	}, []string{"priority", "task_type", "host_type"})
 
 	DownloadPeerBackToSourceStartedFailureCount = promauto.NewCounterVec(prometheus.CounterOpts{
 		Namespace: types.MetricsNamespace,
 		Subsystem: types.SchedulerMetricsName,
 		Name:      "download_peer_back_to_source_started_failure_total",
 		Help:      "Counter of the number of failed of the download peer back-to-source started.",
-	}, []string{"priority", "task_type", "task_tag", "task_app", "host_type"})
+	}, []string{"priority", "task_type", "host_type"})
 
 	DownloadPeerCount = promauto.NewCounterVec(prometheus.CounterOpts{
 		Namespace: types.MetricsNamespace,
 		Subsystem: types.SchedulerMetricsName,
 		Name:      "download_peer_finished_total",
 		Help:      "Counter of the number of the download peer.",
-	}, []string{"priority", "task_type", "task_tag", "task_app", "host_type"})
+	}, []string{"priority", "task_type", "host_type"})
 
 	DownloadPeerFailureCount = promauto.NewCounterVec(prometheus.CounterOpts{
 		Namespace: types.MetricsNamespace,
 		Subsystem: types.SchedulerMetricsName,
 		Name:      "download_peer_finished_failure_total",
 		Help:      "Counter of the number of failed of the download peer.",
-	}, []string{"priority", "task_type", "task_tag", "task_app", "host_type"})
+	}, []string{"priority", "task_type", "host_type"})
 
 	DownloadPeerBackToSourceFailureCount = promauto.NewCounterVec(prometheus.CounterOpts{
 		Namespace: types.MetricsNamespace,
 		Subsystem: types.SchedulerMetricsName,
 		Name:      "download_peer_back_to_source_finished_failure_total",
 		Help:      "Counter of the number of failed of the download peer back-to-source.",
-	}, []string{"priority", "task_type", "task_tag", "task_app", "host_type"})
+	}, []string{"priority", "task_type", "host_type"})
 
 	DownloadPieceCount = promauto.NewCounterVec(prometheus.CounterOpts{
 		Namespace: types.MetricsNamespace,
 		Subsystem: types.SchedulerMetricsName,
 		Name:      "download_piece_finished_total",
 		Help:      "Counter of the number of the download piece.",
-	}, []string{"traffic_type", "task_type", "task_tag", "task_app", "host_type"})
+	}, []string{"traffic_type", "task_type", "host_type"})
 
 	DownloadPieceFailureCount = promauto.NewCounterVec(prometheus.CounterOpts{
 		Namespace: types.MetricsNamespace,
 		Subsystem: types.SchedulerMetricsName,
 		Name:      "download_piece_finished_failure_total",
 		Help:      "Counter of the number of failed of the download piece.",
-	}, []string{"traffic_type", "task_type", "task_tag", "task_app", "host_type"})
+	}, []string{"traffic_type", "task_type", "host_type"})
 
 	DownloadPieceBackToSourceFailureCount = promauto.NewCounterVec(prometheus.CounterOpts{
 		Namespace: types.MetricsNamespace,
 		Subsystem: types.SchedulerMetricsName,
 		Name:      "download_piece_back_to_source_finished_failure_total",
 		Help:      "Counter of the number of failed of the download piece back-to-source.",
-	}, []string{"traffic_type", "task_type", "task_tag", "task_app", "host_type"})
+	}, []string{"traffic_type", "task_type", "host_type"})
 
 	StatTaskCount = promauto.NewCounter(prometheus.CounterOpts{
 		Namespace: types.MetricsNamespace,
@@ -257,14 +257,14 @@ var (
 		Subsystem: types.SchedulerMetricsName,
 		Name:      "traffic",
 		Help:      "Counter of the number of traffic.",
-	}, []string{"type", "task_type", "task_tag", "task_app", "host_type"})
+	}, []string{"type", "task_type", "host_type"})
 
 	HostTraffic = promauto.NewCounterVec(prometheus.CounterOpts{
 		Namespace: types.MetricsNamespace,
 		Subsystem: types.SchedulerMetricsName,
 		Name:      "host_traffic",
 		Help:      "Counter of the number of per host traffic.",
-	}, []string{"type", "task_type", "task_tag", "task_app", "host_type", "host_id", "host_ip", "host_name"})
+	}, []string{"type", "task_type", "host_type", "host_id", "host_ip", "host_name"})
 
 	DownloadPeerDuration = promauto.NewSummaryVec(prometheus.SummaryOpts{
 		Namespace:  types.MetricsNamespace,
@@ -281,6 +281,14 @@ var (
 		Help:      "Gauge of the number of concurrent of the scheduling.",
 	})
 
+	ScheduleDuration = promauto.NewSummary(prometheus.SummaryOpts{
+		Namespace:  types.MetricsNamespace,
+		Subsystem:  types.SchedulerMetricsName,
+		Name:       "schedule_duration_milliseconds",
+		Help:       "Summary of the time each scheduling.",
+		Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.95: 0.005, 0.99: 0.001},
+	})
+
 	VersionGauge = promauto.NewGaugeVec(prometheus.GaugeOpts{
 		Namespace: types.MetricsNamespace,
 		Subsystem: types.SchedulerMetricsName,
diff --git a/scheduler/resource/resource.go b/scheduler/resource/resource.go
index ff6f9fcd..5b253ecb 100644
--- a/scheduler/resource/resource.go
+++ b/scheduler/resource/resource.go
@@ -42,7 +42,7 @@ type Resource interface {
 	// Task manager interface.
 	TaskManager() TaskManager
 
-	// Stop resource serivce.
+	// Stop resource service.
 	Stop() error
 }
 
@@ -147,7 +147,7 @@ func (r *resource) TaskManager() TaskManager {
 	return r.taskManager
 }
 
-// Stop resource serivce.
+// Stop resource service.
 func (r *resource) Stop() error {
 	if r.config.SeedPeer.Enable {
 		return r.seedPeer.Stop()
diff --git a/scheduler/resource/seed_peer.go b/scheduler/resource/seed_peer.go
index 8b68d7b0..989310b2 100644
--- a/scheduler/resource/seed_peer.go
+++ b/scheduler/resource/seed_peer.go
@@ -59,7 +59,7 @@ type SeedPeer interface {
 	// Client returns grpc client of seed peer.
 	Client() SeedPeerClient
 
-	// Stop seed peer serivce.
+	// Stop seed peer service.
 	Stop() error
 }
 
@@ -213,7 +213,7 @@ func (s *seedPeer) TriggerTask(ctx context.Context, rg *http.Range, task *Task)
 				trafficType = commonv2.TrafficType_LOCAL_PEER
 			}
 			metrics.Traffic.WithLabelValues(trafficType.String(), peer.Task.Type.String(),
-				peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Add(float64(pieceSeed.PieceInfo.RangeSize))
+				peer.Host.Type.Name()).Add(float64(pieceSeed.PieceInfo.RangeSize))
 		}
 
 		// Handle end of piece.
@@ -266,7 +266,7 @@ func (s *seedPeer) Client() SeedPeerClient {
 	return s.client
 }
 
-// Stop seed peer serivce.
+// Stop seed peer service.
 func (s *seedPeer) Stop() error {
 	return s.client.Close()
 }
diff --git a/scheduler/resource/task.go b/scheduler/resource/task.go
index b5a3ac86..6a6e1e13 100644
--- a/scheduler/resource/task.go
+++ b/scheduler/resource/task.go
@@ -34,6 +34,7 @@ import (
 	"d7y.io/dragonfly/v2/pkg/container/set"
 	"d7y.io/dragonfly/v2/pkg/digest"
 	"d7y.io/dragonfly/v2/pkg/graph/dag"
+	pkgstrings "d7y.io/dragonfly/v2/pkg/strings"
 	"d7y.io/dragonfly/v2/pkg/types"
 )
 
@@ -249,6 +250,30 @@ func (t *Task) LoadRandomPeers(n uint) []*Peer {
 	return peers
 }
 
+// LoadPeers return all peers.
+func (t *Task) LoadPeers() []*Peer {
+	var peers []*Peer
+	for _, vertex := range t.DAG.GetVertices() {
+		peers = append(peers, vertex.Value)
+	}
+
+	return peers
+}
+
+// LoadFinishedPeers return finished peers.
+func (t *Task) LoadFinishedPeers() []*Peer {
+	var finishedPeers []*Peer
+	for _, vertex := range t.DAG.GetVertices() {
+		peer := vertex.Value
+		peerState := peer.FSM.Current()
+		if pkgstrings.Contains([]string{PeerStateSucceeded, PeerStateFailed, PeerStateLeave}, peerState) {
+			finishedPeers = append(finishedPeers, peer)
+		}
+	}
+
+	return finishedPeers
+}
+
 // StorePeer set peer.
 func (t *Task) StorePeer(peer *Peer) {
 	t.DAG.AddVertex(peer.ID, peer) // nolint: errcheck
diff --git a/scheduler/rpcserver/scheduler_server_v1.go b/scheduler/rpcserver/scheduler_server_v1.go
index 82568b57..61aa7843 100644
--- a/scheduler/rpcserver/scheduler_server_v1.go
+++ b/scheduler/rpcserver/scheduler_server_v1.go
@@ -55,23 +55,20 @@ func newSchedulerServerV1(
 
 // RegisterPeerTask registers peer and triggers seed peer download task.
 func (s *schedulerServerV1) RegisterPeerTask(ctx context.Context, req *schedulerv1.PeerTaskRequest) (*schedulerv1.RegisterResult, error) {
-	// FIXME Scheudler will not generate task id.
+	// FIXME Scheduler will not generate task id.
 	if req.TaskId == "" {
 		req.TaskId = idgen.TaskIDV1(req.Url, req.UrlMeta)
 	}
-
-	tag := req.UrlMeta.Tag
-	application := req.UrlMeta.Application
 	priority := req.UrlMeta.Priority
 
 	// Collect RegisterPeerCount metrics.
 	metrics.RegisterPeerCount.WithLabelValues(priority.String(), commonv1.TaskType_Normal.String(),
-		tag, application, types.HostTypeNormalName).Inc()
+		types.HostTypeNormalName).Inc()
 	resp, err := s.service.RegisterPeerTask(ctx, req)
 	if err != nil {
 		// Collect RegisterPeerFailureCount metrics.
 		metrics.RegisterPeerFailureCount.WithLabelValues(priority.String(), commonv1.TaskType_Normal.String(),
-			tag, application, types.HostTypeNormalName).Inc()
+			types.HostTypeNormalName).Inc()
 	}
 
 	return resp, err
diff --git a/scheduler/service/service_v1.go b/scheduler/service/service_v1.go
index 6fd7f94a..0fb16264 100644
--- a/scheduler/service/service_v1.go
+++ b/scheduler/service/service_v1.go
@@ -59,7 +59,7 @@ type V1 struct {
 	// Scheduling interface.
 	scheduling scheduling.Scheduling
 
-	// Scheduelr service config.
+	// Scheduler service config.
 	config *config.Config
 
 	// Dynamic config.
@@ -252,10 +252,10 @@ func (v *V1) ReportPieceResult(stream schedulerv1.Scheduler_ReportPieceResultSer
 
 			// Collect host traffic metrics.
 			if v.config.Metrics.Enable && v.config.Metrics.EnableHost {
-				metrics.HostTraffic.WithLabelValues(metrics.HostTrafficDownloadType, peer.Task.Type.String(), peer.Task.Tag, peer.Task.Application,
+				metrics.HostTraffic.WithLabelValues(metrics.HostTrafficDownloadType, peer.Task.Type.String(),
 					peer.Host.Type.Name(), peer.Host.ID, peer.Host.IP, peer.Host.Hostname).Add(float64(piece.PieceInfo.RangeSize))
 				if parent, loaded := v.resource.PeerManager().Load(piece.DstPid); loaded {
-					metrics.HostTraffic.WithLabelValues(metrics.HostTrafficUploadType, peer.Task.Type.String(), peer.Task.Tag, peer.Task.Application,
+					metrics.HostTraffic.WithLabelValues(metrics.HostTrafficUploadType, peer.Task.Type.String(),
 						parent.Host.Type.Name(), parent.Host.ID, parent.Host.IP, parent.Host.Hostname).Add(float64(piece.PieceInfo.RangeSize))
 				} else if !resource.IsPieceBackToSource(piece.DstPid) {
 					peer.Log.Warnf("dst peer %s not found", piece.DstPid)
@@ -265,10 +265,10 @@ func (v *V1) ReportPieceResult(stream schedulerv1.Scheduler_ReportPieceResultSer
 			// Collect traffic metrics.
 			if !resource.IsPieceBackToSource(piece.DstPid) {
 				metrics.Traffic.WithLabelValues(commonv2.TrafficType_REMOTE_PEER.String(), peer.Task.Type.String(),
-					peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Add(float64(piece.PieceInfo.RangeSize))
+					peer.Host.Type.Name()).Add(float64(piece.PieceInfo.RangeSize))
 			} else {
 				metrics.Traffic.WithLabelValues(commonv2.TrafficType_BACK_TO_SOURCE.String(), peer.Task.Type.String(),
-					peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Add(float64(piece.PieceInfo.RangeSize))
+					peer.Host.Type.Name()).Add(float64(piece.PieceInfo.RangeSize))
 			}
 			continue
 		}
@@ -305,7 +305,7 @@ func (v *V1) ReportPeerResult(ctx context.Context, req *schedulerv1.PeerResult)
 	// Collect DownloadPeerCount metrics.
 	priority := peer.CalculatePriority(v.dynconfig)
 	metrics.DownloadPeerCount.WithLabelValues(priority.String(), peer.Task.Type.String(),
-		peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+		peer.Host.Type.Name()).Inc()
 
 	parents := peer.Parents()
 	if !req.GetSuccess() {
@@ -313,7 +313,7 @@ func (v *V1) ReportPeerResult(ctx context.Context, req *schedulerv1.PeerResult)
 		if peer.FSM.Is(resource.PeerStateBackToSource) {
 			// Collect DownloadPeerBackToSourceFailureCount metrics.
 			metrics.DownloadPeerBackToSourceFailureCount.WithLabelValues(priority.String(), peer.Task.Type.String(),
-				peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+				peer.Host.Type.Name()).Inc()
 
 			go v.createDownloadRecord(peer, parents, req)
 			v.handleTaskFailure(ctx, peer.Task, req.GetSourceError(), nil)
@@ -323,7 +323,7 @@ func (v *V1) ReportPeerResult(ctx context.Context, req *schedulerv1.PeerResult)
 
 		// Collect DownloadPeerFailureCount metrics.
 		metrics.DownloadPeerFailureCount.WithLabelValues(priority.String(), peer.Task.Type.String(),
-			peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+			peer.Host.Type.Name()).Inc()
 
 		go v.createDownloadRecord(peer, parents, req)
 		v.handlePeerFailure(ctx, peer)
@@ -1035,12 +1035,17 @@ func (v *V1) registerTinyTask(ctx context.Context, peer *resource.Peer) (*schedu
 
 // registerSmallTask registers the small task.
 func (v *V1) registerSmallTask(ctx context.Context, peer *resource.Peer) (*schedulerv1.RegisterResult, error) {
+	// Record the start time.
+	start := time.Now()
 	candidateParents, found := v.scheduling.FindParentAndCandidateParents(ctx, peer, set.NewSafeSet[string]())
 	if !found {
 		return nil, errors.New("candidate parent not found")
 	}
 	candidateParent := candidateParents[0]
 
+	// Collect SchedulingDuration metrics.
+	metrics.ScheduleDuration.Observe(float64(time.Since(start).Milliseconds()))
+
 	// When task size scope is small, parent must be downloaded successfully
 	// before returning to the parent directly.
 	if !candidateParent.FSM.Is(resource.PeerStateSucceeded) {
@@ -1147,7 +1152,12 @@ func (v *V1) handleBeginOfPiece(ctx context.Context, peer *resource.Peer) {
 			return
 		}
 
+		// Record the start time.
+		start := time.Now()
 		v.scheduling.ScheduleParentAndCandidateParents(ctx, peer, set.NewSafeSet[string]())
+
+		// Collect SchedulingDuration metrics.
+		metrics.ScheduleDuration.Observe(float64(time.Since(start).Milliseconds()))
 	default:
 	}
 }
@@ -1218,7 +1228,13 @@ func (v *V1) handlePieceFailure(ctx context.Context, peer *resource.Peer, piece
 	if !loaded {
 		peer.Log.Errorf("parent %s not found", piece.DstPid)
 		peer.BlockParents.Add(piece.DstPid)
+
+		// Record the start time.
+		start := time.Now()
 		v.scheduling.ScheduleParentAndCandidateParents(ctx, peer, peer.BlockParents)
+
+		// Collect SchedulingDuration metrics.
+		metrics.ScheduleDuration.Observe(float64(time.Since(start).Milliseconds()))
 		return
 	}
 
@@ -1277,7 +1293,13 @@ func (v *V1) handlePieceFailure(ctx context.Context, peer *resource.Peer, piece
 
 	peer.Log.Infof("reschedule parent because of failed piece")
 	peer.BlockParents.Add(parent.ID)
+
+	// Record the start time.
+	start := time.Now()
 	v.scheduling.ScheduleParentAndCandidateParents(ctx, peer, peer.BlockParents)
+
+	// Collect SchedulingDuration metrics.
+	metrics.ScheduleDuration.Observe(float64(time.Since(start).Milliseconds()))
 }
 
 // handlePeerSuccess handles successful peer.
@@ -1319,7 +1341,13 @@ func (v *V1) handlePeerFailure(ctx context.Context, peer *resource.Peer) {
 	// Reschedule a new parent to children of peer to exclude the current failed peer.
 	for _, child := range peer.Children() {
 		child.Log.Infof("reschedule parent because of parent peer %s is failed", peer.ID)
+
+		// Record the start time.
+		start := time.Now()
 		v.scheduling.ScheduleParentAndCandidateParents(ctx, child, child.BlockParents)
+
+		// Collect SchedulingDuration metrics.
+		metrics.ScheduleDuration.Observe(float64(time.Since(start).Milliseconds()))
 	}
 }
 
@@ -1334,7 +1362,13 @@ func (v *V1) handleLegacySeedPeer(ctx context.Context, peer *resource.Peer) {
 	// Reschedule a new parent to children of peer to exclude the current failed peer.
 	for _, child := range peer.Children() {
 		child.Log.Infof("reschedule parent because of parent peer %s is failed", peer.ID)
+
+		// Record the start time.
+		start := time.Now()
 		v.scheduling.ScheduleParentAndCandidateParents(ctx, child, child.BlockParents)
+
+		// Collect SchedulingDuration metrics.
+		metrics.ScheduleDuration.Observe(float64(time.Since(start).Milliseconds()))
 	}
 }
 
diff --git a/scheduler/service/service_v2.go b/scheduler/service/service_v2.go
index e415466e..39d20edc 100644
--- a/scheduler/service/service_v2.go
+++ b/scheduler/service/service_v2.go
@@ -873,7 +873,7 @@ func (v *V2) handleRegisterPeerRequest(ctx context.Context, stream schedulerv2.S
 	// Collect RegisterPeerCount metrics.
 	priority := peer.CalculatePriority(v.dynconfig)
 	metrics.RegisterPeerCount.WithLabelValues(priority.String(), peer.Task.Type.String(),
-		peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+		peer.Host.Type.Name()).Inc()
 
 	blocklist := set.NewSafeSet[string]()
 	blocklist.Add(peer.ID)
@@ -904,7 +904,7 @@ func (v *V2) handleRegisterPeerRequest(ctx context.Context, stream schedulerv2.S
 			if err := v.downloadTaskBySeedPeer(ctx, taskID, download, peer); err != nil {
 				// Collect RegisterPeerFailureCount metrics.
 				metrics.RegisterPeerFailureCount.WithLabelValues(priority.String(), peer.Task.Type.String(),
-					peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+					peer.Host.Type.Name()).Inc()
 				return err
 			}
 		} else {
@@ -920,7 +920,7 @@ func (v *V2) handleRegisterPeerRequest(ctx context.Context, stream schedulerv2.S
 		if err := peer.Task.FSM.Event(ctx, resource.TaskEventDownload); err != nil {
 			// Collect RegisterPeerFailureCount metrics.
 			metrics.RegisterPeerFailureCount.WithLabelValues(priority.String(), peer.Task.Type.String(),
-				peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+				peer.Host.Type.Name()).Inc()
 			return status.Error(codes.Internal, err.Error())
 		}
 	} else {
@@ -960,13 +960,18 @@ func (v *V2) handleRegisterPeerRequest(ctx context.Context, stream schedulerv2.S
 
 		// Scheduling parent for the peer.
 		peer.BlockParents.Add(peer.ID)
+
+		// Record the start time.
+		start := time.Now()
 		if err := v.scheduling.ScheduleCandidateParents(ctx, peer, peer.BlockParents); err != nil {
 			// Collect RegisterPeerFailureCount metrics.
 			metrics.RegisterPeerFailureCount.WithLabelValues(priority.String(), peer.Task.Type.String(),
-				peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+				peer.Host.Type.Name()).Inc()
 			return status.Error(codes.FailedPrecondition, err.Error())
 		}
 
+		// Collect SchedulingDuration metrics.
+		metrics.ScheduleDuration.Observe(float64(time.Since(start).Milliseconds()))
 		return nil
 	default:
 		return status.Errorf(codes.FailedPrecondition, "invalid size cope %#v", sizeScope)
@@ -983,14 +988,14 @@ func (v *V2) handleDownloadPeerStartedRequest(ctx context.Context, peerID string
 	// Collect DownloadPeerStartedCount metrics.
 	priority := peer.CalculatePriority(v.dynconfig)
 	metrics.DownloadPeerStartedCount.WithLabelValues(priority.String(), peer.Task.Type.String(),
-		peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+		peer.Host.Type.Name()).Inc()
 
 	// Handle peer with peer started request.
 	if !peer.FSM.Is(resource.PeerStateRunning) {
 		if err := peer.FSM.Event(ctx, resource.PeerEventDownload); err != nil {
 			// Collect DownloadPeerStartedFailureCount metrics.
 			metrics.DownloadPeerStartedFailureCount.WithLabelValues(priority.String(), peer.Task.Type.String(),
-				peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+				peer.Host.Type.Name()).Inc()
 			return status.Error(codes.Internal, err.Error())
 		}
 	}
@@ -1008,14 +1013,14 @@ func (v *V2) handleDownloadPeerBackToSourceStartedRequest(ctx context.Context, p
 	// Collect DownloadPeerBackToSourceStartedCount metrics.
 	priority := peer.CalculatePriority(v.dynconfig)
 	metrics.DownloadPeerBackToSourceStartedCount.WithLabelValues(priority.String(), peer.Task.Type.String(),
-		peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+		peer.Host.Type.Name()).Inc()
 
 	// Handle peer with peer back-to-source started request.
 	if !peer.FSM.Is(resource.PeerStateRunning) {
 		if err := peer.FSM.Event(ctx, resource.PeerEventDownloadBackToSource); err != nil {
 			// Collect DownloadPeerBackToSourceStartedFailureCount metrics.
 			metrics.DownloadPeerBackToSourceStartedFailureCount.WithLabelValues(priority.String(), peer.Task.Type.String(),
-				peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+				peer.Host.Type.Name()).Inc()
 			return status.Error(codes.Internal, err.Error())
 		}
 	}
@@ -1035,10 +1040,14 @@ func (v *V2) handleRescheduleRequest(ctx context.Context, peerID string, candida
 		peer.BlockParents.Add(candidateParent.GetId())
 	}
 
+	// Record the start time.
+	start := time.Now()
 	if err := v.scheduling.ScheduleCandidateParents(ctx, peer, peer.BlockParents); err != nil {
 		return status.Error(codes.FailedPrecondition, err.Error())
 	}
 
+	// Collect SchedulingDuration metrics.
+	metrics.ScheduleDuration.Observe(float64(time.Since(start).Milliseconds()))
 	return nil
 }
 
@@ -1058,7 +1067,7 @@ func (v *V2) handleDownloadPeerFinishedRequest(ctx context.Context, peerID strin
 	// Collect DownloadPeerCount and DownloadPeerDuration metrics.
 	priority := peer.CalculatePriority(v.dynconfig)
 	metrics.DownloadPeerCount.WithLabelValues(priority.String(), peer.Task.Type.String(),
-		peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+		peer.Host.Type.Name()).Inc()
 	// TODO to be determined which traffic type to use, temporarily use TrafficType_REMOTE_PEER instead
 	metrics.DownloadPeerDuration.WithLabelValues(metrics.CalculateSizeLevel(peer.Task.ContentLength.Load()).String()).Observe(float64(peer.Cost.Load().Milliseconds()))
 
@@ -1091,7 +1100,7 @@ func (v *V2) handleDownloadPeerBackToSourceFinishedRequest(ctx context.Context,
 	// Collect DownloadPeerCount and DownloadPeerDuration metrics.
 	priority := peer.CalculatePriority(v.dynconfig)
 	metrics.DownloadPeerCount.WithLabelValues(priority.String(), peer.Task.Type.String(),
-		peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+		peer.Host.Type.Name()).Inc()
 	// TODO to be determined which traffic type to use, temporarily use TrafficType_REMOTE_PEER instead
 	metrics.DownloadPeerDuration.WithLabelValues(metrics.CalculateSizeLevel(peer.Task.ContentLength.Load()).String()).Observe(float64(peer.Cost.Load().Milliseconds()))
 
@@ -1116,9 +1125,9 @@ func (v *V2) handleDownloadPeerFailedRequest(ctx context.Context, peerID string)
 	// Collect DownloadPeerCount and DownloadPeerFailureCount metrics.
 	priority := peer.CalculatePriority(v.dynconfig)
 	metrics.DownloadPeerCount.WithLabelValues(priority.String(), peer.Task.Type.String(),
-		peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+		peer.Host.Type.Name()).Inc()
 	metrics.DownloadPeerFailureCount.WithLabelValues(priority.String(), peer.Task.Type.String(),
-		peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+		peer.Host.Type.Name()).Inc()
 
 	return nil
 }
@@ -1146,9 +1155,9 @@ func (v *V2) handleDownloadPeerBackToSourceFailedRequest(ctx context.Context, pe
 	// Collect DownloadPeerCount and DownloadPeerBackToSourceFailureCount metrics.
 	priority := peer.CalculatePriority(v.dynconfig)
 	metrics.DownloadPeerCount.WithLabelValues(priority.String(), peer.Task.Type.String(),
-		peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+		peer.Host.Type.Name()).Inc()
 	metrics.DownloadPeerBackToSourceFailureCount.WithLabelValues(priority.String(), peer.Task.Type.String(),
-		peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+		peer.Host.Type.Name()).Inc()
 
 	return nil
 }
@@ -1201,14 +1210,14 @@ func (v *V2) handleDownloadPieceFinishedRequest(peerID string, req *schedulerv2.
 
 	// Collect piece and traffic metrics.
 	metrics.DownloadPieceCount.WithLabelValues(piece.TrafficType.String(), peer.Task.Type.String(),
-		peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+		peer.Host.Type.Name()).Inc()
 	metrics.Traffic.WithLabelValues(piece.TrafficType.String(), peer.Task.Type.String(),
-		peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Add(float64(piece.Length))
+		peer.Host.Type.Name()).Add(float64(piece.Length))
 	if v.config.Metrics.EnableHost {
-		metrics.HostTraffic.WithLabelValues(metrics.HostTrafficDownloadType, peer.Task.Type.String(), peer.Task.Tag, peer.Task.Application,
+		metrics.HostTraffic.WithLabelValues(metrics.HostTrafficDownloadType, peer.Task.Type.String(),
 			peer.Host.Type.Name(), peer.Host.ID, peer.Host.IP, peer.Host.Hostname).Add(float64(piece.Length))
 		if loadedParent {
-			metrics.HostTraffic.WithLabelValues(metrics.HostTrafficUploadType, peer.Task.Type.String(), peer.Task.Tag, peer.Task.Application,
+			metrics.HostTraffic.WithLabelValues(metrics.HostTrafficUploadType, peer.Task.Type.String(),
 				parent.Host.Type.Name(), parent.Host.ID, parent.Host.IP, parent.Host.Hostname).Add(float64(piece.Length))
 		}
 	}
@@ -1257,11 +1266,11 @@ func (v *V2) handleDownloadPieceBackToSourceFinishedRequest(ctx context.Context,
 
 	// Collect piece and traffic metrics.
 	metrics.DownloadPieceCount.WithLabelValues(piece.TrafficType.String(), peer.Task.Type.String(),
-		peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+		peer.Host.Type.Name()).Inc()
 	metrics.Traffic.WithLabelValues(piece.TrafficType.String(), peer.Task.Type.String(),
-		peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Add(float64(piece.Length))
+		peer.Host.Type.Name()).Add(float64(piece.Length))
 	if v.config.Metrics.EnableHost {
-		metrics.HostTraffic.WithLabelValues(metrics.HostTrafficDownloadType, peer.Task.Type.String(), peer.Task.Tag, peer.Task.Application,
+		metrics.HostTraffic.WithLabelValues(metrics.HostTrafficDownloadType, peer.Task.Type.String(),
 			peer.Host.Type.Name(), peer.Host.ID, peer.Host.IP, peer.Host.Hostname).Add(float64(piece.Length))
 	}
 
@@ -1277,9 +1286,9 @@ func (v *V2) handleDownloadPieceFailedRequest(ctx context.Context, peerID string
 
 	// Collect DownloadPieceCount and DownloadPieceFailureCount metrics.
 	metrics.DownloadPieceCount.WithLabelValues(commonv2.TrafficType_REMOTE_PEER.String(), peer.Task.Type.String(),
-		peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+		peer.Host.Type.Name()).Inc()
 	metrics.DownloadPieceFailureCount.WithLabelValues(commonv2.TrafficType_REMOTE_PEER.String(), peer.Task.Type.String(),
-		peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+		peer.Host.Type.Name()).Inc()
 
 	if req.Temporary {
 		// Handle peer with piece temporary failed request.
@@ -1312,9 +1321,9 @@ func (v *V2) handleDownloadPieceBackToSourceFailedRequest(ctx context.Context, p
 
 	// Collect DownloadPieceCount and DownloadPieceFailureCount metrics.
 	metrics.DownloadPieceCount.WithLabelValues(commonv2.TrafficType_BACK_TO_SOURCE.String(), peer.Task.Type.String(),
-		peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+		peer.Host.Type.Name()).Inc()
 	metrics.DownloadPieceFailureCount.WithLabelValues(commonv2.TrafficType_BACK_TO_SOURCE.String(), peer.Task.Type.String(),
-		peer.Task.Tag, peer.Task.Application, peer.Host.Type.Name()).Inc()
+		peer.Host.Type.Name()).Inc()
 
 	return status.Error(codes.Internal, "download piece from source failed")
 }
diff --git a/trainer/training/training.go b/trainer/training/training.go
index 79264c28..181c50a1 100644
--- a/trainer/training/training.go
+++ b/trainer/training/training.go
@@ -43,7 +43,7 @@ type training struct {
 	// Storage interface.
 	storage storage.Storage
 
-	// Manager service clent.
+	// Manager service client.
 	managerClient managerclient.V2
 }
 



Test patch:
diff --git a/internal/dynconfig/dynconfig_test.go b/internal/dynconfig/dynconfig_test.go
index 5b341aa3..d0a33d14 100644
--- a/internal/dynconfig/dynconfig_test.go
+++ b/internal/dynconfig/dynconfig_test.go
@@ -138,7 +138,7 @@ func TestDynconfig_Get(t *testing.T) {
 
 				gomock.InOrder(
 					m.Get().Return(d, nil).Times(1),
-					m.Get().Return(nil, errors.New("manager serivce error")).Times(1),
+					m.Get().Return(nil, errors.New("manager service error")).Times(1),
 				)
 			},
 			run: func(t *testing.T, d Dynconfig[TestDynconfig]) {
diff --git a/manager/handlers/job_test.go b/manager/handlers/job_test.go
index b3d02668..9eb311f9 100644
--- a/manager/handlers/job_test.go
+++ b/manager/handlers/job_test.go
@@ -39,6 +39,18 @@ var (
 			"user_id": 4,
 			"bio": "bio"
 		}`
+	mockGetTaskJobReqBody = `
+		{
+			"type": "get_task",
+			"user_id": 4,
+			"bio": "bio"
+		}`
+	mockDeleteTaskJobReqBody = `
+		{
+			"type": "delete_task",
+			"user_id": 4,
+			"bio": "bio"
+		}`
 	mockOtherJobReqBody = `
 		{
 			"type": "others",
@@ -50,6 +62,16 @@ var (
 		Type:   "preheat",
 		BIO:    "bio",
 	}
+	mockCreateGetTaskJobRequest = types.CreateGetTaskJobRequest{
+		UserID: 4,
+		Type:   "get_task",
+		BIO:    "bio",
+	}
+	mockCreateDeleteTaskJobRequest = types.CreateDeleteTaskJobRequest{
+		UserID: 4,
+		Type:   "delete_task",
+		BIO:    "bio",
+	}
 	mockUpdateJobRequest = types.UpdateJobRequest{
 		UserID: 4,
 		BIO:    "bio",
@@ -61,6 +83,20 @@ var (
 		BIO:       "bio",
 		TaskID:    "2",
 	}
+	mockGetTaskJobModel = &models.Job{
+		BaseModel: mockBaseModel,
+		UserID:    4,
+		Type:      "get_task",
+		BIO:       "bio",
+		TaskID:    "2",
+	}
+	mockDeleteTaskJobModel = &models.Job{
+		BaseModel: mockBaseModel,
+		UserID:    4,
+		Type:      "delete_task",
+		BIO:       "bio",
+		TaskID:    "2",
+	}
 )
 
 func mockJobRouter(h *Handlers) *gin.Engine {
@@ -115,6 +151,36 @@ func TestHandlers_CreateJob(t *testing.T) {
 				assert.Equal(mockPreheatJobModel, &job)
 			},
 		},
+		{
+			name: "success",
+			req:  httptest.NewRequest(http.MethodPost, "/oapi/v1/jobs", strings.NewReader(mockGetTaskJobReqBody)),
+			mock: func(ms *mocks.MockServiceMockRecorder) {
+				ms.CreateGetTaskJob(gomock.Any(), gomock.Eq(mockCreateGetTaskJobRequest)).Return(mockGetTaskJobModel, nil).Times(1)
+			},
+			expect: func(t *testing.T, w *httptest.ResponseRecorder) {
+				assert := assert.New(t)
+				assert.Equal(http.StatusOK, w.Code)
+				job := models.Job{}
+				err := json.Unmarshal(w.Body.Bytes(), &job)
+				assert.NoError(err)
+				assert.Equal(mockGetTaskJobModel, &job)
+			},
+		},
+		{
+			name: "success",
+			req:  httptest.NewRequest(http.MethodPost, "/oapi/v1/jobs", strings.NewReader(mockDeleteTaskJobReqBody)),
+			mock: func(ms *mocks.MockServiceMockRecorder) {
+				ms.CreateDeleteTaskJob(gomock.Any(), gomock.Eq(mockCreateDeleteTaskJobRequest)).Return(mockDeleteTaskJobModel, nil).Times(1)
+			},
+			expect: func(t *testing.T, w *httptest.ResponseRecorder) {
+				assert := assert.New(t)
+				assert.Equal(http.StatusOK, w.Code)
+				job := models.Job{}
+				err := json.Unmarshal(w.Body.Bytes(), &job)
+				assert.NoError(err)
+				assert.Equal(mockDeleteTaskJobModel, &job)
+			},
+		},
 	}
 	for _, tc := range tests {
 		t.Run(tc.name, func(t *testing.T) {
diff --git a/pkg/idgen/task_id_test.go b/pkg/idgen/task_id_test.go
index 5f86e134..11cf4d00 100644
--- a/pkg/idgen/task_id_test.go
+++ b/pkg/idgen/task_id_test.go
@@ -113,7 +113,6 @@ func TestTaskIDV2(t *testing.T) {
 		digest      string
 		tag         string
 		application string
-		pieceLength int32
 		filters     []string
 		expect      func(t *testing.T, d any)
 	}{
@@ -123,11 +122,10 @@ func TestTaskIDV2(t *testing.T) {
 			digest:      "sha256:c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
 			tag:         "foo",
 			application: "bar",
-			pieceLength: 1,
 			filters:     []string{},
 			expect: func(t *testing.T, d any) {
 				assert := assert.New(t)
-				assert.Equal(d, "6acf73532a2e7b8c30dfc7abce2fd7d2a2cd3746f16b0d54d3e2f136ffa61c90")
+				assert.Equal(d, "c8659b8372599cf22c7a2de260dd6e148fca6d4e1c2940703022867f739d071d")
 			},
 		},
 		{
@@ -136,7 +134,7 @@ func TestTaskIDV2(t *testing.T) {
 			digest: "sha256:c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4",
 			expect: func(t *testing.T, d any) {
 				assert := assert.New(t)
-				assert.Equal(d, "b08a435da662ad5ae8ab8359a9c4ebd5027cf14d04b71ccc85f1e197e898adbd")
+				assert.Equal(d, "60469c583429af631a45540f05e08805b31ca4f84e7974cad35cfc84c197bcf8")
 			},
 		},
 		{
@@ -145,7 +143,7 @@ func TestTaskIDV2(t *testing.T) {
 			tag:  "foo",
 			expect: func(t *testing.T, d any) {
 				assert := assert.New(t)
-				assert.Equal(d, "274c3716c538b5a49e7296ee36dd412bae29948dfb6153e5ac9694e382144f83")
+				assert.Equal(d, "2773851c628744fb7933003195db436ce397c1722920696c4274ff804d86920b")
 			},
 		},
 		{
@@ -154,16 +152,7 @@ func TestTaskIDV2(t *testing.T) {
 			application: "bar",
 			expect: func(t *testing.T, d any) {
 				assert := assert.New(t)
-				assert.Equal(d, "ca12c6591c38f726c238f35d9c7945559b52a0dcc10ae191920be6f5f8a0326a")
-			},
-		},
-		{
-			name:        "generate taskID with pieceLength",
-			url:         "https://example.com",
-			pieceLength: 1,
-			expect: func(t *testing.T, d any) {
-				assert := assert.New(t)
-				assert.Equal(d, "614fb0088e7d82b2538f1ccb5861db5940aaa665b587792898e4be1f591bafec")
+				assert.Equal(d, "63dee2822037636b0109876b58e95692233840753a882afa69b9b5ee82a6c57d")
 			},
 		},
 		{
@@ -172,14 +161,14 @@ func TestTaskIDV2(t *testing.T) {
 			filters: []string{"foo", "bar"},
 			expect: func(t *testing.T, d any) {
 				assert := assert.New(t)
-				assert.Equal(d, "4a89bbe790108d4987e7dc5127df2b99aea1c17828f1ff3e55176f49ac974b28")
+				assert.Equal(d, "100680ad546ce6a577f42f52df33b4cfdca756859e664b8d7de329b150d09ce9")
 			},
 		},
 	}
 
 	for _, tc := range tests {
 		t.Run(tc.name, func(t *testing.T) {
-			tc.expect(t, TaskIDV2(tc.url, tc.digest, tc.tag, tc.application, tc.pieceLength, tc.filters))
+			tc.expect(t, TaskIDV2(tc.url, tc.digest, tc.tag, tc.application, tc.filters))
 		})
 	}
 }
diff --git a/scheduler/resource/task_test.go b/scheduler/resource/task_test.go
index a597221c..246aadc7 100644
--- a/scheduler/resource/task_test.go
+++ b/scheduler/resource/task_test.go
@@ -52,7 +52,7 @@ var (
 
 	mockTaskBackToSourceLimit   int32 = 200
 	mockTaskURL                       = "http://example.com/foo"
-	mockTaskID                        = idgen.TaskIDV2(mockTaskURL, mockTaskDigest.String(), mockTaskTag, mockTaskApplication, mockTaskPieceLength, mockTaskFilteredQueryParams)
+	mockTaskID                        = idgen.TaskIDV2(mockTaskURL, mockTaskDigest.String(), mockTaskTag, mockTaskApplication, mockTaskFilteredQueryParams)
 	mockTaskDigest                    = digest.New(digest.AlgorithmSHA256, "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4")
 	mockTaskTag                       = "d7y"
 	mockTaskApplication               = "foo"
diff --git a/scheduler/scheduling/evaluator/evaluator_base_test.go b/scheduler/scheduling/evaluator/evaluator_base_test.go
index 19a0e784..1f0e5da5 100644
--- a/scheduler/scheduling/evaluator/evaluator_base_test.go
+++ b/scheduler/scheduling/evaluator/evaluator_base_test.go
@@ -131,7 +131,7 @@ var (
 
 	mockTaskBackToSourceLimit   int32 = 200
 	mockTaskURL                       = "http://example.com/foo"
-	mockTaskID                        = idgen.TaskIDV2(mockTaskURL, mockTaskDigest.String(), mockTaskTag, mockTaskApplication, mockTaskPieceLength, mockTaskFilteredQueryParams)
+	mockTaskID                        = idgen.TaskIDV2(mockTaskURL, mockTaskDigest.String(), mockTaskTag, mockTaskApplication, mockTaskFilteredQueryParams)
 	mockTaskDigest                    = digest.New(digest.AlgorithmSHA256, "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4")
 	mockTaskTag                       = "d7y"
 	mockTaskApplication               = "foo"
diff --git a/scheduler/scheduling/scheduling_test.go b/scheduler/scheduling/scheduling_test.go
index c790283c..27a9b935 100644
--- a/scheduler/scheduling/scheduling_test.go
+++ b/scheduler/scheduling/scheduling_test.go
@@ -159,7 +159,7 @@ var (
 
 	mockTaskBackToSourceLimit   int32 = 200
 	mockTaskURL                       = "http://example.com/foo"
-	mockTaskID                        = idgen.TaskIDV2(mockTaskURL, mockTaskDigest.String(), mockTaskTag, mockTaskApplication, mockTaskPieceLength, mockTaskFilteredQueryParams)
+	mockTaskID                        = idgen.TaskIDV2(mockTaskURL, mockTaskDigest.String(), mockTaskTag, mockTaskApplication, mockTaskFilteredQueryParams)
 	mockTaskDigest                    = digest.New(digest.AlgorithmSHA256, "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4")
 	mockTaskTag                       = "d7y"
 	mockTaskApplication               = "foo"
diff --git a/scheduler/service/service_v1_test.go b/scheduler/service/service_v1_test.go
index 1f792cf0..44ca42b4 100644
--- a/scheduler/service/service_v1_test.go
+++ b/scheduler/service/service_v1_test.go
@@ -197,7 +197,7 @@ var (
 
 	mockTaskBackToSourceLimit   int32 = 200
 	mockTaskURL                       = "http://example.com/foo"
-	mockTaskID                        = idgen.TaskIDV2(mockTaskURL, mockTaskDigest.String(), mockTaskTag, mockTaskApplication, mockTaskPieceLength, mockTaskFilteredQueryParams)
+	mockTaskID                        = idgen.TaskIDV2(mockTaskURL, mockTaskDigest.String(), mockTaskTag, mockTaskApplication, mockTaskFilteredQueryParams)
 	mockTaskDigest                    = digest.New(digest.AlgorithmSHA256, "c71d239df91726fc519c6eb72d318ec65820627232b2f796219e87dcf35d0ab4")
 	mockTaskTag                       = "d7y"
 	mockTaskApplication               = "foo"
diff --git a/test/e2e/v2/concurrency_test.go b/test/e2e/v2/concurrency_test.go
index 62a1c6bf..e5707cbc 100644
--- a/test/e2e/v2/concurrency_test.go
+++ b/test/e2e/v2/concurrency_test.go
@@ -37,7 +37,7 @@ var _ = Describe("Download Concurrency", func() {
 			Expect(err).NotTo(HaveOccurred())
 
 			fileMetadata := util.FileMetadata{
-				ID:     "423990483b62613df9671fb8f3cf48f4c46b9486debf65e62a765719547a00d2",
+				ID:     "de7d72a4f865bb1b1d3a9b7288bfd369a500277f5565736b2ba67aa205958df7",
 				Sha256: "fc44bbbba20490450c73530db3d1b935f893f38d7d8084ca132952a765ff5ff6",
 			}
 
@@ -67,7 +67,7 @@ var _ = Describe("Download Concurrency", func() {
 			Expect(err).NotTo(HaveOccurred())
 
 			fileMetadata := util.FileMetadata{
-				ID:     "f533d0d08acd4e6d57c0249e97aa08195deb41a470cf781cdfc15e4bf34a87e9",
+				ID:     "510f018dc34c7e6ced07db2e88654a4e565e7982d5c73994e48e901f633c8113",
 				Sha256: "dc102987a36be20846821ac74648534863ff0fe8897d4250273a6ffc80481d91",
 			}
 
@@ -97,7 +97,7 @@ var _ = Describe("Download Concurrency", func() {
 			Expect(err).NotTo(HaveOccurred())
 
 			fileMetadata := util.FileMetadata{
-				ID:     "7eee7f3238d0e8c40ac822dbc156384c160d2b3ea0fab1bbddcbe91f31c7caae",
+				ID:     "381ee3f1dd0b55d151997e107e5517e4ac315677a4ed67c3cd814fe7b86481d1",
 				Sha256: "54e54b7ff54ef70d4db2adcd24a27e3b9af3cd99fc0213983bac1e8035429be6",
 			}
 
@@ -127,7 +127,7 @@ var _ = Describe("Download Concurrency", func() {
 			Expect(err).NotTo(HaveOccurred())
 
 			fileMetadata := util.FileMetadata{
-				ID:     "90fd5db5089bee6c00a2eedd616df7b34cfe22894235bb6bbe44ac1e9a9051a6",
+				ID:     "0068ce9e9beaca3ec33911d537be56de2d12e1b201bf3230aefe803919c373a5",
 				Sha256: "87c09b7c338f258809ca2d436bbe06ac94a3166b3f3e1125a86f35d9a9aa1d2f",
 			}
 
diff --git a/test/e2e/v2/containerd_test.go b/test/e2e/v2/containerd_test.go
index 14afc3cf..08e1e4d3 100644
--- a/test/e2e/v2/containerd_test.go
+++ b/test/e2e/v2/containerd_test.go
@@ -35,27 +35,27 @@ var _ = Describe("Containerd with CRI support", func() {
 
 			taskMetadatas := []util.TaskMetadata{
 				{
-					ID:     "ff679754c7951659b21b84fedc15c82e285909146329eae5114a762459b49221",
+					ID:     "c6c9f8b1ded96e4355f46c56c858cc52906ece01df55ad2c9600bd3635af2b74",
 					Sha256: "ca51217de9012bffe54390f1a91365af22a06279a3f2b3e57d4d2dc99b989588",
 				},
 				{
-					ID:     "cfe7b96cdd7af51b0433507da8c4239adb1985d27c8a62136b7ca4c2b0796d63",
+					ID:     "389a7dd948c14ecaa3b36d0c3697a41b2547ea556ca0f1b427860b4b11e80815",
 					Sha256: "0d816dfc0753b877a04e3df93557bd3597fc7d0e308726655b14401c22a3b92a",
 				},
 				{
-					ID:     "43ab6b508e9e57e990d38322572a39fd628fd5ec34d83ecd66aee5d199265f84",
+					ID:     "d16441e8c63799b5148a46edb0af535dd017f43f684510bd5ddd358e901c36ad",
 					Sha256: "b5941d5a445040d3a792e5be361ca42989d97fc30ff53031f3004ccea8e44520",
 				},
 				{
-					ID:     "88c81ef2a014504dd493eeb4ad140dbfe05e12a53038fea2f4f04e10fd4bcf38",
+					ID:     "221de8465d2047153514e30cd586b9a6398bc8860ad5ea7c5853a3ca09b423c2",
 					Sha256: "c1d6d1b2d5a367259e6e51a7f4d1ccd66a28cc9940d6599d8a8ea9544dd4b4a8",
 				},
 				{
-					ID:     "adad87ebcac1fc92d13051a8f15fc29f33f733a93ad322119e00764cbbbcb501",
+					ID:     "71f89a34789a43c3ad7f55842890d0caf5a45a833bf4c8b72874b174f0358127",
 					Sha256: "2a1bc4e0f20bb5ed9a2197ecffde7eace4a9b9179048614205d025df73ba97c7",
 				},
 				{
-					ID:     "1dcf30a9df83b64fd8ad85288ed01def4d8758ee9c433861b86ceced46b2c97d",
+					ID:     "166359883b2334eb1ee9a9d49209a4286328c5e28605367e2d073fbdac6f5d0d",
 					Sha256: "078ea4eebc352a499d7bb6ff65fab1325226e524acac89a9db922ad91cab88f1",
 				},
 			}
@@ -98,19 +98,19 @@ var _ = Describe("Containerd with CRI support", func() {
 
 			taskMetadatas := []util.TaskMetadata{
 				{
-					ID:     "69fa645056298e4809c88cf86c3fb559ffa62bb4d1f986cacf1aa81933e3d030",
+					ID:     "b01e905eb9803c65ade52d10b56cd024d5437377a477a53488cbbd346e895918",
 					Sha256: "0f4277a6444fbaf4eb5a7f39103e281dd57969953c7425edc7c8d4aa419347eb",
 				},
 				{
-					ID:     "23eaaf799cb4191256c352aec0a207089a26e105e779e7f93f3726598c975165",
+					ID:     "f318e52bbbd81e2ba2afc697379118445ea32df733c92b20bfab6ba5183257a4",
 					Sha256: "e55b67c1d5660c34dcb0d8e6923d0a50695a4f0d94f858353069bae17d0bfdea",
 				},
 				{
-					ID:     "4dbaa1695f5410bcd59560cf79408c1ae69d27c8cfd94259359ff69e026ebdaa",
+					ID:     "5276a8a1dc433233d58c36a16a795511c946cf1f27b36ec60efeaae43a615b23",
 					Sha256: "8572bc8fb8a32061648dd183b2c0451c82be1bd053a4ea8fae991436b92faebb",
 				},
 				{
-					ID:     "c65dac943d3f294a1e0005618ac197a4f8d38eb93176a631eba7e34913cb5747",
+					ID:     "83f9961825895cb4890a15db88980832adf825070c148d4260dfeb703652cd7f",
 					Sha256: "88bfc12bad0cc91b2d47de4c7a755f6547b750256cc4c8b284e07aae13e4e041",
 				},
 			}
@@ -154,27 +154,27 @@ var _ = Describe("Containerd with CRI support", func() {
 
 			taskMetadatas := []util.TaskMetadata{
 				{
-					ID:     "d6998ea9e6f6d0fe8dfa5efe1098d4bc29234a298a1bf857c3129d534c064dd5",
+					ID:     "157855128cf9d03cf9d5dcc53ec5d13a1dd26b252c6eda628fec21ccf9a8c349",
 					Sha256: "c8071d0de0f5bb17fde217dafdc9d2813ce9db77e60f6233bcd32f1c8888b121",
 				},
 				{
-					ID:     "9764b091db2dca99e2a0c09c776be3915e913f02def63e794435e048d2cb7ad7",
+					ID:     "76773bad88ce3fded570cc165fe9c11b946622a07172727e18f64fb4316efc5a",
 					Sha256: "e964513726885fa2f977425fc889eabbe25c9fa47e7a4b0ec5e2baef96290f47",
 				},
 				{
-					ID:     "e376fd3b1d92d8db1a29fc7aa307ae243eaa229a84ffc4f4f84247046fd75850",
+					ID:     "c65a3d75938ab15d2520c6ed8a8680ae41921172f0c9359b6ed7e67573f7989d",
 					Sha256: "0e304933d7eae4674e05b3bc409f236c65077e2b7055119bbd66ff613fe5e1ad",
 				},
 				{
-					ID:     "77fb97fa428921c5a5a72be510c69b1208db540479dda3a1ff765a248ed23287",
+					ID:     "d96e650ebf7ec07618a8629880ca0da62fd9e36a9fe59eb309636c6c66410489",
 					Sha256: "53b01ef3d5d676a8514ded6b469932e33d84738e5e00932ca124382a8567c44b",
 				},
 				{
-					ID:     "b58219de7051f520e222ce29c90e2d61b49649d714bd2d9e6ebcebbc83a15f2b",
+					ID:     "666b5bdb2a3c0498dfb3b73b95bc85b2679d0c65ef5d8e80ae9038b92631bfec",
 					Sha256: "c9d959fc168ad8bdc9a021066eb9c1dd4de8e860c03619a88d8ba0ff5479d9ea",
 				},
 				{
-					ID:     "4bceb8758fe687ac33610c23f503dc13d9050c15be3f20f9141b94a450070d9f",
+					ID:     "886aaa587415010d418ce8d3848fda6c3c0d2c8ae733960d28e2bc9149e5ed07",
 					Sha256: "b6acfae843b58bf14369ebbeafa96af5352cde9a89f8255ca51f92b233a6e405",
 				},
 			}
@@ -218,15 +218,15 @@ var _ = Describe("Containerd with CRI support", func() {
 
 			taskMetadatas := []util.TaskMetadata{
 				{
-					ID:     "5f04fd58b821860c616ad3f8cfe096c53969086a99ec9d63a7b6d75e643cd33f",
+					ID:     "3a909585362079e870dd1f2286433b24fe1f2007599dadc6eaf5f73d8ba2b209",
 					Sha256: "c58d97dd21c3b3121f262a1fbb5a278f77ab85dba7a02b819e710f34683cf746",
 				},
 				{
-					ID:     "67948562926bcaafea035f5e7ae8007f1b367c5fb050ed57fc70faa1b95d73af",
+					ID:     "843ad9a841e99d9e8c18e5cccc200ed81e825bcecbeb749f6956bb7e43db0bfc",
 					Sha256: "2ff0ae26fa61a2b0f88f470a8e50f7623ea48b224eb072a5878a20d663d5307d",
 				},
 				{
-					ID:     "ea70b1749ce2e542271512ba2a50b01787b4a17edd42a2c1450097c60845a10c",
+					ID:     "89d8de8f4cabeba625ffe416425a4c821e327b8e687096351bbf072b34018a19",
 					Sha256: "b1826117441e607acd3b98c93cdb16759c2cc2240852055b8a2b5860f3204f1e",
 				},
 			}
diff --git a/test/e2e/v2/dfget_test.go b/test/e2e/v2/dfget_test.go
index 0fec9adf..a4a1de2b 100644
--- a/test/e2e/v2/dfget_test.go
+++ b/test/e2e/v2/dfget_test.go
@@ -38,7 +38,7 @@ var _ = Describe("Download Using Dfget", func() {
 			Expect(err).NotTo(HaveOccurred())
 
 			fileMetadata := util.FileMetadata{
-				ID:     "1fc5ed9922a3d741063c169ec49c2071a391db5fda8de30eb6a97f60b5038c16",
+				ID:     "bca2831966564d5afc95ee720836e22ce064f28ab7afc3e8ad2374565bcf3873",
 				Sha256: "6288d2a89e2a9611191c25a45de20e94d8d058c75f274a39970d41f60f367e6f",
 			}
 
@@ -75,7 +75,7 @@ var _ = Describe("Download Using Dfget", func() {
 			Expect(err).NotTo(HaveOccurred())
 
 			fileMetadata := util.FileMetadata{
-				ID:     "aaa32162d94ffb18dd407dc9abf2ac915b6dac4687dcf936a364818717d0155b",
+				ID:     "cc2a62a71cb3555a67e54ab905ff311a1f74a1cb82137a1af3eaa5c38219bd0d",
 				Sha256: "327b4022d0bfd1d5e9c0701d4a3f989a536f7e6e865e102dcd77c7e7adb31f9a",
 			}
 
@@ -112,7 +112,7 @@ var _ = Describe("Download Using Dfget", func() {
 			Expect(err).NotTo(HaveOccurred())
 
 			fileMetadata := util.FileMetadata{
-				ID:     "3e9135a3e652efb9e6ae0b430f61d36a91093208009ddb839a1c9a1979274f89",
+				ID:     "fd60786a0e11228d949f1ca0e4c82e301c5daab3638159e3bb7202e3dffe12ea",
 				Sha256: "a1cbf1bf2d66757121677fd7fefafacd4f843a2cb44a451131002803bae56a65",
 			}
 
@@ -149,7 +149,7 @@ var _ = Describe("Download Using Dfget", func() {
 			Expect(err).NotTo(HaveOccurred())
 
 			fileMetadata := util.FileMetadata{
-				ID:     "a36732ab9c09237884ceefe8c1a007558fd15a9c891f1f905e4b95136266da70",
+				ID:     "9cd2ae0296e11b8e9a300deb8c13f1edba54e90356716c6a29fbc405e6cdfd45",
 				Sha256: "b0cfe211f851049a78f5812cf5b1d7cb4f3fbb101c02c1865c940d5797f4b73b",
 			}
 
@@ -186,7 +186,7 @@ var _ = Describe("Download Using Dfget", func() {
 			Expect(err).NotTo(HaveOccurred())
 
 			fileMetadata := util.FileMetadata{
-				ID:     "f2efea3df39f19e192a395843f67cfbb4338f3616014d9c5857da4c14cd01621",
+				ID:     "c288f941340197c0611b5c50e6682f367d087a3b5289cf75ac5048f8774cb7c1",
 				Sha256: "c37f93c73cf2f303f874c094f6f76e47b2421a3da9f0e7e0b98bea8a3d685322",
 			}
 
@@ -212,191 +212,6 @@ var _ = Describe("Download Using Dfget", func() {
 		})
 	})
 
-	Context("/etc/containerd/config.toml file and set piece length to 128MB", func() {
-		It("download should be ok", Label("dfget", "download", "piece length 128MB"), func() {
-			clientPod, err := util.ClientExec()
-			fmt.Println(err)
-			Expect(err).NotTo(HaveOccurred())
-
-			out, err := clientPod.Command("sh", "-c", fmt.Sprintf("dfget %s --disable-back-to-source --piece-length 134217728 --output %s", util.GetFileURL("/etc/containerd/config.toml"), util.GetOutputPath("config.toml-2"))).CombinedOutput()
-			fmt.Println(string(out), err)
-			Expect(err).NotTo(HaveOccurred())
-
-			fileMetadata := util.FileMetadata{
-				ID:     "1ae51fe69c381a4604517f1d00d4315afef070bab3bcb475f11770fc5b194821",
-				Sha256: "6288d2a89e2a9611191c25a45de20e94d8d058c75f274a39970d41f60f367e6f",
-			}
-
-			sha256sum, err := util.CalculateSha256ByTaskID([]*util.PodExec{clientPod}, fileMetadata.ID)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(fileMetadata.Sha256).To(Equal(sha256sum))
-
-			sha256sum, err = util.CalculateSha256ByOutput([]*util.PodExec{clientPod}, util.GetOutputPath("config.toml-2"))
-			Expect(err).NotTo(HaveOccurred())
-			Expect(fileMetadata.Sha256).To(Equal(sha256sum))
-
-			time.Sleep(1 * time.Second)
-			seedClientPods := make([]*util.PodExec, 3)
-			for i := 0; i < 3; i++ {
-				seedClientPods[i], err = util.SeedClientExec(i)
-				fmt.Println(err)
-				Expect(err).NotTo(HaveOccurred())
-			}
-
-			sha256sum, err = util.CalculateSha256ByTaskID(seedClientPods, fileMetadata.ID)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(fileMetadata.Sha256).To(Equal(sha256sum))
-		})
-	})
-
-	Context("/bin/kubectl file and set piece length to 64MB", func() {
-		It("download should be ok", Label("dfget", "download", "piece length 64MB"), func() {
-			clientPod, err := util.ClientExec()
-			fmt.Println(err)
-			Expect(err).NotTo(HaveOccurred())
-
-			out, err := clientPod.Command("sh", "-c", fmt.Sprintf("dfget %s --disable-back-to-source --piece-length 67108864 --output %s", util.GetFileURL("/bin/kubectl"), util.GetOutputPath("kubectl-2"))).CombinedOutput()
-			fmt.Println(string(out), err)
-			Expect(err).NotTo(HaveOccurred())
-
-			fileMetadata := util.FileMetadata{
-				ID:     "617d59d9cf3f9bd394ee98f327a77fc0b45a34431e59938abd0db20b467d8713",
-				Sha256: "327b4022d0bfd1d5e9c0701d4a3f989a536f7e6e865e102dcd77c7e7adb31f9a",
-			}
-
-			sha256sum, err := util.CalculateSha256ByTaskID([]*util.PodExec{clientPod}, fileMetadata.ID)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(fileMetadata.Sha256).To(Equal(sha256sum))
-
-			sha256sum, err = util.CalculateSha256ByOutput([]*util.PodExec{clientPod}, util.GetOutputPath("kubectl-2"))
-			Expect(err).NotTo(HaveOccurred())
-			Expect(fileMetadata.Sha256).To(Equal(sha256sum))
-
-			time.Sleep(1 * time.Second)
-			seedClientPods := make([]*util.PodExec, 3)
-			for i := 0; i < 3; i++ {
-				seedClientPods[i], err = util.SeedClientExec(i)
-				fmt.Println(err)
-				Expect(err).NotTo(HaveOccurred())
-			}
-
-			sha256sum, err = util.CalculateSha256ByTaskID(seedClientPods, fileMetadata.ID)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(fileMetadata.Sha256).To(Equal(sha256sum))
-		})
-	})
-
-	Context("/bin/x86_64 file and set piece length to 32MB", func() {
-		It("download should be ok", Label("dfget", "download", "piece length 32MB"), func() {
-			clientPod, err := util.ClientExec()
-			fmt.Println(err)
-			Expect(err).NotTo(HaveOccurred())
-
-			out, err := clientPod.Command("sh", "-c", fmt.Sprintf("dfget %s --disable-back-to-source --piece-length 33554432 --output %s", util.GetFileURL("/bin/x86_64"), util.GetOutputPath("x86_64-2"))).CombinedOutput()
-			fmt.Println(string(out), err)
-			Expect(err).NotTo(HaveOccurred())
-
-			fileMetadata := util.FileMetadata{
-				ID:     "f6b341fff271d4508e6f4820511c44bac3027c005c237798f98b89743c311148",
-				Sha256: "a1cbf1bf2d66757121677fd7fefafacd4f843a2cb44a451131002803bae56a65",
-			}
-
-			sha256sum, err := util.CalculateSha256ByTaskID([]*util.PodExec{clientPod}, fileMetadata.ID)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(fileMetadata.Sha256).To(Equal(sha256sum))
-
-			sha256sum, err = util.CalculateSha256ByOutput([]*util.PodExec{clientPod}, util.GetOutputPath("x86_64-2"))
-			Expect(err).NotTo(HaveOccurred())
-			Expect(fileMetadata.Sha256).To(Equal(sha256sum))
-
-			time.Sleep(1 * time.Second)
-			seedClientPods := make([]*util.PodExec, 3)
-			for i := 0; i < 3; i++ {
-				seedClientPods[i], err = util.SeedClientExec(i)
-				fmt.Println(err)
-				Expect(err).NotTo(HaveOccurred())
-			}
-
-			sha256sum, err = util.CalculateSha256ByTaskID(seedClientPods, fileMetadata.ID)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(fileMetadata.Sha256).To(Equal(sha256sum))
-		})
-	})
-
-	Context("/bin/zless file and set piece length to 16MB", func() {
-		It("download should be ok", Label("dfget", "download", "piece length 16MB"), func() {
-			clientPod, err := util.ClientExec()
-			fmt.Println(err)
-			Expect(err).NotTo(HaveOccurred())
-
-			out, err := clientPod.Command("sh", "-c", fmt.Sprintf("dfget %s --disable-back-to-source --piece-length 16777216 --output %s", util.GetFileURL("/bin/zless"), util.GetOutputPath("zless-2"))).CombinedOutput()
-			fmt.Println(string(out), err)
-			Expect(err).NotTo(HaveOccurred())
-
-			fileMetadata := util.FileMetadata{
-				ID:     "c358a010a628bd2720634ca245886c06d6555db7c020561bbea96d6c3afc13c9",
-				Sha256: "b0cfe211f851049a78f5812cf5b1d7cb4f3fbb101c02c1865c940d5797f4b73b",
-			}
-
-			sha256sum, err := util.CalculateSha256ByTaskID([]*util.PodExec{clientPod}, fileMetadata.ID)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(fileMetadata.Sha256).To(Equal(sha256sum))
-
-			sha256sum, err = util.CalculateSha256ByOutput([]*util.PodExec{clientPod}, util.GetOutputPath("zless-2"))
-			Expect(err).NotTo(HaveOccurred())
-			Expect(fileMetadata.Sha256).To(Equal(sha256sum))
-
-			time.Sleep(1 * time.Second)
-			seedClientPods := make([]*util.PodExec, 3)
-			for i := 0; i < 3; i++ {
-				seedClientPods[i], err = util.SeedClientExec(i)
-				fmt.Println(err)
-				Expect(err).NotTo(HaveOccurred())
-			}
-
-			sha256sum, err = util.CalculateSha256ByTaskID(seedClientPods, fileMetadata.ID)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(fileMetadata.Sha256).To(Equal(sha256sum))
-		})
-	})
-
-	Context("/bin/bash file and set piece length to 1MB", func() {
-		It("download should be ok", Label("dfget", "download", "piece length 1MB"), func() {
-			clientPod, err := util.ClientExec()
-			fmt.Println(err)
-			Expect(err).NotTo(HaveOccurred())
-
-			out, err := clientPod.Command("sh", "-c", fmt.Sprintf("dfget %s --disable-back-to-source --piece-length 1048576 --output %s", util.GetFileURL("/bin/bash"), util.GetOutputPath("bash-2"))).CombinedOutput()
-			fmt.Println(string(out), err)
-			Expect(err).NotTo(HaveOccurred())
-
-			fileMetadata := util.FileMetadata{
-				ID:     "08b79b117296dd83c010d566c11b77e457d8021feb858f2d7b351686f12204e7",
-				Sha256: "c37f93c73cf2f303f874c094f6f76e47b2421a3da9f0e7e0b98bea8a3d685322",
-			}
-
-			sha256sum, err := util.CalculateSha256ByTaskID([]*util.PodExec{clientPod}, fileMetadata.ID)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(fileMetadata.Sha256).To(Equal(sha256sum))
-
-			sha256sum, err = util.CalculateSha256ByOutput([]*util.PodExec{clientPod}, util.GetOutputPath("bash-2"))
-			Expect(err).NotTo(HaveOccurred())
-			Expect(fileMetadata.Sha256).To(Equal(sha256sum))
-
-			time.Sleep(1 * time.Second)
-			seedClientPods := make([]*util.PodExec, 3)
-			for i := 0; i < 3; i++ {
-				seedClientPods[i], err = util.SeedClientExec(i)
-				fmt.Println(err)
-				Expect(err).NotTo(HaveOccurred())
-			}
-
-			sha256sum, err = util.CalculateSha256ByTaskID(seedClientPods, fileMetadata.ID)
-			Expect(err).NotTo(HaveOccurred())
-			Expect(fileMetadata.Sha256).To(Equal(sha256sum))
-		})
-	})
-
 	Context("/etc/containerd/config.toml file and set application to d7y", func() {
 		It("download should be ok", Label("dfget", "download", "application d7y"), func() {
 			clientPod, err := util.ClientExec()
@@ -408,7 +223,7 @@ var _ = Describe("Download Using Dfget", func() {
 			Expect(err).NotTo(HaveOccurred())
 
 			fileMetadata := util.FileMetadata{
-				ID:     "9746acdb4bd8bf2deeb5dd8a3275e51a7fdd4adf8b0dc1d9d26a4565d3ed6592",
+				ID:     "27e00689dfe0410b5b34758452f95d063d916c62ffdd28b1ab35995107696a48",
 				Sha256: "6288d2a89e2a9611191c25a45de20e94d8d058c75f274a39970d41f60f367e6f",
 			}
 
@@ -445,7 +260,7 @@ var _ = Describe("Download Using Dfget", func() {
 			Expect(err).NotTo(HaveOccurred())
 
 			fileMetadata := util.FileMetadata{
-				ID:     "9746acdb4bd8bf2deeb5dd8a3275e51a7fdd4adf8b0dc1d9d26a4565d3ed6592",
+				ID:     "27e00689dfe0410b5b34758452f95d063d916c62ffdd28b1ab35995107696a48",
 				Sha256: "6288d2a89e2a9611191c25a45de20e94d8d058c75f274a39970d41f60f367e6f",
 			}
 
diff --git a/test/e2e/v2/manager/preheat.go b/test/e2e/v2/manager/preheat.go
index 582eb6b7..c312527e 100644
--- a/test/e2e/v2/manager/preheat.go
+++ b/test/e2e/v2/manager/preheat.go
@@ -64,7 +64,7 @@ var _ = Describe("Preheat with Manager", func() {
 			Expect(done).Should(BeTrue())
 
 			fileMetadata := util.FileMetadata{
-				ID:     "e8ef42dcc1e8da5e77b19bf39532f91f0bfeb85ed0d3ce277e1823f91c5a255a",
+				ID:     "6ba5a8781902368d2b07eb8b6d6044a96f49d5008feace1ea8e3ebfc0b96d0a1",
 				Sha256: "80f1d8cd843a98b23b30e90e7e43a14e05935351f354d678bc465f7be66ef3dd",
 			}
 
@@ -111,7 +111,7 @@ var _ = Describe("Preheat with Manager", func() {
 			Expect(done).Should(BeTrue())
 
 			fileMetadata := util.FileMetadata{
-				ID:     "bf3cd4dd9b582ac4a9253d28d38f0d2cb942455572a2a2d2fc9a82e1e83eda4f",
+				ID:     "f4d85d5d6db12bdcdee48a1f3ace8420756399bdfcbddd430b6b2330ad4c00df",
 				Sha256: "4c7f0f298ab3350859f90664d706b8ccaa95072f1f1f3dd74f559642e5483cd5",
 			}
 
@@ -158,7 +158,7 @@ var _ = Describe("Preheat with Manager", func() {
 			Expect(done).Should(BeTrue())
 
 			fileMetadata := util.FileMetadata{
-				ID:     "c6273a9e7140bc2af543fbb15e16186e8f07b054f7bfd1556dce5a76dba7dd28",
+				ID:     "bd2024e044b8b29dcfd930ae1eae9594c8d94f89cc6403303cf07c892c00db7d",
 				Sha256: "a1cbf1bf2d66757121677fd7fefafacd4f843a2cb44a451131002803bae56a65",
 			}
 
@@ -205,7 +205,7 @@ var _ = Describe("Preheat with Manager", func() {
 			Expect(done).Should(BeTrue())
 
 			fileMetadata := util.FileMetadata{
-				ID:     "b9615c0754d6e5dafe0b3b8b1aafc836635efd528a3815288646728c946a0469",
+				ID:     "039d6a3441cc8e47bf83d6bb504be958f6b08511d8c23afcb0dd8c266b23fa93",
 				Sha256: "5a963cbdd08df27651e9c9d006567267ebb3c80f7b8fc0f218ade5771df2998b",
 			}
 
@@ -251,11 +251,11 @@ var _ = Describe("Preheat with Manager", func() {
 
 			taskMetadatas := []util.TaskMetadata{
 				{
-					ID:     "22b576f99cff7676bdb10a4fdf1f1ae5163ccf9023d07d5f1be355a86c3e99e7",
+					ID:     "b32d9d9ab534cd803ae7ecf6655fe2e397edb6bc6e160d462d3d762ca4281150",
 					Sha256: "a711f05d33845e2e9deffcfcc5adf082d7c6e97e3e3a881d193d9aae38f092a8",
 				},
 				{
-					ID:     "3ef8cc79ebac6ad32b68e0ea4b0a863b808b72377e645d1d87c73d073aea18d8",
+					ID:     "21213381947bc939549355f00318f22c2f35fb3a907b79a145aab45f0a18aff7",
 					Sha256: "f643e116a03d9604c344edb345d7592c48cc00f2a4848aaf773411f4fb30d2f5",
 				},
 			}
@@ -305,23 +305,23 @@ var _ = Describe("Preheat with Manager", func() {
 
 			taskMetadatas := []util.TaskMetadata{
 				{
-					ID:     "db5beca8a19049e0420e4efa08983e6b22162c1192de39a363ed16ea6459ee28",
+					ID:     "f3d195d2de9da87385bd381258f436e163efaed266b3ff56eac7b89d40cacfb3",
 					Sha256: "f1f1039835051ecc04909f939530e86a20f02d2ce5ad7a81c0fa3616f7303944",
 				},
 				{
-					ID:     "b89495f24d34cae8e9174df15b60d34d490547d3029e3c187079cc3b475ff250",
+					ID:     "d5f00b6bdba48fdd8920ae419ca0a007b3e15ff93d0c10495da981aaea657ef0",
 					Sha256: "c1d6d1b2d5a367259e6e51a7f4d1ccd66a28cc9940d6599d8a8ea9544dd4b4a8",
 				},
 				{
-					ID:     "efc4e319971484d86cc43a48a9e3eccc23736cabc50ba4d1e707a841eaf42e12",
+					ID:     "5ae39f96a141d56d403f5098bcbefc13882ae3eeb1926d3c1fcfe8644f0ba7eb",
 					Sha256: "871ab018db94b4ae7b137764837bc4504393a60656ba187189e985cd809064f7",
 				},
 				{
-					ID:     "5ff373729cb097252966b0fad599bad4c87e0dc96bf77c65b91badc99d2f7e99",
+					ID:     "11b4932bf84ca19d80ef974d02f62b9d82bd42c1a7b9c2e5112097dbafcec601",
 					Sha256: "f1a1d290795d904815786e41d39a41dc1af5de68a9e9020baba8bd83b32d8f95",
 				},
 				{
-					ID:     "99e12b50d80a25090c7928fe3ce35ca97bd373c45fe90870b3b70884bf9c34c9",
+					ID:     "0d15761559736d2e40678c72f7df9f330328c13abdbc5e3aa4c027c17f42b1c6",
 					Sha256: "f1ffc4b5459e82dc8e7ddd1d1a2ec469e85a1f076090c22851a1f2ce6f71e1a6",
 				},
 			}
@@ -369,23 +369,23 @@ var _ = Describe("Preheat with Manager", func() {
 
 			taskMetadatas := []util.TaskMetadata{
 				{
-					ID:     "4fed91258f022c3f8eb8c0408e871bff653bf8015f9e9ec71bd03a2bb639119b",
+					ID:     "b742ff16c917a4559f1909a1f1bb1a8cf66d242344d33a8ef8ca4b5bfc588b6a",
 					Sha256: "a0d7a8f11f7e25ca59f0bf470187dd9aa27e7ca951cf67a53c750deea5d3b076",
 				},
 				{
-					ID:     "fb47239bde6b518227ccce5ed86b0b1570a9e42ba94ca72f99f5db640350e22a",
+					ID:     "3ed59c2363a552a8b3e9b1d4aed8efef18c7861678db52afd71db57ee238f317",
 					Sha256: "a880266d3b77f75696023df2da1ef66c3c565e0f70596242395c9e68de955c7c",
 				},
 				{
-					ID:     "efc4e319971484d86cc43a48a9e3eccc23736cabc50ba4d1e707a841eaf42e12",
+					ID:     "5ae39f96a141d56d403f5098bcbefc13882ae3eeb1926d3c1fcfe8644f0ba7eb",
 					Sha256: "871ab018db94b4ae7b137764837bc4504393a60656ba187189e985cd809064f7",
 				},
 				{
-					ID:     "7860f1bd9cc5eca105df4c40719351562f04f5f0bda7805c34ed475ddd66d778",
+					ID:     "7f83153778995fabe52d43913bc70cfe6e1f858e9450d93750903b9cbcd1007b",
 					Sha256: "9b5952218d7711195c6c6fbddbef2780507d20851ca68845d180397d1348f0d8",
 				},
 				{
-					ID:     "34be7b23dcbb09487133810e30c1e701a4285f742d4dbe6f6fda496014f90af6",
+					ID:     "9368993adbbee8e4eeedfbd9279c88c7ea8f6dfe9b6ff035eac5dc2bf351b706",
 					Sha256: "889f4c960ac4ff70774e9c4cfa64efc4823ade0702d0f96c20ff0054ffbbe504",
 				},
 			}
diff --git a/test/e2e/v2/proxy_test.go b/test/e2e/v2/proxy_test.go
index 7306c53c..bf2d2df2 100644
--- a/test/e2e/v2/proxy_test.go
+++ b/test/e2e/v2/proxy_test.go
@@ -39,7 +39,7 @@ var _ = Describe("Download Using Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "0ef882badaeb3195aed759a203cfb61951d158bf614f90ab0a20504fb7f97992",
+				ID:     "090278fc27871e8bb93c4546a0f44dd16126ed476a23bee7c4b0812357e2042b",
 				Sha256: "6288d2a89e2a9611191c25a45de20e94d8d058c75f274a39970d41f60f367e6f",
 			}
 
@@ -77,7 +77,7 @@ var _ = Describe("Download Using Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "e37fccc0c725a947c0a8856e2e1f6a14a4a5792338a73dcafa7e5ebd6443f7b4",
+				ID:     "80c17d9f21dcfd8b6f4526d131e65cd70dd0ad644033ea1900ea9a7deeed6dc3",
 				Sha256: "327b4022d0bfd1d5e9c0701d4a3f989a536f7e6e865e102dcd77c7e7adb31f9a",
 			}
 
@@ -115,7 +115,7 @@ var _ = Describe("Download Using Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "7c7cf5c8303626754ba4ae6575c1c96cd3fcad985687ec0d15744e68b15661d6",
+				ID:     "559fb82754b3cd804f75d4e9e58ae6cd9aba5c49e24e7f52891bee5c815ed2b8",
 				Sha256: "a1cbf1bf2d66757121677fd7fefafacd4f843a2cb44a451131002803bae56a65",
 			}
 
@@ -153,7 +153,7 @@ var _ = Describe("Download Using Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "297205e16a85e8cf803067c84fdd659c1877ff595e76e7633e4aa52b64321dee",
+				ID:     "c8e05b7c9ebae46268691292fd2905c2cb4250af12ce91e53750e16eec69ce5a",
 				Sha256: "b0cfe211f851049a78f5812cf5b1d7cb4f3fbb101c02c1865c940d5797f4b73b",
 			}
 
@@ -191,7 +191,7 @@ var _ = Describe("Download Using Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "b4df90b001f49adcc64d71f68b1c01ad462f631c94c7c7ffc12d97f351874da1",
+				ID:     "8a541eb07998f3980807ec1d183d74516bf6e2afe76d674e813ddca99938e02e",
 				Sha256: "c37f93c73cf2f303f874c094f6f76e47b2421a3da9f0e7e0b98bea8a3d685322",
 			}
 
@@ -229,7 +229,7 @@ var _ = Describe("Download Using Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "b56a0807131865baffe2d687440f121f40cf2071c478a5abfb0930bc57b7e715",
+				ID:     "ef524d1361ee2c0f0b0a457f1d5e605b3fe4f3dd2fd131950004bb20fa83d6fa",
 				Sha256: "cd00e292c5970d3c5e2f0ffa5171e555bc46bfc4faddfb4a418b6840b86e79a3",
 			}
 
@@ -267,7 +267,7 @@ var _ = Describe("Download Using Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "0091f6a0373fe02d2e4cf6a83904889f5326a3590239015743bc812b02c51408",
+				ID:     "d22bb2076dc27f0f0be5d3ecc1e95a63ea516ce5dff49d235cf2266e98625474",
 				Sha256: "7bbfcb694f6acc69483751d3b48d5bdbdcb284f9e04c7b7caa04b5977cffddc8",
 			}
 
@@ -305,7 +305,7 @@ var _ = Describe("Download Using Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "28ded7113a871c1eb08728204810514f08e200952131075ea5f7a3756973ceb2",
+				ID:     "f58775d042d37c406dbe03a294446e994f183e5872e93477025ad049f62a0a85",
 				Sha256: "ba9a10ceceb80562fc124dc9bc94ea2a38e3a71e3e746e2140e6381ac791cdeb",
 			}
 
@@ -343,7 +343,7 @@ var _ = Describe("Download Using Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "871b9e11903e7f3cadcb25706be7fd2c153b76cdf138f713bd7b506f695fc863",
+				ID:     "6353c7c65066bf24acdfe62601ba17a1636d217169e79f7ea3f2ebf7f0940e06",
 				Sha256: "ba9a10ceceb80562fc124dc9bc94ea2a38e3a71e3e746e2140e6381ac791cdeb",
 			}
 
@@ -381,7 +381,7 @@ var _ = Describe("Download Using Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "28ded7113a871c1eb08728204810514f08e200952131075ea5f7a3756973ceb2",
+				ID:     "1ff704a22e421b2f9b99f7f8e2228e6f71d9c987ef242348acc031d003d3e941",
 				Sha256: "327b4022d0bfd1d5e9c0701d4a3f989a536f7e6e865e102dcd77c7e7adb31f9a",
 			}
 
@@ -419,7 +419,7 @@ var _ = Describe("Download Using Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "e5ccafcd80ee0dfc48aa1f313ef6086a1fd1e0021183452c096ae40d87d191c6",
+				ID:     "dba445f5310c2a63fabeaad075511357e411b74f68a47bc579ed36f78a380013",
 				Sha256: "8732360b941ad09a5e0e5d5f9891118bc068f6d0d5a56e3c6d483e4600fbc43f",
 			}
 
@@ -457,7 +457,7 @@ var _ = Describe("Download Using Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "16d94182383e84a73f9c85a28a25d781a8a4e56ec37c6e3e61d1f946fb236e85",
+				ID:     "ae82ec86b58e7a91853ce6a3d52a59a1d590365a91b30db57df922bd8a6bc952",
 				Sha256: "d6d17dca18b8de59e38da525dc24c47b74fec1a790a9f64afdd6538f4f8fa90e",
 			}
 
@@ -497,7 +497,7 @@ var _ = Describe("Download Using Prefetch Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "0fa5f40dfccfcd4c20b2d2dba0bab7205bfced189cc7a013919a6d155d841dab",
+				ID:     "4a4df08f3aa3311e29556582de4269294a6805f81b7d8d38b83e8a91bc461d4e",
 				Sha256: "6288d2a89e2a9611191c25a45de20e94d8d058c75f274a39970d41f60f367e6f",
 			}
 
@@ -523,7 +523,7 @@ var _ = Describe("Download Using Prefetch Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "8cdfeba7c8858b1bf7dc6097aeb6bae12e3a4cb8ed32cc3b60bdb45765bda590",
+				ID:     "3496028e92e0e35651f92e86ffde1dfa3c03a66265d248f8d3254ac78d30ef83",
 				Sha256: "327b4022d0bfd1d5e9c0701d4a3f989a536f7e6e865e102dcd77c7e7adb31f9a",
 			}
 
@@ -549,7 +549,7 @@ var _ = Describe("Download Using Prefetch Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "86b0c4424368f35e500045d5375b8b53940cadf69b71d0ae4b349ac972ad6bdb",
+				ID:     "91ae78d5302e267bd245bae82c6ab90e18a8a4234bb87642f108901e801a1e2a",
 				Sha256: "a1cbf1bf2d66757121677fd7fefafacd4f843a2cb44a451131002803bae56a65",
 			}
 
@@ -575,7 +575,7 @@ var _ = Describe("Download Using Prefetch Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "d759035bb589e9334717660701c58ef91ebab49bb5790367ede36bf78daa52a1",
+				ID:     "d2ccf9401074d729a88359394f1d9b4888ee6b7d9e4045e49bf1fa8d7caaf1d7",
 				Sha256: "b0cfe211f851049a78f5812cf5b1d7cb4f3fbb101c02c1865c940d5797f4b73b",
 			}
 
@@ -601,7 +601,7 @@ var _ = Describe("Download Using Prefetch Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "ecd74f0e4f9ff453e3c165934d473ef6946b088fecabb8a2eb7d11d2948f743c",
+				ID:     "a8a7a947d233ce5298c937c7e3cb52321810533d89c526c751b71a2dd91bc908",
 				Sha256: "c37f93c73cf2f303f874c094f6f76e47b2421a3da9f0e7e0b98bea8a3d685322",
 			}
 
@@ -627,7 +627,7 @@ var _ = Describe("Download Using Prefetch Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "2d9e6ebe90a230ff5ffad7938163456c308e072e910eac3dd063f64f62112f05",
+				ID:     "cbc6213119267fb7437947a971673a6a3eb65d3b972eac55b227104a4069f32c",
 				Sha256: "cd00e292c5970d3c5e2f0ffa5171e555bc46bfc4faddfb4a418b6840b86e79a3",
 			}
 
@@ -655,7 +655,7 @@ var _ = Describe("Download Using Prefetch Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "bd969c992e6faff240ac1601afe07bdeaa64c2b75bd5abb36a1fd6601895c542",
+				ID:     "ab59a8e67be5672729f97ecd6c9824561ab6e77652d59ea4e7b6eaf18a5a443e",
 				Sha256: "7bbfcb694f6acc69483751d3b48d5bdbdcb284f9e04c7b7caa04b5977cffddc8",
 			}
 
@@ -682,7 +682,7 @@ var _ = Describe("Download Using Prefetch Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "a58f439c45c5737613f1c1d4f10b57c06239b675fccdc32a3d078af89d2bd870",
+				ID:     "235c7f0377f3cea69659756c883243fd071ffb527c38d6abb407bf428ecc6489",
 				Sha256: "ba9a10ceceb80562fc124dc9bc94ea2a38e3a71e3e746e2140e6381ac791cdeb",
 			}
 
@@ -709,7 +709,7 @@ var _ = Describe("Download Using Prefetch Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "ba4b4a0a1be91ab6b2a76f99bbd8eac5977c388cfc7de73707d30e5d5cf0a6d4",
+				ID:     "5135a54f35215fcbdfcea61313bc746ee4d2112781e7b346967aa53e3d266377",
 				Sha256: "ba9a10ceceb80562fc124dc9bc94ea2a38e3a71e3e746e2140e6381ac791cdeb",
 			}
 
@@ -736,7 +736,7 @@ var _ = Describe("Download Using Prefetch Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "66b8f945a2906550194aefee5a6da6c3a4c60b533e30340707c8bea67ce35eae",
+				ID:     "c573851cdcabc1d5f7344c576ff67bdfe3f63f65b49e08942f24c15a1808a027",
 				Sha256: "327b4022d0bfd1d5e9c0701d4a3f989a536f7e6e865e102dcd77c7e7adb31f9a",
 			}
 
@@ -763,7 +763,7 @@ var _ = Describe("Download Using Prefetch Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "5cfbab580dd42ef5c3a4d28488fde7e82220115dffc8aff01c0c568665405bcb",
+				ID:     "cc826acc16c2ab33525874eb66baddb180709b33380983d489e510d6674ef6bb",
 				Sha256: "8732360b941ad09a5e0e5d5f9891118bc068f6d0d5a56e3c6d483e4600fbc43f",
 			}
 
@@ -790,7 +790,7 @@ var _ = Describe("Download Using Prefetch Proxy", func() {
 			fmt.Println(string(out))
 
 			fileMetadata := util.FileMetadata{
-				ID:     "e376250edb769e967fe48bdd05d50f4124f89f3db367b0eee9850128c93043d7",
+				ID:     "60645e89632f754c704450108e2d188f7496cb63bb6055a5b1bf5c71f29d0b3a",
 				Sha256: "d6d17dca18b8de59e38da525dc24c47b74fec1a790a9f64afdd6538f4f8fa90e",
 			}