- commit
- c1c7f7b
- parent
- 0ce812c
- author
- Eric Bower
- date
- 2026-04-29 09:46:08 -0400 EDT
feat(wait): summary of failed tasks and actionable commands to run This simply prints the failed tasks and shows some commands to run to see what went wrong.
1 files changed,
+46,
-13
+46,
-13
1@@ -1477,11 +1477,12 @@ fn wait(cfg: *Cfg, matchers: std.ArrayList(SessionMatch)) !void {
2 var max_seen: i32 = 0;
3 var zero_match_iters: u32 = 0;
4
5+ var agg_exit_code: u8 = 0;
6 while (true) {
7+ agg_exit_code = 0;
8 var sessions = try util.get_session_entries(alloc, cfg.socket_dir);
9 var total: i32 = 0;
10 var done: i32 = 0;
11- var agg_exit_code: u8 = 0;
12
13 for (sessions.items) |session| {
14 var found = false;
15@@ -1502,8 +1503,8 @@ fn wait(cfg: *Cfg, matchers: std.ArrayList(SessionMatch)) !void {
16 // persist as task_ended_at==0 forever → infinite "still
17 // waiting". Count it as done+failed so wait terminates.
18 try stderr.print(
19- "task unreachable: {s} ({s})\n",
20- .{ session.name, session.error_name orelse "unknown" },
21+ "[{d}] task unreachable: {s} ({s})\n",
22+ .{ std.time.timestamp(), session.name, session.error_name orelse "unknown" },
23 );
24 try stderr.flush();
25 agg_exit_code = 1;
26@@ -1511,11 +1512,17 @@ fn wait(cfg: *Cfg, matchers: std.ArrayList(SessionMatch)) !void {
27 continue;
28 }
29 if (session.task_ended_at == 0) {
30- try stdout.print("waiting task={s}\n", .{session.name});
31+ try stdout.print(
32+ "[{d}] waiting task={s}\n",
33+ .{ std.time.timestamp(), session.name },
34+ );
35 try stdout.flush();
36 continue;
37 }
38- try stdout.print("completed task={s} exit_code={d}\n", .{ session.name, session.task_exit_code.? });
39+ try stdout.print(
40+ "[{d}] completed task={s} exit_code={d}\n",
41+ .{ session.task_ended_at.?, session.name, session.task_exit_code.? },
42+ );
43 try stdout.flush();
44 if (session.task_exit_code != 0) {
45 agg_exit_code = session.task_exit_code orelse 0;
46@@ -1543,14 +1550,7 @@ fn wait(cfg: *Cfg, matchers: std.ArrayList(SessionMatch)) !void {
47 max_seen = total;
48
49 if (total > 0 and total == done) {
50- if (agg_exit_code == 0) {
51- try stdout.print("task(s) completed!\n", .{});
52- } else {
53- try stdout.print("task(s) failed!\n", .{});
54- }
55- try stdout.flush();
56- std.process.exit(agg_exit_code);
57- return;
58+ break;
59 }
60
61 if (max_seen == 0) {
62@@ -1569,6 +1569,39 @@ fn wait(cfg: *Cfg, matchers: std.ArrayList(SessionMatch)) !void {
63
64 std.Thread.sleep(1000 * std.time.ns_per_ms);
65 }
66+
67+ if (agg_exit_code == 0) {
68+ try stdout.print("task(s) completed!\n", .{});
69+ } else {
70+ try stdout.print("task(s) failed!\n", .{});
71+ }
72+ try stdout.flush();
73+
74+ const sessions = try util.get_session_entries(alloc, cfg.socket_dir);
75+ for (sessions.items) |session| {
76+ var found = false;
77+ for (matchers.items) |m| {
78+ if (m.matches(session.name)) {
79+ found = true;
80+ break;
81+ }
82+ }
83+ if (!found) {
84+ continue;
85+ }
86+ if (session.task_exit_code.? > 0) {
87+ try stdout.print("---\n", .{});
88+ try stdout.print("[{d}] failed task={s} exit_status={d}\n\n", .{
89+ session.task_ended_at.?,
90+ session.name,
91+ session.task_exit_code.?,
92+ });
93+ try stdout.print("See the logs:\nzmx history {s}\nzmx attach {s}\n", .{ session.name, session.name });
94+ try stdout.flush();
95+ }
96+ }
97+
98+ std.process.exit(agg_exit_code);
99 }
100
101 fn list(cfg: *Cfg, short: bool) !void {