mirror of
https://github.com/lordmathis/llamactl.git
synced 2025-11-05 16:44:22 +00:00
Improve instance management
This commit is contained in:
@@ -1,12 +1,52 @@
|
||||
package llamactl
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"os/exec"
|
||||
"sync"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type Instance struct {
|
||||
ID uuid.UUID
|
||||
Port int
|
||||
Status string
|
||||
Args []string
|
||||
Options *InstanceOptions
|
||||
|
||||
// Status
|
||||
Running bool
|
||||
|
||||
// Output channels
|
||||
StdOut chan string // Channel for sending output messages
|
||||
StdErr chan string // Channel for sending error messages
|
||||
|
||||
// internal
|
||||
cmd *exec.Cmd // Command to run the instance
|
||||
ctx context.Context // Context for managing the instance lifecycle
|
||||
cancel context.CancelFunc // Function to cancel the context
|
||||
stdout io.ReadCloser // Standard output stream
|
||||
stderr io.ReadCloser // Standard error stream
|
||||
mu sync.Mutex // Mutex for synchronizing access to the instance
|
||||
}
|
||||
|
||||
func NewInstance(id uuid.UUID, options *InstanceOptions) *Instance {
|
||||
return &Instance{
|
||||
ID: id,
|
||||
Args: options.BuildCommandArgs(),
|
||||
Options: options,
|
||||
|
||||
Running: false,
|
||||
|
||||
StdOut: make(chan string, 100),
|
||||
StdErr: make(chan string, 100),
|
||||
}
|
||||
}
|
||||
|
||||
func (i *Instance) Start() *exec.Cmd {
|
||||
args := i.Options.BuildCommandArgs()
|
||||
cmd := exec.Command("llama-server", args...)
|
||||
|
||||
cmd.Start()
|
||||
return cmd
|
||||
}
|
||||
|
||||
@@ -46,15 +46,30 @@ func (im *instanceManager) ListInstances() ([]*Instance, error) {
|
||||
// CreateInstance creates a new instance with the given options and returns it.
|
||||
// The instance is initially in a "stopped" state.
|
||||
func (im *instanceManager) CreateInstance(options *InstanceOptions) (*Instance, error) {
|
||||
id := uuid.New()
|
||||
instance := &Instance{
|
||||
ID: id,
|
||||
Port: 8080, // Default port, can be changed later
|
||||
Status: "stopped", // Initial status
|
||||
Options: options,
|
||||
if options == nil {
|
||||
return nil, fmt.Errorf("instance options cannot be nil")
|
||||
}
|
||||
im.instances[id] = instance
|
||||
|
||||
// Generate a unique ID for the new instance
|
||||
id := uuid.New()
|
||||
for im.instances[id] != nil {
|
||||
id = uuid.New() // Ensure unique ID
|
||||
}
|
||||
|
||||
// Assign a port if not specified
|
||||
if options.Port == 0 {
|
||||
port, err := im.getNextAvailablePort()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to get next available port: %w", err)
|
||||
}
|
||||
options.Port = port
|
||||
}
|
||||
|
||||
instance := NewInstance(id, options)
|
||||
im.instances[instance.ID] = instance
|
||||
|
||||
return instance, nil
|
||||
|
||||
}
|
||||
|
||||
// GetInstance retrieves an instance by its ID.
|
||||
@@ -83,8 +98,8 @@ func (im *instanceManager) DeleteInstance(id uuid.UUID) error {
|
||||
return fmt.Errorf("instance with ID %s not found", id)
|
||||
}
|
||||
|
||||
if im.instances[id].Status != "stopped" {
|
||||
return fmt.Errorf("cannot delete a running instance, stop it first")
|
||||
if im.instances[id].Running {
|
||||
return fmt.Errorf("instance with ID %s is still running, stop it before deleting", id)
|
||||
}
|
||||
|
||||
delete(im.instances, id)
|
||||
@@ -98,13 +113,11 @@ func (im *instanceManager) StartInstance(id uuid.UUID) (*Instance, error) {
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("instance with ID %s not found", id)
|
||||
}
|
||||
if instance.Status == "running" {
|
||||
if instance.Running {
|
||||
return instance, fmt.Errorf("instance with ID %s is already running", id)
|
||||
}
|
||||
|
||||
//TODO:
|
||||
|
||||
instance.Status = "running"
|
||||
return instance, nil
|
||||
}
|
||||
|
||||
@@ -114,12 +127,11 @@ func (im *instanceManager) StopInstance(id uuid.UUID) (*Instance, error) {
|
||||
if !exists {
|
||||
return nil, fmt.Errorf("instance with ID %s not found", id)
|
||||
}
|
||||
if instance.Status == "stopped" {
|
||||
if !instance.Running {
|
||||
return instance, fmt.Errorf("instance with ID %s is already stopped", id)
|
||||
}
|
||||
|
||||
// TODO:
|
||||
instance.Status = "stopped"
|
||||
return instance, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,35 @@ import (
|
||||
)
|
||||
|
||||
type InstanceOptions struct {
|
||||
Name string `json:"name,omitempty"`
|
||||
Name string `json:"name,omitempty"` // Display name
|
||||
|
||||
// Auto restart
|
||||
AutoRestart bool `json:"auto_restart,omitempty"`
|
||||
MaxRestarts int `json:"max_restarts,omitempty"`
|
||||
RestartDelay int `json:"restart_delay,omitempty"` // in seconds
|
||||
|
||||
*LlamaServerOptions
|
||||
}
|
||||
|
||||
// UnmarshalJSON implements custom JSON unmarshaling with default values
|
||||
func (o *InstanceOptions) UnmarshalJSON(data []byte) error {
|
||||
// Set defaults first
|
||||
o.AutoRestart = true
|
||||
o.MaxRestarts = 3
|
||||
o.RestartDelay = 5
|
||||
|
||||
// Create a temporary struct to avoid recursion
|
||||
type tempInstanceOptions InstanceOptions
|
||||
temp := (*tempInstanceOptions)(o)
|
||||
|
||||
// Unmarshal into the temporary struct
|
||||
if err := json.Unmarshal(data, temp); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type LlamaServerOptions struct {
|
||||
// Common params
|
||||
VerbosePrompt bool `json:"verbose_prompt,omitempty"`
|
||||
|
||||
Reference in New Issue
Block a user