Commit a9e9d52

Eric Bower  ·  2026-08-09 10:47:31 -0400 EDT
parent 234c991
fix: proper job cancellation
2 files changed,  +26, -4
+23, -4
 1@@ -829,9 +829,9 @@ func waitAndReport(cfg *Cfg, log *slog.Logger, name, jobID, eventType string) er
 2 	ticker := time.NewTicker(interval)
 3 	defer ticker.Stop()
 4 
 5-	// Handle ^C gracefully
 6+	// Handle ^C and termination signals gracefully
 7 	sigCh := make(chan os.Signal, 1)
 8-	signal.Notify(sigCh, syscall.SIGINT)
 9+	signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
10 	defer signal.Stop(sigCh)
11 
12 	fmt.Fprintln(os.Stdout)                                //nolint:errcheck
13@@ -855,8 +855,9 @@ func waitAndReport(cfg *Cfg, log *slog.Logger, name, jobID, eventType string) er
14 			fmt.Fprintln(os.Stdout, "\n⏹ job cancelled") //nolint:errcheck
15 			return cfg.Ctx.Err()
16 		case <-sigCh:
17-			fmt.Fprintln(os.Stdout, "\n⏹ cancelled") //nolint:errcheck
18-			return nil
19+			cancelJobSessions(prefix)
20+			fmt.Fprintln(os.Stdout, "\n⏹ job cancelled") //nolint:errcheck
21+			return fmt.Errorf("job cancelled by signal")
22 		case <-ticker.C:
23 		}
24 
25@@ -1842,6 +1843,24 @@ func killSessions(names []string) error {
26 	return nil
27 }
28 
29+// cancelJobSessions finds and kills all active zmx sessions with the given prefix.
30+func cancelJobSessions(prefix string) {
31+	listOutput, err := exec.Command("zmx", "list").CombinedOutput()
32+	if err != nil {
33+		return
34+	}
35+	sessions := parseZMXList(string(listOutput))
36+	var toKill []string
37+	for _, s := range sessions {
38+		if strings.HasPrefix(s.Name, prefix) && s.Ended == "" {
39+			toKill = append(toKill, s.Name)
40+		}
41+	}
42+	if len(toKill) > 0 {
43+		_ = killSessions(toKill)
44+	}
45+}
46+
47 // runGC kills all ci. zmx sessions older than 3 hours, regardless of status.
48 func runGC(cfg *Cfg) error {
49 	log := cfg.Logger.With("cmd", "gc")
+3, -0
 1@@ -285,6 +285,9 @@ zmx run fast-step echo "done"
 2 	artifactDir := t.TempDir()
 3 	ctx, cancel := context.WithCancel(context.Background())
 4 	defer cancel()
 5+	t.Cleanup(func() {
 6+		_ = exec.Command("zmx", "kill", "-f", "local.dup-repo").Run()
 7+	})
 8 
 9 	makeCfg := func(eventSource io.ReadCloser) *Cfg {
10 		return &Cfg{