Fix TUS chunked upload and resume failures (#8783) (#8786)

* Fix TUS chunked upload and resume failures caused by request context cancellation (#8783)

The filer's TCP connections use a 10-second inactivity timeout (net_timeout.go).
After the TUS PATCH request body is fully consumed, internal operations (assigning
file IDs via gRPC to the master, uploading data to volume servers, completing uploads)
do not generate any activity on the client connection, so the inactivity timer fires
and Go's HTTP server cancels the request context. This caused HTTP 500 errors on
PATCH requests where body reading + internal processing exceeded the timeout.

Fix by using context.WithoutCancel in TUS create and patch handlers, matching the
existing pattern used by assignNewFileInfo. This ensures internal operations complete
regardless of client connection state.

Fixes seaweedfs/seaweedfs#8783

* Add comment to tusCreateHandler explaining context.WithoutCancel rationale

* Run TUS integration tests on all PRs, not just TUS file changes

The previous path filter meant these tests only ran when TUS-specific files
changed. This allowed regressions from changes to shared infrastructure
(net_timeout.go, upload paths, gRPC) to go undetected — which is exactly
how the context cancellation bug in #8783 was missed. Matches the pattern
used by s3-go-tests.yml.
This commit is contained in:
Chris Lu
2026-03-26 14:06:21 -07:00
committed by GitHub
parent 77e4b92432
commit 3a3fff1399
2 changed files with 9 additions and 13 deletions

View File

@@ -2,17 +2,6 @@ name: "TUS Protocol Tests"
on:
pull_request:
paths:
- 'weed/server/filer_server_tus*.go'
- 'weed/server/filer_server.go'
- 'test/tus/**'
- '.github/workflows/tus-tests.yml'
push:
branches: [ master, main ]
paths:
- 'weed/server/filer_server_tus*.go'
- 'weed/server/filer_server.go'
- 'test/tus/**'
concurrency:
group: ${{ github.head_ref || github.ref }}/tus-tests

View File

@@ -80,7 +80,10 @@ func (fs *FilerServer) tusOptionsHandler(w http.ResponseWriter, r *http.Request)
// tusCreateHandler handles POST requests to create new uploads
func (fs *FilerServer) tusCreateHandler(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
// Use a context that ignores cancellation from the request context.
// Internal operations (creating TUS session, writing data, completing uploads)
// may exceed the filer's client connection inactivity timeout.
ctx := context.WithoutCancel(r.Context())
// Parse Upload-Length header (required)
uploadLengthStr := r.Header.Get("Upload-Length")
@@ -195,7 +198,11 @@ func (fs *FilerServer) tusHeadHandler(w http.ResponseWriter, r *http.Request, up
// tusPatchHandler handles PATCH requests to upload data
func (fs *FilerServer) tusPatchHandler(w http.ResponseWriter, r *http.Request, uploadID string) {
ctx := r.Context()
// Use a context that ignores cancellation from the request context.
// The filer's connection has an inactivity timeout: after the request body is fully read,
// internal operations (assigning file IDs, uploading to volume servers, completing uploads)
// may exceed the timeout, causing the request context to be canceled.
ctx := context.WithoutCancel(r.Context())
// Validate Content-Type
contentType := r.Header.Get("Content-Type")