diff --git a/pkg/instance/lifecycle.go b/pkg/instance/lifecycle.go index 4de9dde..ef92f97 100644 --- a/pkg/instance/lifecycle.go +++ b/pkg/instance/lifecycle.go @@ -144,6 +144,10 @@ func (i *Process) Stop() error { return nil } +func (i *Process) LastRequestTime() int64 { + return i.lastRequestTime.Load() +} + func (i *Process) WaitForHealthy(timeout int) error { if !i.IsRunning() { return fmt.Errorf("instance %s is not running", i.Name) diff --git a/pkg/manager/manager.go b/pkg/manager/manager.go index 21e85ea..390cefe 100644 --- a/pkg/manager/manager.go +++ b/pkg/manager/manager.go @@ -23,6 +23,7 @@ type InstanceManager interface { StartInstance(name string) (*instance.Process, error) IsMaxRunningInstancesReached() bool StopInstance(name string) (*instance.Process, error) + EvictLRUInstance() error RestartInstance(name string) (*instance.Process, error) GetInstanceLogs(name string) (string, error) Shutdown() diff --git a/pkg/manager/operations.go b/pkg/manager/operations.go index 5af19e7..8972b80 100644 --- a/pkg/manager/operations.go +++ b/pkg/manager/operations.go @@ -239,6 +239,36 @@ func (im *instanceManager) StopInstance(name string) (*instance.Process, error) return instance, nil } +// EvictLRUInstance finds and stops the least recently used running instance. +func (im *instanceManager) EvictLRUInstance() error { + im.mu.RLock() + var lruInstance *instance.Process + + for name, _ := range im.runningInstances { + inst := im.instances[name] + if inst == nil { + continue + } + + if lruInstance == nil { + lruInstance = inst + } + + if inst.LastRequestTime() < lruInstance.LastRequestTime() { + lruInstance = inst + } + } + im.mu.RUnlock() + + if lruInstance == nil { + return fmt.Errorf("failed to find lru instance") + } + + // Evict Instance + _, err := im.StopInstance(lruInstance.Name) + return err +} + // RestartInstance stops and then starts an instance, returning the updated instance. func (im *instanceManager) RestartInstance(name string) (*instance.Process, error) { instance, err := im.StopInstance(name)