Commit 57ccc40

Eric Bower  ·  2026-05-08 20:16:53 -0400 EDT
parent 97d87a6
chore: copy changes
2 files changed,  +22, -5
M main.go
+21, -5
 1@@ -54,6 +54,7 @@ type Cfg struct {
 2 	Event               string        // event JSON passed via --event flag
 3 	EventSource         io.ReadCloser // when set, used directly as the event source (for testing)
 4 	MonitorInterval     time.Duration
 5+	GCInterval          time.Duration
 6 	NewWorkspace        WorkspaceFactory
 7 	StatusOutput        io.Writer // where status JSONL is written (default: os.Stdout)
 8 	IncludeRunning      bool      // emit running status updates in addition to terminal
 9@@ -73,12 +74,14 @@ type Event struct {
10 func NewCfg() (*Cfg, string, bool) {
11 	var keyLoc, certLoc, artifactDir, event string
12 	var monitorInterval time.Duration
13+	var gcInterval time.Duration
14 	var logLevel string
15 	flag.StringVar(&keyLoc, "pk", "", "ssh private key used to authenticate with pico services")
16 	flag.StringVar(&certLoc, "ck", "", "ssh certificate public key used to authenticate with pico services (only required if using ssh certificates)")
17 	flag.StringVar(&artifactDir, "artifact-dir", "/tmp/pici-artifacts", "local directory to stage artifacts")
18 	flag.StringVar(&event, "event", "", "event JSON to run (alternative to reading from stdin)")
19 	flag.DurationVar(&monitorInterval, "monitor-interval", 5*time.Second, "interval for monitoring zmx sessions")
20+	flag.DurationVar(&gcInterval, "gc-interval", 10*time.Minute, "interval for garbage collection in monitor (0 to disable)")
21 	flag.StringVar(&logLevel, "log-level", "info", "log level: debug, info, warn, error")
22 	var includeRunning bool
23 	var human bool
24@@ -107,6 +110,7 @@ func NewCfg() (*Cfg, string, bool) {
25 		ArtifactDir:         artifactDir,
26 		Event:               event,
27 		MonitorInterval:     monitorInterval,
28+		GCInterval:          gcInterval,
29 		IncludeRunning:      includeRunning,
30 		HumanOutput:         human,
31 		Wait:                wait,
32@@ -226,6 +230,7 @@ FLAGS
33   -ck <path>               SSH certificate public key
34   -artifact-dir <path>     Local directory to stage artifacts (default: /tmp/pici-artifacts)
35   -monitor-interval <dur>  Poll interval (default: 5s)
36+  -gc-interval <dur>       Garbage collection interval (default: 10m, 0 to disable)
37   -include-running         Emit running status updates in addition to terminal (default: terminal only)
38   -human                   Human-readable output instead of JSONL (for terminal, not piping)
39   -log-level <level>       Log level: debug, info, warn, error (default: info)`)
40@@ -892,10 +897,17 @@ func runMonitor(cfg *Cfg) error {
41 	ticker := time.NewTicker(cfg.MonitorInterval)
42 	defer ticker.Stop()
43 
44+	// Optional GC ticker — runs garbage collection on a separate interval.
45+	var gcTicker *time.Ticker
46+	if cfg.GCInterval > 0 {
47+		gcTicker = time.NewTicker(cfg.GCInterval)
48+		defer gcTicker.Stop()
49+	}
50+
51 	// Track per-job display state across ticks (for human output)
52 	jobStates := make(map[string]*monitorJobState) // key: "name/jobID"
53 
54-	log.Debug("monitor started", "interval", cfg.MonitorInterval, "artifact_dir", cfg.ArtifactDir)
55+	log.Debug("monitor started", "interval", cfg.MonitorInterval, "gc_interval", cfg.GCInterval, "artifact_dir", cfg.ArtifactDir)
56 	log.Debug("monitoring ci.* sessions for job status, writing status to stdout")
57 
58 	for {
59@@ -904,10 +916,14 @@ func runMonitor(cfg *Cfg) error {
60 			log.Debug("context cancelled, stopping monitor")
61 			return cfg.Ctx.Err()
62 		case <-ticker.C:
63-		}
64-
65-		if err := monitorTick(cfg, log, output, jobStates); err != nil {
66-			log.Error("monitor tick", "err", err)
67+			if err := monitorTick(cfg, log, output, jobStates); err != nil {
68+				log.Error("monitor tick", "err", err)
69+			}
70+		case <-gcTicker.C:
71+			log.Debug("running periodic garbage collection")
72+			if err := runGC(cfg); err != nil {
73+				log.Error("periodic gc", "err", err)
74+			}
75 		}
76 	}
77 }
M tmpl/session.html
+1, -0
1@@ -17,6 +17,7 @@
2   <span>ID: {{.JobID}}</span>
3   <span>Duration: {{.Duration}}</span>
4   {{if .ExitCode}}<span>Exit: {{.ExitCode}}</span>{{end}}
5+  <span>Connect: <code>zmx attach {{.SessionName}}</code></span>
6 </div>
7 <div class="zmx-output">{{.Content}}</div>
8 <div class="links">