Skip to content

kthena-router: order boosted requests by session completion time#1334

Open
YaoZengzeng wants to merge 5 commits into
volcano-sh:mainfrom
YaoZengzeng:feat/session-boost-newest-first
Open

kthena-router: order boosted requests by session completion time#1334
YaoZengzeng wants to merge 5 commits into
volcano-sh:mainfrom
YaoZengzeng:feat/session-boost-newest-first

Conversation

@YaoZengzeng

@YaoZengzeng YaoZengzeng commented Jul 10, 2026

Copy link
Copy Markdown
Member

What type of PR is this?

/kind enhancement

What this PR does / why we need it:

In session-boost mode the per-model priority queue orders boosted requests
(follow-up turns of a recently-completed conversation) ahead of all non-boosted
traffic. This PR improves how boosted requests are ordered relative to each
other
so that prefix-cache reuse is maximized without starving any request.

Boosted requests are now ordered by their session's completion time: the
session whose previous turn completed most recently is served first, because its
prefix (KV) cache is the most likely to still be warm on the backend. Ordering
depends only on how recently the session's last turn finished, not on when the
follow-up request arrived; ties are broken FIFO by arrival time.

Why completion time rather than a plain LIFO on arrival:

  • A session's completion time is fixed once its turn finishes, so a waiting
    boosted request cannot be perpetually pushed back by a stream of newer
    arrivals. Plain LIFO has no such bound and can starve an older boosted request.
  • It targets the signal we actually care about (cache warmth) directly, and it
    degrades gracefully: once a session's cache is likely cold it also ages out of
    the tracker's LRU, so it stops competing for the head.
  • Boosted requests still always outrank non-boosted ones, and non-boosted
    requests keep FIFO ordering, so a follow-up turn is always prioritized over
    unrelated traffic.

Changes:

  • session_boost_queue.go: SessionTracker stores each session's completion
    timestamp (LRU value) and exposes CompletionTime.
  • fairness_queue.go: new Request.SessionCompletedAt; Less orders boosted
    requests by most-recent completion time (FIFO tiebreak); PushRequest
    captures the completion time when boosting.
  • session_boost_queue_test.go: updated expectations and a new
    TestSessionBoostQueue_OrderedByCompletionTime that distinguishes
    completion-time ordering from both FIFO and LIFO.
  • Docs: session-boost.md (user guide) and session-boost-strategy.md
    (proposal) updated to describe completion-time ordering.

Which issue(s) this PR fixes:
Fixes #

Special notes for your reviewer:

Unit tests in pkg/kthena-router/datastore pass locally (go test ./pkg/kthena-router/datastore/...).

This PR was prepared with AI assistance; I have reviewed and understand every change.

Does this PR introduce a user-facing change?:

kthena-router: in session-boost mode, boosted requests are ordered by their session's completion time (most recently completed first) to maximize prefix-cache reuse while avoiding starvation of older boosted requests.

In session-boost mode, boosted requests were dequeued FIFO among
themselves. Change the ordering so the most-recently-arrived boosted
request wins (LIFO): a freshly boosted follow-up always jumps to the
head of the queue so it reuses the still-warm prefix cache before
earlier boosted requests. Non-boosted requests keep FIFO ordering, and
boosted requests still outrank non-boosted ones.

Also remove the grace-period 'head already boosted' fast path so the
freed slot is held for the full grace window, allowing a still-newer
same-session follow-up to arrive and take the head.

Docs updated accordingly.

Signed-off-by: YaoZengzeng <yaozengzeng@huawei.com>
Copilot AI review requested due to automatic review settings July 10, 2026 06:36
@volcano-sh-bot volcano-sh-bot added the kind/enhancement New feature or request label Jul 10, 2026
@volcano-sh-bot

Copy link
Copy Markdown
Contributor

[APPROVALNOTIFIER] This PR is NOT APPROVED

This pull-request has been approved by:
Once this PR has been reviewed and has the lgtm label, please ask for approval from yaozengzeng. For more information see the Kubernetes Code Review Process.

The full list of commands accepted by this bot can be found here.

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@gemini-code-assist gemini-code-assist Bot 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.

Code Review

This pull request updates the session boost queue scheduling strategy to prioritize the most recently arrived boosted requests (LIFO) rather than serving them in FIFO order, maximizing prefix cache hits. Additionally, it removes the fast path that skipped the grace period when a boosted request was already at the head of the queue, ensuring the queue always waits for the full grace window for potential newer same-session follow-ups. These changes are reflected in the documentation, core queue logic, and unit tests. I have no feedback to provide as there are no review comments.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

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 kthena-router per-model queue’s session-boost behavior to prioritize the most recently arrived boosted request (LIFO within the boosted group), improving the likelihood of reusing warm prefix (KV) cache for same-session follow-ups. It also adjusts the grace-period behavior and documentation to match the intended scheduling semantics.

Changes:

  • Change session-boost queue ordering so boosted requests are newest-first (LIFO) while non-boosted remain FIFO.
  • Remove the “head already boosted” grace fast path so the full grace window is always honored (when enabled).
  • Update unit tests and docs to reflect the new ordering and grace behavior.

Reviewed changes

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
pkg/kthena-router/datastore/session_boost_queue.go Removes the grace fast path and updates grace behavior documentation in code comments.
pkg/kthena-router/datastore/session_boost_queue_test.go Updates assertions to expect newest-first ordering among boosted requests.
pkg/kthena-router/datastore/fairness_queue.go Adjusts heap ordering in session-boost mode to prefer newer boosted requests.
docs/proposal/session-boost-strategy.md Updates proposal to describe newest-first boosted ordering and no grace fast path.
docs/kthena/docs/user-guide/session-boost.md Updates user guide to describe newest-first boosted ordering and full grace behavior.

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

Comment thread docs/proposal/session-boost-strategy.md Outdated
Comment on lines +179 to +181
1. A request finishes → `Release()` runs → `inflightCount` is decremented → a signal is sent on `releaseCh`.
2. The freed slot would normally be claimed immediately by the current heap head (which may be an unrelated, non-boosted request). The grace wait instead **holds that just-freed slot for up to `SessionBoostGracePeriod`**, betting that a same-session follow-up is about to arrive and reuse the warm prefix cache.
3. When the wait resolves, `tryBackpressureDequeue` runs and re-checks **both** capacity gates before admitting anyone. A boosted follow-up that arrived during grace is admitted first because boosted requests outrank others in the heap, and only when `inflight < MaxConcurrent` **and** at least one backend pod reports capacity.
3. When the wait resolves, `tryBackpressureDequeue` runs and re-checks **both** capacity gates before admitting anyone. A boosted follow-up that arrived during grace is admitted first because boosted requests outrank others in the heap and, among boosted requests, the most-recently-arrived one is at the head — and only when `inflight < MaxConcurrent` **and** at least one backend pod reports capacity.
Replace the LIFO-by-arrival ordering of boosted requests with an
ordering based on each session's completion time: the session whose
previous turn completed most recently is served first, because its
prefix (KV) cache is the most likely to still be warm on the backend.

Unlike plain LIFO, a session's completion time is fixed once its turn
finishes, so a waiting boosted request cannot be starved by a stream of
newer arrivals. Boosted requests still always outrank non-boosted ones,
and non-boosted requests keep FIFO ordering.

SessionTracker now stores the completion timestamp per session (LRU
value) and exposes CompletionTime; PushRequest captures it into the new
Request.SessionCompletedAt field used by Less.

Signed-off-by: YaoZengzeng <yaozengzeng@huawei.com>
Copilot AI review requested due to automatic review settings July 10, 2026 07:43
@YaoZengzeng YaoZengzeng changed the title kthena-router: boost newest same-session request to queue head kthena-router: order boosted requests by session completion time Jul 10, 2026

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

Copilot reviewed 5 out of 5 changed files in this pull request and generated 2 comments.

Comment on lines +167 to +171
│ │ first and, among boosted, the
│ │ newest-arrived wins, so a
│ │ same-session follow-up that
│ │ arrived during the window is
│ │ dequeued first automatically.
Comment on lines +247 to +249
q.MarkSessionRequestCompleted("conv-A")
q.MarkSessionRequestCompleted("conv-B")
q.MarkSessionRequestCompleted("conv-C")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

fixed

@YaoZengzeng

Copy link
Copy Markdown
Member Author

@hzxuzhonghu ptal

// SessionCompletedAt is the time the session's previous turn completed, captured
// when the request is boosted. Boosted requests are ordered by this timestamp
// (most recent first) so the session with the warmest prefix cache runs first.
SessionCompletedAt time.Time

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The name is a little confusing.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

renamed to LastTurnCompletedAt

Comment on lines +247 to +249
q.MarkSessionRequestCompleted("conv-A")
q.MarkSessionRequestCompleted("conv-B")
q.MarkSessionRequestCompleted("conv-C")

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Address review feedback: SessionCompletedAt could be read as the whole
session ending. The field is the completion time of the session's previous
turn, so rename it to LastTurnCompletedAt for clarity.

Signed-off-by: YaoZengzeng <yaozengzeng@huawei.com>
Copilot AI review requested due to automatic review settings July 10, 2026 09:35

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

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Comment on lines +220 to 224
// Among boosted: the session that completed most recently wins. conv-B was
// marked completed after conv-A, so boost-B (u3) is dequeued before boost-A (u2).
if first.UserID != "u3" {
t.Errorf("Expected boost-B first (most recently completed session), got %s", first.UserID)
}
Comment on lines +246 to +249
// Completion order: conv-A, then conv-B, then conv-C (conv-C most recent).
q.MarkSessionRequestCompleted("conv-A")
q.MarkSessionRequestCompleted("conv-B")
q.MarkSessionRequestCompleted("conv-C")
Comment on lines +167 to +171
│ │ first and, among boosted, the
│ │ newest-arrived wins, so a
│ │ same-session follow-up that
│ │ arrived during the window is
│ │ dequeued first automatically.
Comment on lines +187 to +189
| Outcome | Trigger | What happens next |
| ----------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Grace expires** | The timer fires (`timer.C`). | Stop holding the slot and fall through to the capacity gates, which admit the heap head. If a same-session follow-up arrived during the wait it is now boosted and sits at the head (session with the most recent completion first), so it wins automatically (subject to inflight + backend capacity). |
The completion-time ordering tests relied on consecutive MarkRequestCompleted
calls producing strictly increasing time.Now() values. On a coarse clock or
under fast execution two completions could share an instant, making the boosted
ordering fall back to RequestTime and the expected order nondeterministic.

Inject an overridable clock into SessionTracker (defaults to time.Now) and use
it in the tests to assign strictly distinct completion timestamps, removing the
flake without arbitrary sleeps.

Signed-off-by: YaoZengzeng <yaozengzeng@huawei.com>
Copilot AI review requested due to automatic review settings July 10, 2026 09:41

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

Copilot reviewed 5 out of 5 changed files in this pull request and generated 4 comments.

Comment on lines +166 to +169
│ │ head. Boosted requests rank
│ │ first and, among boosted, the
│ │ newest-arrived wins, so a
│ │ same-session follow-up that
| -------------------------- | --------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **Skip grace (fast path)** | The heap head is *already* session-boosted when the release fires (`isHeadSessionBoosted()`). | No wait at all — go straight to the capacity gates and admit if they pass. There is nothing to wait for. |
| **Grace expires** | The timer fires (`timer.C`). | Stop holding the slot and fall through to the capacity gates, which admit the heap head. If a same-session follow-up arrived during the wait it is now boosted and sits at the head, so it wins automatically (subject to inflight + backend capacity). |
> There is no "head already boosted" fast path. The queue holds the freed slot for the full grace window even when a boosted request is already at the head, because a still-newer same-session follow-up may yet arrive during the window and should be the one to ride the warm prefix cache.
Comment on lines +292 to +294
- If a boosted (same-session) request arrives during the grace window, it is admitted first when the window ends, because boosted requests outrank others in the queue—and among boosted requests the one whose session completed most recently is at the head.
- If no boosted request arrives before the window expires, the next non-boosted request proceeds as normal.
- If the head of the queue is already a boosted request, the grace period is skipped entirely.
- The queue always waits for the full grace window even when a boosted request is already at the head, because a still-newer same-session follow-up may yet arrive and should be the one to ride the warm prefix cache.
│ │ keys: sessionID │ │ (after response sent) │ │
│ │ cap: 4096 default│ └─────────────────────────┘ │
│ │ key: sessionID │ │ (after response sent) │ │
│ │ value: completeAt│ └─────────────────────────┘ │
Signed-off-by: YaoZengzeng <yaozengzeng@huawei.com>
Copilot AI review requested due to automatic review settings July 10, 2026 09:47

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

Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.

│ │ grace period, then dequeue the
│ │ head. Boosted requests rank
│ │ first and, among boosted, the
│ │ newest-arrived wins, so a
}
if pq.heap[i].SessionBoost {
if !pq.heap[i].LastTurnCompletedAt.Equal(pq.heap[j].LastTurnCompletedAt) {
return pq.heap[i].LastTurnCompletedAt.After(pq.heap[j].LastTurnCompletedAt)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Newest-first ordering can starve an older boosted request. Each later-completing session gets a newer timestamp and stays ahead of it, while the queued request keeps the timestamp captured at enqueue, so sustained boosted traffic can make the older request hit SESSION_BOOST_TIMEOUT instead of ever running. Please add bounded overtaking or aging, with a test that inserts a newer completion before each dequeue.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

kind/enhancement New feature or request size/L

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants