Skip to content

EAI-7650: Set explicit request timeout on SeaweedFS S3 route - #800

Open
nowycondro wants to merge 3 commits into
mainfrom
EAI-7650-fix-seaweed-s3-route-timeout
Open

EAI-7650: Set explicit request timeout on SeaweedFS S3 route#800
nowycondro wants to merge 3 commits into
mainfrom
EAI-7650-fix-seaweed-s3-route-timeout

Conversation

@nowycondro

@nowycondro nowycondro commented Aug 6, 2026

Copy link
Copy Markdown

Summary

The seaweed HTTPRoute declares no timeouts, so Envoy applies its 15 second default request timeout to the SeaweedFS S3 data path. Any transfer lasting longer than 15s is reset mid-stream.

The limit is duration, not size, which is why it doesn't show up as a body-size setting anywhere. On a slow client link even a modest object fails.

Evidence

Measured against app-dev using the same 26 MB object and the same presigned URL, varying only transfer speed:

Speed Duration Result
unthrottled 5.4s 26,139,600 bytes, complete
2.5 MB/s 9.5s 26,139,600 bytes, complete
1.2 MB/s cut at ~15s truncated at 23,330,816 bytes
800 KB/s cut at ~15s truncated at 14,172,160 bytes

Failures surface as HTTP/2 stream not closed cleanly: INTERNAL_ERROR. Note the response begins as HTTP 200 and the stream resets afterwards, so clients see a truncated object rather than a clean error — a silent corruption risk for anything that doesn't verify length or checksum.

Confirmed from the live Envoy config dump that the route's timeout field is unset, while routes that need longer already set one explicitly (aiwb-api-route runs at 10m/30m, AIM routes at 1800s). This route was simply left at the default.

Change

Sets request and backendRequest on the S3 route, defaulting to 30m and read from s3Route.timeouts in values so each cluster can retune it from its own values repo without patching the chart. The seaweed-admin route is left untouched.

The knob sits at a top-level s3Route rather than inside seaweed, because seaweedfs-seaweed.yaml wraps that block in {{- with .Values.seaweed }} and maps it 1:1 onto the Seaweed CR — a route timeout is not part of that CR. The shape mirrors the existing kgateway.aiwbapi.timeouts convention in aiwb-api.

Test plan

  • helm template sources/seaweedfs-config renders the expected timeouts block
  • helm lint clean; default renders 30m, and --set s3Route.timeouts.request=2m overrides it
  • kubectl apply --dry-run=server accepts the manifest, validating the 30m duration format against the Gateway API schema
  • After sync, re-run a throttled transfer that exceeds 15s and confirm it completes

Context

This unblocks adapter artifact uploads in AIWB (EAI-7650), where users upload LoRA adapter files directly to storage through a presigned URL. Without this, those uploads fail for anyone whose connection can't finish inside 15 seconds.

The seaweed HTTPRoute declared no timeouts, so Envoy applied its 15s default
request timeout to the S3 data path. Transfers longer than 15s were reset
mid-stream, truncating objects regardless of their size.

Co-authored-by: Cursor <cursoragent@cursor.com>
@nowycondro
nowycondro requested a review from a team as a code owner August 6, 2026 08:12
@nowycondro
nowycondro requested a lite review from Copilot August 6, 2026 09:07

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Updates the SeaweedFS S3 HTTPRoute to explicitly set longer Gateway API timeouts so Envoy doesn’t apply its 15s default request timeout and reset long-running object transfers mid-stream.

Changes:

  • Add timeouts.request and timeouts.backendRequest set to 30m on the seaweed HTTPRoute rule.
  • Document the rationale inline (duration-based timeout causing truncated objects on slow links).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@brownzebra brownzebra left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is 15 sec -> 30 minutes really the amount to change? would 1m not be enough?

Instead of hardcoding in the template, I suggest to parametrize it into values and allow for a gitea override.

@brownzebra

Copy link
Copy Markdown
Contributor

OK, so it is based on the whole transfer... would still be nice to have it templated so it could be tuned in the field.

The timeout was hardcoded in the template, so a cluster hitting a
different transfer profile had no way to retune it. Move it to values
under s3Route.timeouts, matching the aiwb-api route convention, so it
can be overridden per cluster from the gitea values repo.
@nowycondro

Copy link
Copy Markdown
Author

Parametrized in be1b708 — the timeout now comes from values:

s3Route:
  timeouts:
    request: 30m
    backendRequest: 30m

with the template reading .Values.s3Route.timeouts.{request,backendRequest}. That shape matches what aiwb-api already does (kgateway.aiwbapi.timeouts), and since cluster-apps.yaml passes valuesObject/helmParameters through to every app, a cluster can retune it from its own values repo without touching this chart.

Put it under a top-level s3Route rather than inside seaweed because seaweedfs-seaweed.yaml wraps that block in {{- with .Values.seaweed }} and maps it straight onto the Seaweed CR — a route timeout isn't part of that CR.

Kept the default at 30m per the transfer-duration point above. The rationale comment moved to values.yaml, next to the knob rather than in the template.

Verified helm lint clean, renders 30m by default and honours --set s3Route.timeouts.request=2m. The remaining test-plan item — a throttled >15s transfer after sync — still needs a cluster.

@nowycondro
nowycondro requested a review from brownzebra August 13, 2026 12:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants