fix(failover): keep the aliased model of a warm target loaded

The warm list held target names as the chain lists them. For an alias
target that is the alias, but the preloader loads the alias stub (no
backend, no model) and the eviction guard compares against loaded
model names, which never include an alias. A warm alias target was
neither preloaded nor protected from eviction.

Report the model that serves each warm target instead.

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
Assisted-by: Claude:claude-opus-5-5 [Claude Code]
This commit is contained in:
Ettore Di Giacinto committed 2026-09-27 20:18:30 +00:00
1 parent 1b03600437
commit 8474296cb1
2 files changed
+20 -4

No files matched your search

+8 -4
View File
@@ -87,7 +87,10 @@ type Manager struct {
}
type targetState struct {
name string
name string
// serving is the model that serves this target: its own name, or the
// model an alias points to. Model loading and eviction only know it.
serving string
kind Kind
warm bool
state TargetState
@@ -196,6 +199,7 @@ func (m *Manager) syncLocked() {
continue
}
ts.kind = KindOf(tc)
ts.serving = tc.Name
if t.Warm && ts.kind == KindLocal {
ts.warm = true
}
@@ -224,9 +228,9 @@ func (m *Manager) syncLocked() {
m.recomputeLocked(ch, "")
}
var warm []string
for name, ts := range m.targets {
if ts.warm {
warm = append(warm, name)
for _, ts := range m.targets {
if ts.warm && ts.serving != "" && !slices.Contains(warm, ts.serving) {
warm = append(warm, ts.serving)
}
}
sort.Strings(warm)
+12
View File
@@ -248,6 +248,18 @@ var _ = Describe("Manager", func() {
Expect(m.WarmTargets()).To(Equal([]string{"b"}))
})
It("reports the model an alias target serves from as warm, not the alias", func() {
var got []string
m = New(src, WithClock(clock), WithOnWarmChanged(func(w []string) { got = w }))
// The preloader and the eviction guard work on loaded model names; an
// alias is never loaded under its own name.
src.Put(config.ModelConfig{Name: "al", Alias: "b"})
src.Put(chainCfg("chain", nil, t("a"), warmT("al")))
m.Sync()
Expect(got).To(Equal([]string{"b"}))
Expect(m.WarmTargets()).To(Equal([]string{"b"}))
})
It("closes a subscription on cancel", func() {
events, cancel := m.Subscribe(1)
cancel()