You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat(client): scrollable watch, and a gateway address nobody has to copy
## Summary
### Why?
Two things made a watch awkward to actually use.
**A big table could only be trimmed.** The previous change stopped a frame taller than the window from repainting the screen, by dropping settled rows and saying how many it had dropped. That keeps the redraw honest but it is still a table you cannot read: the rows are there, and the only reason they are not on screen is that the renderer had to choose. What a reader wants is what `top` gives them — the whole table, and a way to move through it.
**The gateway address had to be copied by hand, and went stale.** Compose publishes a fresh random port on every start, so a `GATEWAY_ADDR` noted from an earlier run points at a port that no longer exists, and every demo command fails with a connection refused that says nothing about why. That is not a hypothetical: it is the most common way these commands fail.
### What?
**A watch of a queue is now a scrollable full-screen view.** It takes the alternate buffer while it runs, reads keys in raw mode, and gives the screen back untouched afterwards:
| Key | |
|---|---|
| `↑` `↓` / `k` `j` | one row |
| `PgUp` `PgDn` / `Space` | one screen |
| `g` `G` | first row, last row |
| `q` | stop watching |
It follows the end of the table by default, so rows and stages appear without anyone touching it; scrolling up holds the reader's place, and scrolling back to the bottom resumes following. There is no dedicated key for that, because being at the end is what following is.
The full-screen view also removes the class of bug the trimming worked around, rather than managing it: the alternate buffer never scrolls, so each frame is painted from the top and there is no previous frame to find. The trimming path remains for the case where it is still needed — a terminal on stdout but not on stdin, where there is a screen to draw on but nobody to press a key.
The finished table is printed into the restored screen whole, however tall it is. Nothing is drawn over it, so a long one scrolls, which is what a reader of a completed run wants.
No new dependency: `golang.org/x/term` was already in use for the window size and provides raw mode too.
**`make land`, `land-status`, `land-list`, `land-watch` and `demo-requests` find the gateway themselves**, by asking Docker for the running stack's published port. `GATEWAY_ADDR` is now an override for reaching a gateway the Makefile did not start, and a stack that is not running produces a sentence saying so rather than a refused connection. The resolution is done inside each recipe rather than as a `$(shell ...)` assignment, which would shell out to Docker on every `make help`.
## Test Plan
- ✅ drove the view through a pty with real keystrokes — `G`, two up-arrows, `PgUp`, `q` — and read the positions back out of the footer: `40-40 → 39-40 → 38-40 → 36-40 of 40`, then a clean exit
- ✅ the alternate screen is entered once and left once in every run captured, so the terminal is never left on it
- ✅ after `q`, all 40 rows are printed into the restored screen; after a settled 25-request run, all 25 are, with nothing hidden
- ✅ `make demo-requests` and `make land-list` with no `GATEWAY_ADDR` set at all; with it set explicitly; and with no stack running, which now says `No gateway found: 'submitqueue' is not running`
- ✅ redirected output still produces a plain log: `make demo-requests LAND=false` and piped runs take neither the screen nor the keyboard
- ✅ new tests for the parts that are not a terminal: every key and escape sequence including one split across reads, and the scroll arithmetic — bounds, paging, and that scrolling up releases follow while rows arriving do not move a view that has scrolled away
- ✅ `make test` (105 targets), `make lint`, `make gazelle`
Two behaviours worth knowing. A bare `Escape` is not acted on until another key follows, and swallows it — the alternative is misreading an arrow whose bytes arrive in separate reads, which is worse and intermittent. And with tall wrapped rows in a short window, moving up one row can land back at the bottom, because the number of rows that fit changes with their height.
Copy file name to clipboardExpand all lines: doc/howto/QUICKSTART.md
+12-7Lines changed: 12 additions & 7 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -28,13 +28,7 @@ Compose publishes each service on a **random** host port so several stacks can r
28
28
Gateway gRPC port: 58537
29
29
```
30
30
31
-
Export it, because every command below needs it:
32
-
33
-
```bash
34
-
export GATEWAY_ADDR=localhost:58537
35
-
```
36
-
37
-
Leaving it unset does not fall back to anything useful — the client's default is `localhost:8081`, the `go run` port rather than the compose one.
31
+
You do not have to note it down. Every command below finds the running stack's port for itself, which matters because Compose picks a fresh one on every start — a number copied from an earlier run is the most common reason a demo command cannot connect. Set `GATEWAY_ADDR=host:port` only to reach a gateway this Makefile did not start.
38
32
39
33
## Put traffic through it
40
34
@@ -118,6 +112,17 @@ Eight builds means the batch was speculating down eight paths at once, and `wait
118
112
119
113
`land-watch` fixes its set when it starts and exits non-zero if any request in that set finishes anywhere other than `landed`, which makes it usable from a script. A request accepted after the watch begins is not picked up: a watch that grew as the queue did would never finish.
120
114
115
+
Watching more requests than the window holds takes over the screen while it runs, the way `top` does, so the table can be scrolled rather than trimmed:
116
+
117
+
| Key ||
118
+
|---|---|
119
+
|`↑``↓` or `k``j`| one row |
120
+
|`PgUp``PgDn` or `Space`| one screen |
121
+
|`g``G`| first row, last row |
122
+
|`q`| stop watching |
123
+
124
+
The view follows the end of the table by default, so new rows and new stages appear without touching it. Scrolling up holds your place; scrolling back to the bottom starts following again. The screen you had is restored on exit and the finished table is printed into it whole, so nothing is lost with the view — and when output is redirected, none of this happens at all and the run stays a plain log.
125
+
121
126
A listing of a busy queue is mostly `speculating` rows, since that is where a request spends most of its active life — waiting on the build its batch was admitted for.
122
127
123
128
Under the hood these are `client list` and `client watch`, which take a queue and reach any gateway:
0 commit comments