Skip to content

Commit 247329d

Browse files
v2.10.2: cancel superseded queries instead of letting them pile up
Clicking through targets and windows faster than they load left every abandoned query running server-side: the front end dropped the stale responses, but the reads kept chewing through day files and starved each other. That is why a 12h window showed up in the slow log at 6-8 seconds while a 30d read was in flight. - front end aborts the in-flight series request before starting the next one (AbortController, no new dependency); an aborted request exits silently - ReadRange takes a context and checks it between day files, so a disconnected client stops the read immediately instead of finishing work nobody is waiting for Measured: 8 rapid clicks now produce 4 completed and 4 cancelled requests; after a 20-click burst the chart is back in 15ms with zero slow-request log lines.
1 parent 94dadf0 commit 247329d

3 files changed

Lines changed: 26 additions & 4 deletions

File tree

static/index.html

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,8 @@
216216

217217
let sel = null; // {from,to} 自定义查询区间(unix 秒)
218218
let renderSeq = 0;
219+
let inflight = null; // 正在飞的 series 请求 —— 新请求发起前先掐掉它,
220+
// 否则快速点击会在服务端堆起一串没人要的慢查询,互相拖死。
219221
let rendering = false; // 一次渲染(含慢速 band 查询)是否仍在进行
220222
async function render() {
221223
const seq = ++renderSeq;
@@ -234,7 +236,18 @@
234236
let url = `/api/series?target=${encodeURIComponent(current)}`;
235237
if (sel) url += `&from=${sel.from}&to=${sel.to}`;
236238
else url += `&minutes=${minutes}`;
237-
const rounds = await (await fetch(url)).json() || [];
239+
if (inflight) inflight.abort();
240+
const ctl = new AbortController();
241+
inflight = ctl;
242+
let rounds;
243+
try {
244+
rounds = await (await fetch(url, { signal: ctl.signal })).json() || [];
245+
} catch (e) {
246+
if (e.name === 'AbortError') return; // 被新点击取代,静默退出
247+
throw e;
248+
} finally {
249+
if (inflight === ctl) inflight = null;
250+
}
238251
if (seq !== renderSeq) return; // 过期响应:已切走,丢弃
239252

240253
const smoke = [], median = [], lossBars = [], burstPts = [];

store.go

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package main
22

33
import (
44
"bufio"
5+
"context"
56
"encoding/json"
67
"fmt"
78
"log"
@@ -161,12 +162,15 @@ func (s *Store) RemoveTarget(name string) {
161162
}
162163
}
163164

164-
func (s *Store) ReadRange(name string, from, to int64) []Round {
165+
// ReadRange reads raw rounds in [from,to]. ctx lets a long read stop early when the
166+
// browser navigates away: without it, clicking through targets leaves every abandoned
167+
// query still chewing through day files, and they starve each other.
168+
func (s *Store) ReadRange(ctx context.Context, name string, from, to int64) []Round {
165169
var rounds []Round
166170
// ring first (covers the recent tail cheaply)
167171
s.mu.RLock()
168172
ring := s.rings[name]
169-
ringFrom := int64(1<<62)
173+
ringFrom := int64(1 << 62)
170174
if len(ring) > 0 {
171175
ringFrom = ring[0].T
172176
}
@@ -176,6 +180,11 @@ func (s *Store) ReadRange(name string, from, to int64) []Round {
176180
rounds = s.Recent(name, from)
177181
} else {
178182
for d := time.Unix(from, 0); !d.After(time.Unix(to, 0)); d = d.AddDate(0, 0, 1) {
183+
select {
184+
case <-ctx.Done(): // client went away — stop reading, drop what we have
185+
return []Round{}
186+
default:
187+
}
179188
day, _ := s.readDay(name, d.Format("2006-01-02"))
180189
rounds = append(rounds, day...)
181190
}

web.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ func serveWeb(cfg *Config, store *Store, users map[string]string) error {
170170
to = time.Now().Unix()
171171
from = to - int64(minutes)*60
172172
}
173-
writeJSON(w, store.ReadRange(name, from, to))
173+
writeJSON(w, store.ReadRange(r.Context(), name, from, to))
174174
}))
175175

176176
return http.ListenAndServe(cfg.Listen, mux)

0 commit comments

Comments
 (0)