notify router: deliveries log, dry-run hit counts, api and page
This commit is contained in:
parent
6dd9d0086e
commit
ed1fd053e7
24 changed files with 1848 additions and 40 deletions
|
|
@ -171,17 +171,68 @@ controller that predates it, gets no answer to the request and logs that. A cont
|
|||
router runs the built-ins as before. A router that predates this ignores the
|
||||
document, so the page and the API show a state the router isn't yet running.
|
||||
|
||||
## Deliveries and dry runs
|
||||
|
||||
**The deliveries log.** The router appends one row to the `NOTIFY_ROUTER_LOG`
|
||||
stream for each delivery it makes, and the stream keeps the newest 500. A
|
||||
delivery is a todo op queued for an agent or a review requested from the
|
||||
controller, whether it went through or not. A row has:
|
||||
|
||||
| Field | Holds |
|
||||
| ------------------------- | ---------------------------------------------------------------------------------- |
|
||||
| `at` | Unix seconds |
|
||||
| `flow`, `node` | the flow and the node that delivered |
|
||||
| `event`, `repo`, `number` | the forge event type and the issue or PR it concerns |
|
||||
| `kind`, `target` | `todo` and the agent, or `request_reviewer` and the reviewer |
|
||||
| `ok`, `detail` | whether it went through, and the op and key, the controller's answer, or the error |
|
||||
|
||||
A review the controller skipped (`skipped: <why>`) is `ok`: nothing was
|
||||
wrong. An event the router retries after a failed step writes its rows again,
|
||||
so a retry shows twice. When the router fails to write a row, it logs the failure and the delivery
|
||||
stands.
|
||||
|
||||
**The dry run.** The router runs a flows document over the newest 50 events of
|
||||
the `SWARM_EVENTS` stream and returns, for each flow the document turns on,
|
||||
how many of those events reached each node. A `match` node counts the events
|
||||
that passed it. It uses the walk the router delivers with and delivers nothing:
|
||||
no todo op, no review request, no log row and no snapshot written. It keeps
|
||||
its own per-issue snapshots, starting empty, so the first assign event it
|
||||
replays for an issue counts every assignee as newly added. Every recipient
|
||||
counts as an agent.
|
||||
|
||||
**The API.** The router answers two NATS requests from swarm-controller, which
|
||||
serves them next to `GET /api/notify/flows`:
|
||||
|
||||
| Route | Router subject | Answers |
|
||||
| ---------------------------- | ------------------------------ | ------------------------------------------------------------------ |
|
||||
| `GET /api/notify/deliveries` | `$SWARM.router.api.deliveries` | the newest rows, newest first; `?limit=` up to 500, 100 by default |
|
||||
| `GET /api/notify/dry-run` | `$SWARM.router.api.dry-run` | the saved flows document, run over the newest 50 events |
|
||||
|
||||
The dry-run request carries a whole document, so a draft runs the same way.
|
||||
The controller sends the saved one. [`/notifications`](ui.md#notification-flows)
|
||||
shows both: the recent deliveries, and the counts beside each node.
|
||||
|
||||
**Deploying in any order.** A router that predates these subjects doesn't
|
||||
subscribe to them, and the queue answers the controller's request at once with
|
||||
no responders. Both routes then answer 503 saying the router doesn't answer
|
||||
and may be an older build, and the page shows that in place of the table and
|
||||
the counts. A request the router hears and doesn't answer within 10 seconds is
|
||||
the same 503. A router that answers with a refusal, or with something the
|
||||
controller can't read, is 502. A controller that predates the routes has no
|
||||
route: the page, if newer, shows the failure.
|
||||
|
||||
## Credentials and grants
|
||||
|
||||
| Principal | Grant |
|
||||
| --------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `swarm-notify-router`, in its container | store: `read` on `swarm/services/<router client id>/oidc/client`. Queue: its own consumer on `SWARM_EVENTS` (create, pull, ack), publish on `$SWARM.router.todo.*` and on `$SWARM.router.sink.request-reviewer`, create `ROUTER_TODOS`, its own `notify-router-state` bucket, read on the `notify-flows` bucket, and `STREAM.INFO` on the agent-status bucket, which lists the agents |
|
||||
| swarm-controller | publish on `$SWARM.events.forge.*`; subscribe to `$SWARM.router.sink.request-reviewer` and answer each request once, for 30 seconds; creates and writes the `notify-flows` bucket (every bucket, by its `$KV.*.>` grant) |
|
||||
| an agent, under its own credential | create its own consumer `todo-<agent>` in the form whose filter is `$SWARM.router.todo.<agent>`, pull from it, and ack what it delivered |
|
||||
| Principal | Grant |
|
||||
| --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `swarm-notify-router`, in its container | store: `read` on `swarm/services/<router client id>/oidc/client`. Queue: its own consumer on `SWARM_EVENTS` (create, pull, ack) and `STREAM.MSG.GET` on it for the dry run, publish on `$SWARM.router.todo.*` and on `$SWARM.router.sink.request-reviewer`, create `ROUTER_TODOS`, create `NOTIFY_ROUTER_LOG`, publish its one subject and read it by sequence, its own `notify-router-state` bucket, read on the `notify-flows` bucket, `STREAM.INFO` on the agent-status bucket, which lists the agents, and subscribe to the two `$SWARM.router.api.*` request subjects and answer each once, for 10 seconds |
|
||||
| swarm-controller | publish on `$SWARM.events.forge.*` and on the two `$SWARM.router.api.*` request subjects; subscribe to `$SWARM.router.sink.request-reviewer` and answer each request once, for 30 seconds; creates and writes the `notify-flows` bucket (every bucket, by its `$KV.*.>` grant) |
|
||||
| an agent, under its own credential | create its own consumer `todo-<agent>` in the form whose filter is `$SWARM.router.todo.<agent>`, pull from it, and ack what it delivered |
|
||||
|
||||
No other client may publish on `$SWARM.router.todo.*`, `$SWARM.router.sink.request-reviewer` or
|
||||
No other client may publish on `$SWARM.router.todo.*`, `$SWARM.router.log`, the two
|
||||
`$SWARM.router.api.*` subjects, `$SWARM.router.sink.request-reviewer` or
|
||||
`$SWARM.events.forge.*`, so each has one writer, and the controller alone
|
||||
hears the review requests. The review request needs no secret of its own: the
|
||||
hears the review requests and the router alone hears the api requests. The review request needs no secret of its own: the
|
||||
controller asks the forge under the token it already holds. The agent's create subject
|
||||
carries the consumer's filter, and the queue server checks it against the
|
||||
request, so an agent can't create a consumer that delivers another agent's
|
||||
|
|
|
|||
Loading…
Reference in a new issue