mirror of
https://github.com/R0m1k3/Loki.git
synced 2026-10-11 17:26:57 +02:00
Slots : corrections de relecture du lot 2 — une lecture d'un client ne prend plus le slot
Les proxys de Loki (/v1 et le relais) comptaient TOUTE requête d'un client comme une requête qui passe par le slot : un GET /v1/models ou une sonde /health (Open WebUI en envoie régulièrement) annulait le préchauffage en vol et retirait le tampon de la discussion. Avec PREWARM, COMPACT_CONTINUATION ou SLOT_PERSIST, la clé devenait inopérante dès qu'un client sondait le moteur. - engineProxyBegin : une lecture (GET, HEAD) reste comptée en vol, comme avant, mais n'avance pas le numéro des requêtes et garde le préchauffage ; une complétion de client garde le comportement d'avant. - README : avec PREWARM, SLOT_PERSIST ne garde presque rien (le préchauffage passe par le slot après chaque tour) — dit plutôt que découvert. Sans aucune de ces clés, rien ne change. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
a94c752529
commit
f0d5711a1a
5 files changed
+65
-4
No files matched your search
@@ -634,3 +634,47 @@ func TestBuildChatPayloadNoSampling(t *testing.T) {
|
||||
t.Fatalf("échantillonnage posé malgré noSampling : %v", p)
|
||||
}
|
||||
}
|
||||
|
||||
// Corrections de relecture du lot 2 : une lecture passée par les proxys de
|
||||
// Loki (GET /v1/models, /health d'un client qui sonde) ne calcule rien dans un
|
||||
// slot — elle ne retire pas le tampon de la discussion et n'annule pas un
|
||||
// préchauffage. Une complétion de client, si.
|
||||
func TestProxyReadKeepsSlotStamp(t *testing.T) {
|
||||
testHome(t)
|
||||
contReset(t)
|
||||
if err := SetConfigKey("MODEL", "/models/a.gguf"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
end, seq := engineRequestBegin(nil)
|
||||
end()
|
||||
engineMarkMain(seq, "c1")
|
||||
cancelled := false
|
||||
p := &prewarmRun{cancel: func() { cancelled = true }}
|
||||
endP, ok := prewarmBegin(p)
|
||||
if !ok {
|
||||
t.Fatal("préchauffage refusé, moteur libre")
|
||||
}
|
||||
defer endP()
|
||||
// Le préchauffage retire lui-même le tampon : reposé à la main, pour voir
|
||||
// ce que fait la lecture seule.
|
||||
engineGate.mu.Lock()
|
||||
engineGate.main.seq = engineGate.seq
|
||||
engineGate.mu.Unlock()
|
||||
for _, m := range []string{http.MethodGet, http.MethodHead} {
|
||||
r := httptest.NewRequest(m, "/v1/models", nil)
|
||||
engineProxyBegin(r, false)()
|
||||
}
|
||||
if cancelled {
|
||||
t.Error("une lecture a annulé le préchauffage")
|
||||
}
|
||||
if !engineSlotHolds("c1") {
|
||||
t.Error("une lecture a retiré le tampon de la discussion")
|
||||
}
|
||||
engineProxyBegin(httptest.NewRequest(http.MethodPost, "/v1/chat/completions", nil), false)()
|
||||
if !cancelled {
|
||||
t.Error("une complétion de client n'a pas annulé le préchauffage")
|
||||
}
|
||||
if engineSlotHolds("c1") {
|
||||
t.Error("tampon gardé après une complétion de client")
|
||||
}
|
||||
}
|
||||
@@ -123,8 +123,7 @@ func oaiHandler() http.Handler {
|
||||
// Requête en vol vers le moteur : l'isolation des travaux annexes
|
||||
// n'efface pas le slot pendant ce temps. Différé : ReverseProxy panique
|
||||
// (ErrAbortHandler) quand le client coupe en plein flux.
|
||||
end, _ := engineRequestBeginSide(nil, side)
|
||||
defer end()
|
||||
defer engineProxyBegin(r, side)()
|
||||
// Complétion d'un client externe : elle prend le slot sous le nez de
|
||||
// la conversation. Notée pour nommer la perte de cache qui suit.
|
||||
if r.Method == http.MethodPost && strings.HasPrefix(p, "/v1/") {
|
||||
|
||||
@@ -185,6 +185,22 @@ func engineRequestBeginSide(keep func(*prewarmRun) bool, side bool) (func(), uin
|
||||
}, seq
|
||||
}
|
||||
|
||||
// engineProxyBegin : engineRequestBeginSide pour une requête d'un client passée
|
||||
// par les proxys de Loki (/v1, /health, /props, /metrics, /slots). Comptée en
|
||||
// vol dans tous les cas, comme avant. Une lecture (GET, HEAD : /v1/models, une
|
||||
// sonde /health d'Open WebUI…) ne calcule rien dans aucun slot : elle ne doit
|
||||
// ni annuler un préchauffage (PREWARM), ni dire que le slot ne porte plus la
|
||||
// discussion (COMPACT_CONTINUATION, SLOT_PERSIST). Sans ces clés, aucune
|
||||
// différence.
|
||||
func engineProxyBegin(r *http.Request, side bool) func() {
|
||||
if r.Method == http.MethodGet || r.Method == http.MethodHead {
|
||||
end, _ := engineRequestBeginSide(func(*prewarmRun) bool { return true }, true)
|
||||
return end
|
||||
}
|
||||
end, _ := engineRequestBeginSide(nil, side)
|
||||
return end
|
||||
}
|
||||
|
||||
// slotsWrite : une action sur /slots (save, restore, erase) plutôt qu'une
|
||||
// lecture. Les proxys de Loki la refusent : seul Loki, en local, efface — et
|
||||
// save ou restore écriraient des Gio sur le disque pour un client distant.
|
||||
|
||||
@@ -530,8 +530,7 @@ func newLinkHandler(mux *http.ServeMux) http.Handler {
|
||||
http.Error(w, msg, status)
|
||||
return
|
||||
}
|
||||
end, _ := engineRequestBeginSide(nil, side) // voir oaiHandler
|
||||
defer end()
|
||||
defer engineProxyBegin(r, side)() // voir oaiHandler
|
||||
lp.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user