Repository navigation
router: reuse signed sandbox JWTs for a session - #479
Conversation
Benchmark handleInvoke end to end (session lookup, preflight dial, JWT signing, reverse proxy) against an in-process upstream, for the SandboxClaim kind that signs a JWT and the CodeInterpreter kind that does not. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: manaspros <manasnandchoudhary@gmail.com>
generateSandboxJWT signed a new RS256 token on every request. With RSA-2048 that is about 0.55 ms of CPU, roughly ten times the rest of the invoke path. Cache the token per (session, user sub, user email) and sign again once it is older than half its 5 minute lifetime. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Signed-off-by: manaspros <manasnandchoudhary@gmail.com>
|
Welcome @manaspros! It looks like this is your first PR to volcano-sh/agentcube 🎉 |
|
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## main #479 +/- ##
==========================================
+ Coverage 59.98% 61.46% +1.47%
==========================================
Files 36 35 -1
Lines 3589 3659 +70
==========================================
+ Hits 2153 2249 +96
+ Misses 1216 1185 -31
- Partials 220 225 +5
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
a good reuse practice |
Replace GenerateTokenCached(key, claims) with GenerateSandboxToken(sessionID, caller). It builds the cache key and the claims together, so they cannot get out of sync, and the handler no longer has to know about the cache key. RS256 is deterministic, so comparing two tokens signed in the same second did not prove that the cache was used. The tests now swap the signing key between calls and check which key the token verifies with. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: manaspros <manasnandchoudhary@gmail.com>
|
pushed the fix for both of acsoto's review comments (commit 165d36d). The reuse tests now fail when the cache is off, and the key and claims are built in one place. |
k8s.io/utils/lru already locks on every call. The cache is now created once in NewJWTManager and emptied with Clear() when a private key is loaded, instead of being replaced. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: manaspros <manasnandchoudhary@gmail.com>
|
/lgtm |
|
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: acsoto The full list of commands accepted by this bot can be found here. The pull request process is described here DetailsNeeds approval from an approver in each of these files:
Approvers can indicate their approval by writing |
|
You're right, the LRU already locks internally. Removed the mutex in 5c0b32e: the cache is now created once in NewJWTManager, and loading a key calls Clear() instead of replacing it. go test -race ./pkg/router passes. |
What type of PR is this?
/kind enhancement
What this PR does / why we need it:
The router signed a new RS256 JWT on every request to a
SandboxorSandboxClaimsession. With RSA-2048 that's about 0.55 ms of CPU per request, roughly ten times the rest of the invoke path.This PR caches the signed token in
JWTManager.GenerateTokenCached:generateSandboxJWTputs in the token.k8s.io/utils/lruwith 4096 entries (already a dependency), behind one mutex.loadPrivateKeyPEMclears it, so a token signed with an old key is never handed out.There are two commits. The first only adds the benchmark, so you can check it out to reproduce the "before" numbers.
CodeInterpreterdoesn't sign, so it's the control and doesn't change. Its "before" run had one slow outlier. The same code measured 48.10µ ± 4% in a separate 10-run sample. Machine: AMD Ryzen 9 9900X, Go 1.27.1, Linux.I use
-benchtime=1000xbecause of the per-request preflight dial: with the default benchtime the run exhausts ephemeral ports (TIME_WAIT) and requests start failing. That's a separate thing, not touched here.Which issue(s) this PR fixes:
Fixes #478
Special notes for your reviewer:
The behaviour change to look at: a sandbox can now get the same token on several requests within 2.5 minutes. picod checks signature,
expandiat(pkg/picod/auth.go) and has nojtior nonce check, so I don't think anything relies on a fresh token.Tests:
TestGenerateTokenCachedcovers reuse, a different key, expiry, key swap, a zero-value manager and concurrent use. There's also a handler-level test.go test -race ./pkg/...passes.Lint:
make lintdoesn't run as is. The Makefile pins golangci-lint v1.64.1 but.golangci.ymlis a v2 config. I ran v2.15 with an equivalent config. There are no new findings in non-test code. The new tests only addgoconstrepeats, same as the existing tests.Not tested: a real cluster, real network latency, Redis, concurrent load.
AI use: I used Claude Code (Claude Sonnet 5.5 and Claude Opus 5.5) to find this and draft the code, benchmark and tests. I've read and run all of it and can explain each line.
Does this PR introduce a user-facing change?: