Review fixes: record cancelled requests as 499; empty usage is an array
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
This commit is contained in:
+47
-17
@@ -30,26 +30,31 @@ func (p *Handler) forward(w http.ResponseWriter, r *http.Request, route, host, l
|
||||
rev := &forwardState{started: started}
|
||||
rp := newReverseProxy(p.health, host, leaseState, target, rest, rev)
|
||||
rec := &statusRecorder{ResponseWriter: w, status: http.StatusOK}
|
||||
|
||||
// ServeHTTP unwinds with http.ErrAbortHandler when a client leaves mid-stream; recover so the
|
||||
// row the request earned is still written, then re-panic so the server keeps its semantics.
|
||||
defer func() {
|
||||
if pv := recover(); pv != nil {
|
||||
total := time.Since(started).Milliseconds()
|
||||
req := forwardRow(route, fp, model, host, started, waited, rev, rec.status, total)
|
||||
if perr, ok := pv.(error); ok && errors.Is(perr, http.ErrAbortHandler) {
|
||||
req.Status = 499
|
||||
req.Err = "client cancelled"
|
||||
} else {
|
||||
req.Err = "upstream error"
|
||||
}
|
||||
p.writeRecord(req)
|
||||
panic(pv)
|
||||
}
|
||||
}()
|
||||
|
||||
rp.ServeHTTP(rec, r)
|
||||
total := time.Since(started)
|
||||
|
||||
req := store.Request{
|
||||
Route: route,
|
||||
FP: fp,
|
||||
Model: model,
|
||||
Host: host,
|
||||
Started: started,
|
||||
QueuedMs: waited.Milliseconds(),
|
||||
TTFBMs: ttfbMs(rev),
|
||||
TotalMs: total.Milliseconds(),
|
||||
Status: rec.status,
|
||||
Streamed: rev.streamed,
|
||||
}
|
||||
if rev.tee != nil {
|
||||
prompt, cached, completion := rev.tee.tokens()
|
||||
req.PromptTokens = int64(prompt)
|
||||
req.CachedTokens = int64(cached)
|
||||
req.CompletionTokens = int64(completion)
|
||||
req := forwardRow(route, fp, model, host, started, waited, rev, rec.status, total.Milliseconds())
|
||||
if r.Context().Err() != nil {
|
||||
req.Status = 499
|
||||
req.Err = "client cancelled"
|
||||
}
|
||||
p.writeRecord(req)
|
||||
|
||||
@@ -70,6 +75,31 @@ func (p *Handler) forward(w http.ResponseWriter, r *http.Request, route, host, l
|
||||
)
|
||||
}
|
||||
|
||||
// forwardRow builds the accounting row from the state a forward gathered: what the tee scanned and
|
||||
// what the recorder captured. totalMs is measured from start to the caller's exit, so the forward
|
||||
// path and the recovery path above build identical rows.
|
||||
func forwardRow(route, fp, model, host string, start time.Time, waited time.Duration, rev *forwardState, status int, totalMs int64) store.Request {
|
||||
req := store.Request{
|
||||
Route: route,
|
||||
FP: fp,
|
||||
Model: model,
|
||||
Host: host,
|
||||
Started: start,
|
||||
QueuedMs: waited.Milliseconds(),
|
||||
TTFBMs: ttfbMs(rev),
|
||||
TotalMs: totalMs,
|
||||
Status: status,
|
||||
Streamed: rev.streamed,
|
||||
}
|
||||
if rev.tee != nil {
|
||||
prompt, cached, completion := rev.tee.tokens()
|
||||
req.PromptTokens = int64(prompt)
|
||||
req.CachedTokens = int64(cached)
|
||||
req.CompletionTokens = int64(completion)
|
||||
}
|
||||
return req
|
||||
}
|
||||
|
||||
// leaseState is "reused" when the lease already held the conversation, else "new".
|
||||
func leaseState(reused bool) string {
|
||||
if reused {
|
||||
|
||||
Reference in New Issue
Block a user