heroagent/pkg/system/processmanager/README.md
2025-05-23 15:28:30 +04:00

3.4 KiB

Process Manager

The Process Manager (processmanager) is a Go package responsible for starting, stopping, monitoring, and managing system processes. It provides a robust way to handle long-running tasks, scheduled jobs (via cron expressions), and general command execution with logging capabilities.

It can be interacted with via heroscript commands, typically through a telnet interface to a ProcessManagerHandler server.

Features

  • Start and Stop Processes: Launch new processes and terminate existing ones.
  • Restart Processes: Convenience function to stop, delete, and restart a process.
  • Delete Processes: Remove a process definition and its associated logs.
  • Process Monitoring: Tracks process status (running, stopped, failed, completed), PID, CPU, and memory usage.
  • Logging: Captures stdout and stderr for each managed process. Logs are stored in a configurable base directory, with each process having its own subdirectory.
  • Deadline Management: Processes can be started with a deadline, after which they will be automatically stopped.
  • Cron Scheduling: Processes can be scheduled to run based on cron expressions (though the actual scheduling logic might be external and trigger process.start).
  • Heroscript Integration: Exposes functionality through heroscript actions.

Direct Usage in Go (Conceptual)

While primarily designed for heroscript interaction, the core ProcessManager can be used directly in Go applications:

package main

import (
	"fmt"
	"time"

	"git.ourworld.tf/herocode/heroagent/pkg/system/processmanager"
)

func main() {
	pm := processmanager.NewProcessManager()

	// Configure logs path (optional, defaults to a temp directory)
	// pm.SetLogsBasePath("./my_process_logs")

	processName := "my_go_task"
	command := "sleep 10 && echo 'Task finished'"

	fmt.Printf("Starting process: %s\n", processName)
	err := pm.StartProcess(processName, command, true, 0, "", "") // name, command, logEnabled, deadline, cron, jobID
	if err != nil {
		fmt.Printf("Error starting process: %v\n", err)
		return
	}

	fmt.Printf("Process '%s' started. Waiting for it to complete or monitoring...\n", processName)

	// Monitor status (example)
	for i := 0; i < 12; i++ {
		time.Sleep(1 * time.Second)
		status, err := pm.GetProcessStatus(processName)
		if err != nil {
			fmt.Printf("Error getting status: %v\n", err)
			break
		}
		fmt.Printf("Status of '%s': %s (PID: %d, CPU: %.2f%%, Mem: %.2fMB)\n",
			status.Name, status.Status, status.PID, status.CPUPercent, status.MemoryMB)

		if status.Status == processmanager.ProcessStatusCompleted || status.Status == processmanager.ProcessStatusFailed {
			fmt.Printf("Process '%s' ended with status: %s\n", processName, status.Status)
			if status.Error != "" {
				fmt.Printf("Error: %s\n", status.Error)
			}
			break
		}
	}

	// Retrieve logs
	logs, err := pm.GetProcessLogs(processName, 100)
	if err != nil {
		fmt.Printf("Error getting logs: %v\n", err)
	} else {
		fmt.Printf("\n--- Logs for %s ---\n%s\n-------------------\n", processName, logs)
	}

	// Stop (if still running) and delete
	fmt.Printf("Stopping process: %s\n", processName)
	pm.StopProcess(processName) // Ignoring error for simplicity if already stopped

	fmt.Printf("Deleting process: %s\n", processName)
	err = pm.DeleteProcess(processName)
	if err != nil {
		fmt.Printf("Error deleting process: %v\n", err)
	}

	fmt.Println("Done.")
}