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 }
+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">