return httpserver.IneligibleForQueuePriority
case req.Method == http.MethodPost && strings.HasPrefix(req.URL.Path, "/arvados/v1/logs"):
// "Create log entry" is the most harmless kind of
- // request to drop.
- return 0
+ // request to drop. Negative priority is called "low"
+ // in aggregate metrics.
+ return -1
case req.Header.Get("Origin") != "":
- // Handle interactive requests first.
- return 2
- default:
+ // Handle interactive requests first. Positive
+ // priority is called "high" in aggregate metrics.
return 1
+ default:
+ // Zero priority is called "normal" in aggregate
+ // metrics.
+ return 0
}
}
// registered with Registry, if it is not nil.
Registry *prometheus.Registry
- setupOnce sync.Once
- mtx sync.Mutex
- handling int
- queue queue
+ setupOnce sync.Once
+ mQueueDelay *prometheus.SummaryVec
+ mtx sync.Mutex
+ handling int
+ queue queue
}
type qent struct {
},
func() float64 { return float64(rl.MaxQueue) },
))
- rl.mQueueDelay = prometheus.NewSummary(prometheus.SummaryOpts{
+ rl.mQueueDelay = prometheus.NewSummaryVec(prometheus.SummaryOpts{
Namespace: "arvados",
Name: "queue_delay_seconds",
- Help: "Number of seconds spent in the incoming request queue",
+ Help: "Time spent in the incoming request queue",
Objectives: map[float64]float64{0.5: 0.05, 0.9: 0.01, 0.95: 0.005, 0.99: 0.001},
- })
- reg.MustRegister(rl.mQueueDelay)
+ }, []string{"priority"})
+ rl.Registry.MustRegister(rl.mQueueDelay)
}
}
ent := rl.enqueue(req)
SetResponseLogFields(req.Context(), logrus.Fields{"priority": ent.priority})
var ok bool
+ var abandoned bool
select {
case <-req.Context().Done():
+ abandoned = true
rl.remove(ent)
// we still need to wait for ent.ready, because
// sometimes runqueue() will have already decided to
ok = <-ent.ready
case ok = <-ent.ready:
}
+
+ // report time spent in queue
+ var qlabel string
+ switch {
+ case abandoned:
+ case !ok && ent.priority == IneligibleForQueuePriority:
+ // don't pollute stats
+ case ent.priority < 0:
+ qlabel = "low"
+ case ent.priority > 0:
+ qlabel = "high"
+ default:
+ qlabel = "normal"
+ }
+ if qlabel != "" && rl.mQueueDelay != nil {
+ rl.mQueueDelay.WithLabelValues(qlabel).Observe(time.Now().Sub(ent.queued).Seconds())
+ }
+
if !ok {
resp.WriteHeader(http.StatusServiceUnavailable)
return