diff --git a/openvidu-dashboard/openspec/changes/lost-ingress-error/.openspec.yaml b/openvidu-dashboard/openspec/changes/lost-ingress-error/.openspec.yaml new file mode 100644 index 000000000..97e364202 --- /dev/null +++ b/openvidu-dashboard/openspec/changes/lost-ingress-error/.openspec.yaml @@ -0,0 +1,2 @@ +schema: spec-driven +created: 2026-10-27 diff --git a/openvidu-dashboard/openspec/changes/lost-ingress-error/design.md b/openvidu-dashboard/openspec/changes/lost-ingress-error/design.md new file mode 100644 index 000000000..abb17463d --- /dev/null +++ b/openvidu-dashboard/openspec/changes/lost-ingress-error/design.md @@ -0,0 +1,31 @@ +# Design + +## Context + +- `reconcileIngresses` (server) clones the publishing state of an ingress whose room or participant is gone, sets + `ENDPOINT_INACTIVE` and the end time, stores it and emits `INGRESS_ENDED`. +- The writer maps the state status to the session status (`inactive`, `error`, `complete`…) and copies `state.error` to + the session's `error`. + +## Goals / Non-Goals + +**Goals:** +- A lost session is told apart from a normal end in the store, with the error the server gave it. + +**Non-Goals:** +- Changing the ingress state customers read through the API, beyond the error text. + +## Decisions + +### Error text on an inactive state + +`ENDPOINT_ERROR` would mark the ingress itself as failed and could keep a reusable ingress from its next session. The +reset stays `ENDPOINT_INACTIVE`, and `Error: "ingress lost"` is the mark. The writer reads an `INGRESS_ENDED` with an +inactive state and an error as a session in `error`. + +Alternative rejected: accepting `inactive` for lost sessions. It hides the loss in the store and the dashboard. + +### Data model + +- No collection, field, index or schema-version change: `ingress_sessions.status` takes its existing value `error`. +- Migration from legacy events: legacy ingress events never carry this reset, so nothing changes. diff --git a/openvidu-dashboard/openspec/changes/lost-ingress-error/proposal.md b/openvidu-dashboard/openspec/changes/lost-ingress-error/proposal.md new file mode 100644 index 000000000..bcee6dbb9 --- /dev/null +++ b/openvidu-dashboard/openspec/changes/lost-ingress-error/proposal.md @@ -0,0 +1,39 @@ +# Proposal + +## Why + +When the ingress service that owns a publishing session dies and the session's room or participant is gone, the +server-side reconciler resets the ingress state to `ENDPOINT_INACTIVE`, so that a reusable ingress can be used again, +and emits `INGRESS_ENDED`. The state carries no error, so the writer stores the lost session as `inactive`, the status +of a session that ended normally. The spec requires lost ingress sessions to be projected as `error`. + +## What Changes + +- The server-side reset keeps `ENDPOINT_INACTIVE` and sets the state's error to `ingress lost`. +- The writer projects an `INGRESS_ENDED` whose state is `ENDPOINT_INACTIVE` with an error as a session in `error`, with + that error. The ingress itself stays `inactive`, ready for its next session. + +Scope excludes the following: +- The store reconciler's fallback for ingress sessions, which already closes them as `error`. +- Egress, whose server-side reconciler already ends lost egress as `FAILED`. + +Edition: CE and PRO (server and writer). Repositories: openvidu-livekit (`pkg/service/openvidu_reconciler.go`, +`openvidu/analytics/projection`) and the specs of the dashboard. + +CHANGELOG: none. The reconciler and the data model have not shipped in a release. + +## Capabilities + +### New Capabilities + +None. + +### Modified Capabilities + +- `server-reconciler`: the server-side end of a lost ingress session carries `ingress lost` and is projected as `error`. + +## Impact + +- Server: the reset of `reconcileIngresses` sets `IngressState.Error`. +- Writer: the ingress session status of `INGRESS_ENDED`. Unit or integration test of both. +- The end-to-end reconciler tests of the deployments, whose lost ingress case already expects `error`. diff --git a/openvidu-dashboard/openspec/changes/lost-ingress-error/specs/server-reconciler/spec.md b/openvidu-dashboard/openspec/changes/lost-ingress-error/specs/server-reconciler/spec.md new file mode 100644 index 000000000..d0fb59a3e --- /dev/null +++ b/openvidu-dashboard/openspec/changes/lost-ingress-error/specs/server-reconciler/spec.md @@ -0,0 +1,27 @@ +## MODIFIED Requirements + +### Requirement: Lost egress and ingress representation +Edition: CE and PRO servers. Egress and ingress lost with their node SHALL be closed by the real +`EGRESS_ENDED (FAILED)` and `INGRESS_ENDED` events of the server-side reconciler, projected as `failed` +and `error`; the store reconciler SHALL close only candidate egress and ingress sessions, always as +`failed` or `error`, never `complete`. + +#### Scenario: Egress lost after the room is gone +- **GIVEN** an egress whose handler died and whose room was deleted +- **WHEN** the server-side reconciler emits `EGRESS_ENDED` with status FAILED and error "egress lost" +- **THEN** the egress document has `status: "failed"`, `error` from the event and `closedBy: "event"` + +#### Scenario: Ingress lost after the room is gone +- **GIVEN** a publishing ingress session whose ingress service died and whose room was deleted +- **WHEN** the server-side reconciler resets its state to `ENDPOINT_INACTIVE` with error "ingress lost" and emits `INGRESS_ENDED` +- **THEN** the ingress session has `status: "error"`, `error: "ingress lost"` and `closedBy: "event"`, and the ingress is `inactive`, ready for another session + +#### Scenario: Store fallback for an egress +- **GIVEN** a candidate egress (room closed for more than 2 × cleanup interval, node dead) +- **WHEN** the reconciler closes it +- **THEN** it has `status: "failed"`, `error: "egress lost (reconciled)"`, `closedBy: "reconciler"`, `endedAt = max(room.endedAt, egress.updatedAt)` and a synthetic `EGRESS_ENDED` event exists + +#### Scenario: Store fallback for an ingress session +- **GIVEN** a candidate ingress session +- **WHEN** the reconciler closes it +- **THEN** it has `status: "error"`, `error: "ingress lost (reconciled)"`, `closedBy: "reconciler"`, `endedAt = max(room.endedAt, session.startedAt)` and its ingress document reflects the ended session diff --git a/openvidu-dashboard/openspec/changes/lost-ingress-error/tasks.md b/openvidu-dashboard/openspec/changes/lost-ingress-error/tasks.md new file mode 100644 index 000000000..d7d856b66 --- /dev/null +++ b/openvidu-dashboard/openspec/changes/lost-ingress-error/tasks.md @@ -0,0 +1,20 @@ +# Tasks + +## 1. Writer and server (openvidu-livekit) + +- [x] 1.1 Set `Error: "ingress lost"` on the state reset of `reconcileIngresses`, and project an `INGRESS_ENDED` with an + inactive state and an error as a session in `error`. Verify with the reconciler unit tests, a writer integration + test and the lint of the fork. + +## 2. Tests + +- [ ] 2.1 Run the lost ingress case of the end-to-end reconciler tests on the deployment playground. Verify that it + passes. + +## 3. Docs and CHANGELOG + +- [x] 3.1 No CHANGELOG line: unreleased. Verify by reading the change against the CHANGELOG files. + +## 4. Integration check + +- [x] 4.1 Run the spec validation and the format check of the dashboard. Verify that they pass.