mirror of
https://github.com/lordmathis/llamactl.git
synced 2025-11-06 09:04:27 +00:00
Merge pull request #25 from lordmathis/fix/stopping-deadlock
fix: Server stopping deadlock
This commit is contained in:
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@@ -10,6 +10,10 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"mode": "auto",
|
"mode": "auto",
|
||||||
"program": "${workspaceFolder}/cmd/server/main.go",
|
"program": "${workspaceFolder}/cmd/server/main.go",
|
||||||
|
"env": {
|
||||||
|
"GO_ENV": "development",
|
||||||
|
"LLAMACTL_REQUIRE_MANAGEMENT_AUTH": "false"
|
||||||
|
},
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -123,10 +123,10 @@ func (im *instanceManager) persistInstance(instance *instance.Process) error {
|
|||||||
|
|
||||||
func (im *instanceManager) Shutdown() {
|
func (im *instanceManager) Shutdown() {
|
||||||
im.mu.Lock()
|
im.mu.Lock()
|
||||||
defer im.mu.Unlock()
|
|
||||||
|
|
||||||
// Check if already shutdown
|
// Check if already shutdown
|
||||||
if im.isShutdown {
|
if im.isShutdown {
|
||||||
|
im.mu.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
im.isShutdown = true
|
im.isShutdown = true
|
||||||
@@ -134,27 +134,32 @@ func (im *instanceManager) Shutdown() {
|
|||||||
// Signal the timeout checker to stop
|
// Signal the timeout checker to stop
|
||||||
close(im.shutdownChan)
|
close(im.shutdownChan)
|
||||||
|
|
||||||
// Release lock temporarily to wait for goroutine
|
// Create a list of running instances to stop
|
||||||
|
var runningInstances []*instance.Process
|
||||||
|
var runningNames []string
|
||||||
|
for name, inst := range im.instances {
|
||||||
|
if inst.IsRunning() {
|
||||||
|
runningInstances = append(runningInstances, inst)
|
||||||
|
runningNames = append(runningNames, name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Release lock before stopping instances to avoid deadlock
|
||||||
im.mu.Unlock()
|
im.mu.Unlock()
|
||||||
|
|
||||||
// Wait for the timeout checker goroutine to actually stop
|
// Wait for the timeout checker goroutine to actually stop
|
||||||
<-im.shutdownDone
|
<-im.shutdownDone
|
||||||
// Reacquire lock
|
|
||||||
im.mu.Lock()
|
|
||||||
|
|
||||||
// Now stop the ticker
|
// Now stop the ticker
|
||||||
if im.timeoutChecker != nil {
|
if im.timeoutChecker != nil {
|
||||||
im.timeoutChecker.Stop()
|
im.timeoutChecker.Stop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stop instances without holding the manager lock
|
||||||
var wg sync.WaitGroup
|
var wg sync.WaitGroup
|
||||||
wg.Add(len(im.instances))
|
wg.Add(len(runningInstances))
|
||||||
|
|
||||||
for name, inst := range im.instances {
|
|
||||||
if !inst.IsRunning() {
|
|
||||||
wg.Done() // If instance is not running, just mark it as done
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
|
for i, inst := range runningInstances {
|
||||||
go func(name string, inst *instance.Process) {
|
go func(name string, inst *instance.Process) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
fmt.Printf("Stopping instance %s...\n", name)
|
fmt.Printf("Stopping instance %s...\n", name)
|
||||||
@@ -162,7 +167,7 @@ func (im *instanceManager) Shutdown() {
|
|||||||
if err := inst.Stop(); err != nil {
|
if err := inst.Stop(); err != nil {
|
||||||
fmt.Printf("Error stopping instance %s: %v\n", name, err)
|
fmt.Printf("Error stopping instance %s: %v\n", name, err)
|
||||||
}
|
}
|
||||||
}(name, inst)
|
}(runningNames[i], inst)
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
|
|||||||
Reference in New Issue
Block a user