Add onStatusChange callback to instance management for status updates

This commit is contained in:
2025-08-27 20:54:26 +02:00
parent a8f3a8e0f5
commit ae37055331
6 changed files with 82 additions and 20 deletions

View File

@@ -82,7 +82,8 @@ type Process struct {
globalSettings *config.InstancesConfig
// Status
Status InstanceStatus `json:"status"`
Status InstanceStatus `json:"status"`
onStatusChange func(oldStatus, newStatus InstanceStatus)
// Creation time
Created int64 `json:"created,omitempty"` // Unix timestamp when the instance was created
@@ -193,7 +194,7 @@ func applyDefaultOptions(options *CreateInstanceOptions, globalSettings *config.
}
// NewInstance creates a new instance with the given name, log path, and options
func NewInstance(name string, globalSettings *config.InstancesConfig, options *CreateInstanceOptions) *Process {
func NewInstance(name string, globalSettings *config.InstancesConfig, options *CreateInstanceOptions, onStatusChange func(oldStatus, newStatus InstanceStatus)) *Process {
// Validate and copy options
optionsCopy := validateAndCopyOptions(name, options)
// Apply defaults
@@ -208,6 +209,8 @@ func NewInstance(name string, globalSettings *config.InstancesConfig, options *C
logger: logger,
timeProvider: realTimeProvider{},
Created: time.Now().Unix(),
Status: Stopped,
onStatusChange: onStatusChange,
}
}

View File

@@ -24,7 +24,10 @@ func TestNewInstance(t *testing.T) {
},
}
instance := instance.NewInstance("test-instance", globalSettings, options)
// Mock onStatusChange function
mockOnStatusChange := func(oldStatus, newStatus instance.InstanceStatus) {}
instance := instance.NewInstance("test-instance", globalSettings, options, mockOnStatusChange)
if instance.Name != "test-instance" {
t.Errorf("Expected name 'test-instance', got %q", instance.Name)
@@ -76,7 +79,10 @@ func TestNewInstance_WithRestartOptions(t *testing.T) {
},
}
instance := instance.NewInstance("test-instance", globalSettings, options)
// Mock onStatusChange function
mockOnStatusChange := func(oldStatus, newStatus instance.InstanceStatus) {}
instance := instance.NewInstance("test-instance", globalSettings, options, mockOnStatusChange)
opts := instance.GetOptions()
// Check that explicit values override defaults
@@ -106,7 +112,10 @@ func TestSetOptions(t *testing.T) {
},
}
inst := instance.NewInstance("test-instance", globalSettings, initialOptions)
// Mock onStatusChange function
mockOnStatusChange := func(oldStatus, newStatus instance.InstanceStatus) {}
inst := instance.NewInstance("test-instance", globalSettings, initialOptions, mockOnStatusChange)
// Update options
newOptions := &instance.CreateInstanceOptions{
@@ -144,7 +153,10 @@ func TestGetProxy(t *testing.T) {
},
}
inst := instance.NewInstance("test-instance", globalSettings, options)
// Mock onStatusChange function
mockOnStatusChange := func(oldStatus, newStatus instance.InstanceStatus) {}
inst := instance.NewInstance("test-instance", globalSettings, options, mockOnStatusChange)
// Get proxy for the first time
proxy1, err := inst.GetProxy()
@@ -180,7 +192,10 @@ func TestMarshalJSON(t *testing.T) {
},
}
instance := instance.NewInstance("test-instance", globalSettings, options)
// Mock onStatusChange function
mockOnStatusChange := func(oldStatus, newStatus instance.InstanceStatus) {}
instance := instance.NewInstance("test-instance", globalSettings, options, mockOnStatusChange)
data, err := json.Marshal(instance)
if err != nil {
@@ -303,7 +318,10 @@ func TestCreateInstanceOptionsValidation(t *testing.T) {
},
}
instance := instance.NewInstance("test", globalSettings, options)
// Mock onStatusChange function
mockOnStatusChange := func(oldStatus, newStatus instance.InstanceStatus) {}
instance := instance.NewInstance("test", globalSettings, options, mockOnStatusChange)
opts := instance.GetOptions()
if opts.MaxRestarts == nil {

View File

@@ -28,9 +28,13 @@ var statusToName = map[InstanceStatus]string{
func (p *Process) SetStatus(status InstanceStatus) {
p.mu.Lock()
defer p.mu.Unlock()
oldStatus := p.Status
p.Status = status
p.mu.Unlock()
if p.onStatusChange != nil {
p.onStatusChange(oldStatus, status)
}
}
func (p *Process) GetStatus() InstanceStatus {

View File

@@ -42,7 +42,10 @@ func TestUpdateLastRequestTime(t *testing.T) {
},
}
inst := instance.NewInstance("test-instance", globalSettings, options)
// Mock onStatusChange function
mockOnStatusChange := func(oldStatus, newStatus instance.InstanceStatus) {}
inst := instance.NewInstance("test-instance", globalSettings, options, mockOnStatusChange)
// Test that UpdateLastRequestTime doesn't panic
inst.UpdateLastRequestTime()
@@ -61,7 +64,10 @@ func TestShouldTimeout_NotRunning(t *testing.T) {
},
}
inst := instance.NewInstance("test-instance", globalSettings, options)
// Mock onStatusChange function
mockOnStatusChange := func(oldStatus, newStatus instance.InstanceStatus) {}
inst := instance.NewInstance("test-instance", globalSettings, options, mockOnStatusChange)
// Instance is not running, should not timeout regardless of configuration
if inst.ShouldTimeout() {
@@ -85,6 +91,9 @@ func TestShouldTimeout_NoTimeoutConfigured(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
// Mock onStatusChange function
mockOnStatusChange := func(oldStatus, newStatus instance.InstanceStatus) {}
options := &instance.CreateInstanceOptions{
IdleTimeout: tt.idleTimeout,
LlamaServerOptions: llamacpp.LlamaServerOptions{
@@ -92,7 +101,7 @@ func TestShouldTimeout_NoTimeoutConfigured(t *testing.T) {
},
}
inst := instance.NewInstance("test-instance", globalSettings, options)
inst := instance.NewInstance("test-instance", globalSettings, options, mockOnStatusChange)
// Simulate running state
inst.SetStatus(instance.Running)
@@ -116,7 +125,10 @@ func TestShouldTimeout_WithinTimeLimit(t *testing.T) {
},
}
inst := instance.NewInstance("test-instance", globalSettings, options)
// Mock onStatusChange function
mockOnStatusChange := func(oldStatus, newStatus instance.InstanceStatus) {}
inst := instance.NewInstance("test-instance", globalSettings, options, mockOnStatusChange)
inst.SetStatus(instance.Running)
// Update last request time to now
@@ -141,7 +153,10 @@ func TestShouldTimeout_ExceedsTimeLimit(t *testing.T) {
},
}
inst := instance.NewInstance("test-instance", globalSettings, options)
// Mock onStatusChange function
mockOnStatusChange := func(oldStatus, newStatus instance.InstanceStatus) {}
inst := instance.NewInstance("test-instance", globalSettings, options, mockOnStatusChange)
inst.SetStatus(instance.Running)
// Use MockTimeProvider to simulate old last request time
@@ -184,7 +199,10 @@ func TestTimeoutConfiguration_Validation(t *testing.T) {
},
}
inst := instance.NewInstance("test-instance", globalSettings, options)
// Mock onStatusChange function
mockOnStatusChange := func(oldStatus, newStatus instance.InstanceStatus) {}
inst := instance.NewInstance("test-instance", globalSettings, options, mockOnStatusChange)
opts := inst.GetOptions()
if opts.IdleTimeout == nil || *opts.IdleTimeout != tt.expectedTimeout {