1
0
mirror of https://github.com/sredevopsorg/deepseek-kubernetes-sandbox.git synced 2026-11-03 01:13:24 +00:00
Files
deepseek-kubernetes-sandbox/examples
SREDevOps.org Agent cbcc56f97e fix(gateway): answer client-aborted requests with 499, not a traceback (#32)
* fix(gateway): answer client-aborted requests with 499, not a traceback

A browser reload, back navigation or proxy timeout can abort a request while
its body is still arriving. Starlette then raises ClientDisconnect from
request.stream(); nothing caught it, so ServerErrorMiddleware logged a full
ERROR traceback per aborted request and buried real faults. The request never
reaches DSH (the body is buffered before the upstream send) and the peer can
no longer be answered, so this is not an error.

- Register a ClientDisconnect exception handler that answers 499
  (CLIENT_CLOSED_REQUEST). One handler covers the proxy and the body-reading
  control routes (signup, login). A request already streaming keeps its
  upstream status because the response has started.
- Make _release await-free, and reach it even when the upstream close is
  cancelled. CancelledError is a BaseException, so suppress(Exception) around
  upstream.aclose() skipped the release and stranded the in-flight slot,
  leaving that user's sandbox looking busy forever (the idle sweeper then
  never suspends it).
- Add raw-ASGI regression tests: mid-body abort on the proxy and on signup,
  mid-stream abort, a cancelled release, and a cancelled upstream close.
- Document the 499 semantics in the gateway README failure table and the
  architecture failure modes.

Verified: make check, make test (114 passed), make lint. Against the pinned
uvicorn 0.54 the abort reproduces the original traceback before the fix and
logs no traceback after it.

* chore(deps): bump gateway starlette to 1.10.0 and ruff to 0.17.2

Absorbs Dependabot PR #27 against current main: that branch predates the
dsh-v0.2.1-rc.5 changelog/release commits, so merging it as-is would have
reverted them.

starlette 1.10.0 reworks URL-encoded form parsing (fields are built in the
parser callbacks, and the last field is kept when the stream ends without an
empty chunk) and clears tracebacks of handled exceptions. The gateway reads
JSON and form bodies, so the existing suite exercises signup/login forms and
the 499 client-abort path against the new release. ruff 0.17.2 only adds
preview and fix-safety changes; the configured rule set reports nothing new.

Verified: make check, make test (114 passed), make lint, make gateway (image
builds on python:3.12-slim and imports starlette 1.10.0), plus a direct ASGI
abort probe under 1.10.0 (499, in-flight slot released, nothing forwarded).

---------

Co-authored-by: SREDevOpsAgents <agents@sredevops.org>
2026-10-30 07:14:49 -03:00
..

Examples

Every implementation in this repository is a self-contained example: one directory, plain kubectl, an end-to-end README, and a cleanup command. Examples consume the main DSH Web image; they are reference material, not libraries.

Example What it demonstrates Needs
examples/dsh-agents-as-a-service/ The full multi-tenant platform pattern: one SandboxTemplate with per-user PVCs, a warm pool, one ~10-line SandboxClaim per user, suspend-when-idle / wake-on-return, and a browser gateway with signup, HttpOnly sessions, an HTTP + WebSocket proxy and two exposure variants (Ingress, or Gateway API + GitHub SSO). agent-sandbox with extensions; kind for the e2e script.
examples/minimal-single-tenant/ The smallest useful setup: a single SandboxTemplate and one SandboxClaim, no gateway — reach DSH Web with a launch-token URL through kubectl port-forward. agent-sandbox with extensions.

The multi-tenant example also documents opt-in gVisor, nodeSelector, NetworkPolicy and extra provider-key hardening in optional hardening.

The example contract (short version)

Full rules: docs/examples.md. scripts/check-examples.sh enforces the layout, and make check runs it.

examples/<name>/
+-- README.md                  # walkthrough: prerequisites, steps, troubleshooting, cleanup
+-- manifests/                 # NN-*.yaml, applied with plain kubectl
|   +-- optional/<feature>/    # optional opt-in manifests...
|   +-- optional/README.md     # ...required whenever optional/ exists
|   +-- exposure/<variant>/    # optional per-variant manifests...
|   +-- exposure/README.md     # ...required whenever exposure/ exists
+-- scripts/                   # optional executable, idempotent, self-cleaning *.sh
+-- docs/                      # optional architecture/ADR material
+-- <component>/               # optional component with Dockerfile + README + tests
  • Secrets never ship populated: use *.yaml.example files with placeholders.
  • Manifests are numbered (00-, 10-, ...) and read as an ordered walkthrough.
  • Component images are published nested below the main image: <registry>/<owner>/<repo>/<example>/<component>.
  • Every example must be listed above with its literal examples/<name>/ path.
  • Scripts under scripts/ must be executable, idempotent and clean up after themselves.

Running an example

# e.g. the multi-tenant platform example
kubectl apply -f examples/dsh-agents-as-a-service/manifests/

# or run the whole walkthrough (kind + agent-sandbox required) and let it clean up
examples/dsh-agents-as-a-service/scripts/e2e-kind.sh

kubectl apply -f manifests/ is non-recursive: optional/ and exposure/ subdirectories are applied explicitly. Each example README has the exact prerequisites, optional hardening, exposure options and teardown.