Route by lease, queue per host and model, record every request
Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
package proxy
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"git.wntrmute.dev/kyle/crossbar/internal/choose"
|
||||
"git.wntrmute.dev/kyle/crossbar/internal/config"
|
||||
"git.wntrmute.dev/kyle/crossbar/internal/health"
|
||||
"git.wntrmute.dev/kyle/crossbar/internal/lease"
|
||||
"git.wntrmute.dev/kyle/crossbar/internal/limiter"
|
||||
)
|
||||
|
||||
// Hosts adapts the health table and config for the lease table, and holds the operator's drain set.
|
||||
// The lease table filters candidates by Healthy && !Draining: Healthy is the health table's view of
|
||||
// a host, Draining is an operator flag that keeps new leases off a host being taken out of service.
|
||||
type Hosts struct {
|
||||
health *health.Table
|
||||
drain map[string]bool
|
||||
mu sync.Mutex
|
||||
}
|
||||
|
||||
// HostView builds the lease-table view of the health table and config.
|
||||
func HostView(h *health.Table, cfg *config.Config) *Hosts {
|
||||
return &Hosts{health: h, drain: make(map[string]bool)}
|
||||
}
|
||||
|
||||
// Healthy reports whether the health table says the host answered its last poll; an unknown host is
|
||||
// not healthy.
|
||||
func (h *Hosts) Healthy(name string) bool {
|
||||
s, ok := h.health.Get(name)
|
||||
if !ok {
|
||||
return false
|
||||
}
|
||||
return s.Healthy
|
||||
}
|
||||
|
||||
// Draining reports whether an operator is draining the host.
|
||||
func (h *Hosts) Draining(name string) bool {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
return h.drain[name]
|
||||
}
|
||||
|
||||
// SetDraining turns draining on or off for a host.
|
||||
func (h *Hosts) SetDraining(name string, on bool) {
|
||||
h.mu.Lock()
|
||||
defer h.mu.Unlock()
|
||||
if on {
|
||||
h.drain[name] = true
|
||||
return
|
||||
}
|
||||
delete(h.drain, name)
|
||||
}
|
||||
|
||||
// hostChooser adapts config, health and limiter to lease.Chooser via choose.Best.
|
||||
type hostChooser struct {
|
||||
cfg *config.Config
|
||||
health *health.Table
|
||||
lim *limiter.Limiter
|
||||
}
|
||||
|
||||
// Chooser adapts config, health and limiter to lease.Chooser using choose.Best: among the candidates
|
||||
// it prefers the hosts that have the model loaded over those that can only serve it, then the one
|
||||
// with the most free slots times weight, breaking ties by shortest queue. Draining is reported false
|
||||
// because the lease table already filtered draining hosts out before calling Choose.
|
||||
func Chooser(cfg *config.Config, h *health.Table, l *limiter.Limiter) lease.Chooser {
|
||||
return &hostChooser{cfg: cfg, health: h, lim: l}
|
||||
}
|
||||
|
||||
func (c *hostChooser) Choose(candidates []string, model string) (string, bool) {
|
||||
return choose.Best(candidates, func(host string) (choose.Info, bool) {
|
||||
s, ok := c.health.Get(host)
|
||||
info := choose.Info{
|
||||
Healthy: ok && s.Healthy,
|
||||
Draining: false,
|
||||
Loaded: contains(s.Loaded, model),
|
||||
CanServe: c.cfg.Serves(host, model),
|
||||
Free: c.lim.FreeSlots(host),
|
||||
Queued: c.lim.Queued(host, model),
|
||||
Weight: c.cfg.Hosts[host].Weight,
|
||||
}
|
||||
return info, ok
|
||||
})
|
||||
}
|
||||
|
||||
func contains(list []string, v string) bool {
|
||||
for _, s := range list {
|
||||
if s == v {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
Reference in New Issue
Block a user