CPU replicas start on half the machine's CPUs, not all of them: two busy llama.cpp servers each spinning on all 8 vCPUs fell to 0.8 tok/s apiece, where at 4 threads they keep 5.5. llamacpp.threads sets it per node. Inference requests can be traced over OTLP/HTTP (tracing.endpoint), with admission, schedule and upstream spans and traceparent sent to the engine. Security: onboarding no longer puts the cluster root in the system trust store and removes it where it was; the mirror's mutual-TLS API can be limited to named certificates (--api-client); init.log no longer keeps the administrator's password; a warning when auth is off on a public listen; the recorded actor is sanitised and sudo-aware; Ray's dashboard is off, and the remaining engine gaps are documented. reconciler.go and agent.go are split by topic, the status mapping of each failure is tested, and the plan's checklist is brought up to date. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
59 lines
1.9 KiB
Go
59 lines
1.9 KiB
Go
package agent
|
|
|
|
import (
|
|
"context"
|
|
"os"
|
|
"runtime"
|
|
"time"
|
|
|
|
"gitea.mynodes.xyz/ilker/llmgw/internal/release"
|
|
|
|
llmgwv1 "gitea.mynodes.xyz/ilker/llmgw/api/gen/llmgw/v1"
|
|
)
|
|
|
|
// upgradeExit is the exit status after an upgrade: non-zero, so systemd's
|
|
// Restart=on-failure starts the new binary, and distinct, so the journal says
|
|
// why the agent went.
|
|
const upgradeExit = 75
|
|
|
|
// exitForUpgrade ends the process; a variable so a test can see it called
|
|
// rather than have its own process end.
|
|
var exitForUpgrade = func() { os.Exit(upgradeExit) }
|
|
|
|
// upgradeTarget is the binary an upgrade replaces; a variable so a test
|
|
// replaces a file of its own rather than the test binary running it.
|
|
var upgradeTarget = os.Executable
|
|
|
|
// upgrade replaces this agent's binary with a release and restarts into it.
|
|
//
|
|
// Engines are not touched: an agent restart leaves them running and adopts
|
|
// them again, which is what makes upgrading a node something that can be done
|
|
// while it serves.
|
|
func (a *Agent) upgrade(ctx context.Context, m *llmgwv1.UpgradeAgent, out chan<- *llmgwv1.AgentMessage) {
|
|
reply := &llmgwv1.UpgradeReply{RequestId: m.GetRequestId(), Version: m.GetVersion()}
|
|
send := func() {
|
|
select {
|
|
case out <- &llmgwv1.AgentMessage{Msg: &llmgwv1.AgentMessage_Upgrade{Upgrade: reply}}:
|
|
case <-ctx.Done():
|
|
}
|
|
}
|
|
a.log.Info("upgrading", "to", m.GetVersion(), "from", a.cfg.Version)
|
|
self, err := upgradeTarget()
|
|
if err == nil {
|
|
dctx, cancel := context.WithTimeout(ctx, 10*time.Minute)
|
|
_, err = release.Install(dctx, nil, m.GetReleases(), m.GetVersion(), runtime.GOOS, runtime.GOARCH, self)
|
|
cancel()
|
|
}
|
|
if err != nil {
|
|
reply.Error = err.Error()
|
|
a.log.Error("upgrade failed; still running the old version", "to", m.GetVersion(), "err", err)
|
|
send()
|
|
return
|
|
}
|
|
send()
|
|
a.log.Info("upgraded; restarting into the new version", "to", m.GetVersion())
|
|
// A moment for the reply to leave before the stream goes.
|
|
time.Sleep(500 * time.Millisecond)
|
|
exitForUpgrade()
|
|
}
|