openvidu/openvidu-dashboard/openspec/specs/status-api/spec.md

87 lines
5.0 KiB
Markdown
Raw Permalink Normal View History

# status-api Specification
## Purpose
The server status endpoint: a cheap document with the writer schema status, the legacy migration and the writer
health that every page of the dashboard polls at a fixed cadence, whatever the page and its auto-refresh.
## Requirements
### Requirement: Status endpoint
Edition: CE. `GET /api/v1/status` SHALL require a bearer token, take no parameters and answer `200` with `generatedAt`
(the MongoDB clock), `schema` and `migration` with the same shapes and sources as `GET /api/v1/info`, and
`writer { lastSeenAt?, nodes, aliveNodes, batchIntervalMs? }`. A node's fresh window is `max(30 s, 1.5 × I + 5 s)`, I
being its `batchIntervalMs` (10 s when absent). The response carries `Cache-Control: private, no-store`.
#### Scenario: Running migration
- **GIVEN** two nodes last seen 4 s and 12 s ago, both with `batchIntervalMs: 10000`, writer schema 1 equal to the dashboard's and a migration with `processed` 400000 of `total` 1200000
- **WHEN** the client requests `GET /api/v1/status` with a valid token
- **THEN** the response is `200`, `writer.lastSeenAt` is the 4 s old timestamp, `writer.nodes` is `2`, `writer.aliveNodes` is `2`, `writer.batchIntervalMs` is `10000`, `schema.status` is `"ok"` and `migration` is `{ state: "running", progress: { processed: 400000, total: 1200000, startedAt } }`
#### Scenario: Writer never seen
- **GIVEN** empty `nodes` and `schema_meta` collections
- **WHEN** the client requests the status
- **THEN** `writer` is `{ nodes: 0, aliveNodes: 0 }`, `schema.status` is `"uninitialized"` and `migration.state` is `"none"`
#### Scenario: A node stopped reporting
- **GIVEN** `node-a` seen 4 s ago and `node-b` seen 50 s ago
- **WHEN** the client requests the status
- **THEN** `writer.nodes` is `2` and `writer.aliveNodes` is `1`
#### Scenario: Each node judged by its own interval
- **GIVEN** `node-a` with `batchIntervalMs: 60000` seen 80 s ago and `node-b` with `batchIntervalMs: 10000` seen 40 s ago
- **WHEN** the client requests the status
- **THEN** `writer.aliveNodes` is `1` (`node-a`, whose fresh window is 95 s) and `writer.batchIntervalMs` is `60000`
#### Scenario: Largest interval of the last hour
- **GIVEN** `node-a` with `batchIntervalMs: 10000` seen 5 s ago, `node-b` with `30000` seen 20 minutes ago and `node-c` with `60000` seen 2 hours ago
- **WHEN** the client requests the status
- **THEN** `writer.batchIntervalMs` is `30000`
#### Scenario: Nodes without a reported interval
- **GIVEN** one node seen 25 s ago whose document has no `batchIntervalMs`
- **WHEN** the client requests the status
- **THEN** `writer.aliveNodes` is `1`, judged with the 30 s window of a 10 s interval, and `writer` has no `batchIntervalMs`
#### Scenario: No token
- **WHEN** the client requests `GET /api/v1/status` without `Authorization`
- **THEN** the response is `401` with code `UNAUTHORIZED`
#### Scenario: Writer fields
- **WHEN** a client with a bearer token requests `GET /api/v1/status`
- **THEN** `writer.lastSeenAt` is the newest `nodes.lastSeenAt`, `writer.nodes` the node count, `writer.aliveNodes` the
nodes whose `lastSeenAt` is within their own fresh window of `generatedAt`, and `writer.batchIntervalMs` the largest
`nodes.batchIntervalMs` among the nodes whose `lastSeenAt` is within one hour of `generatedAt`, absent when none of
them reports one
### Requirement: Cheap status reads
Edition: CE. Each status request SHALL read only the `schema_meta` and `nodes` collections, both whole and bounded by
the number of server nodes, plus the MongoDB clock; it SHALL compute no storage, database or retention facts, which
stay in `GET /api/v1/info`.
#### Scenario: Commands of one request
- **GIVEN** a database generated by the data generator at scenario M
- **WHEN** the client requests the status with MongoDB command monitoring on
- **THEN** the only `find` commands target `schema_meta` and `nodes`, and no `aggregate`, `collStats` or `buildInfo` command is sent
### Requirement: Freshness windows
Edition: CE. Freshness windows SHALL derive from a batch interval I (`writer.batchIntervalMs` of the status, 10 s
when absent) through the typings helper `freshnessWindows`: fresh `max(30 s, 1.5 × I + 5 s)`, silent
`max(60 s, 2 × I + 15 s)` and stale `max(90 s, 60 s + I + 15 s)`. Clients SHALL judge the writer fresh and silent
by comparing `generatedAt − writer.lastSeenAt` with these windows, never with fixed thresholds.
#### Scenario: Default interval
- **GIVEN** a status whose `writer.batchIntervalMs` is `10000`, or absent
- **WHEN** a client derives the windows
- **THEN** fresh is 30 000 ms, silent 60 000 ms and stale 90 000 ms
#### Scenario: Slow writer
- **GIVEN** a status whose `writer.batchIntervalMs` is `60000`
- **WHEN** a client derives the windows
- **THEN** fresh is 95 000 ms, silent 135 000 ms and stale 135 000 ms
#### Scenario: Last batch 70 s old at a 60 s interval
- **GIVEN** a status with `writer.batchIntervalMs: 60000` and `writer.lastSeenAt` 70 s before `generatedAt`
- **WHEN** a client judges the writer
- **THEN** the writer is fresh and not silent