Skip to content

Fix/participant count consistency#29

Merged
agonza1 merged 10 commits into
masterfrom
fix/participant-count-consistency
May 6, 2026
Merged

Fix/participant count consistency#29
agonza1 merged 10 commits into
masterfrom
fix/participant-count-consistency

Conversation

@agonza1
Copy link
Copy Markdown
Contributor

@agonza1 agonza1 commented May 5, 2026

No description provided.

Boanerges1996 and others added 8 commits April 20, 2026 21:47
Five new endpoints for the remaining dashboard charts that fetch raw data:

- GET /v1/conferences/duration-summary
    Returns conference counts bucketed by duration range (< 1m, 1-3m, etc.)
- GET /v1/conferences/participant-count-summary
    Returns distribution of conferences by participant count
- GET /v1/issues/summary
    Returns issue counts grouped by code with titles
- GET /v1/issues/gum-summary
    Returns getusermedia_error issue counts grouped by error name

Also adds three new filter params to /v1/conferences for click-to-detail
modals on these charts:
- duration_gte, duration_lt (for duration chart)
- issue_code (for most-common-issues chart)

All endpoints accept appId, created_at_gte, created_at_lte and handle
both Python native ISO format and JavaScript's toISOString Z suffix.

Phases 2 and 3 of #20 — eliminates the need for the dashboard to
download all conferences (~38MB) and all issues (~73MB).
Adds three new aggregation endpoints that let the dashboard stop
downloading full /connections and /sessions payloads to build charts
client-side:

- GET /v1/connections/summary — relay vs direct connection counts
  (replaces the Relayed-connections pie chart's client-side reduce)
- GET /v1/connections/setup-time-summary — connection setup-time
  buckets with per-bucket conference_ids for click-to-detail
- GET /v1/sessions/summary — browsers, OS, country, and city/geo
  aggregates (powers Browsers, OS, and Map charts in one roundtrip)

Also accepts `conference_ids=a,b,c` on /conferences so the setup-time
chart can page through matched conferences on click.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
…se C of #20)

With Phases 0-5 merged, every dashboard chart reads from a server-side
aggregation endpoint. The SQL is fast with indexes, but the same ~8
queries run on every page load, and the heavy ones (sessions.summary,
connections.setup_time_summary) still cost 400-800ms on a live tenant.

Adds a thin caching layer in front of each summary view:

- `app/summary_cache.py` — `cached_json(endpoint, request, compute)`
  hashes (endpoint + filter params) into a short key, reads Redis,
  falls through to `compute()` on miss, and writes back with a 60s TTL.
  Redis failures are tolerated (settings already has IGNORE_EXCEPTIONS).
- Each of the eight summary views moves its existing compute body into
  a local `compute()` closure and returns through the helper. No change
  to the JSON shape, query logic, or error handling.
- `manage.py prewarm_summaries` — scheduled command that iterates apps
  with recent traffic (default: any conference in the last 2 days) and
  runs every summary view with the 30d-window filters the dashboard
  sends by default. Intended to run every ~30s as an ECS scheduled
  task so first visitors never see a cold miss.

Measured locally against a 7-day Production clone (~18k conferences /
38k sessions / 38k connections):

  endpoint                               cold      warm
  conferences/summary                    391ms  →   12ms   (33x)
  sessions/summary                       748ms  →   11ms   (68x)
  connections/setup_time_summary         373ms  →   11ms   (34x)
  conferences/participant_count_summary  216ms  →    7ms   (31x)
  issues/gum_summary                     107ms  →    6ms   (18x)
  connections/summary                     57ms  →    6ms   (9.5x)
  issues/summary                          45ms  →   86ms   (noise; both <100ms)
  conferences/duration_summary            19ms  →    8ms   (2.3x)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Unit-test cache key rules, hit/miss, TTL override, and soft-fail on get/set errors.
- Smoke-test prewarm_summaries for zero apps and one recent app (8 views).

Made-with: Cursor
The dashboard sends `new Date().toISOString()` minus 30 days as
created_at_gte (web app.vue:189), which is millisecond-precise. With the
unrounded value going straight into _make_key, every page load — even
back-to-back reloads — produced a unique SHA1 digest and a fresh cache
miss, so the warm path never served real users:

  flush redis -> 0 keys
  load dashboard -> 8 keys
  reload         -> 16 keys (8 stale + 8 fresh)

prewarm_summaries had the same problem on the write side: its own
since_window = utcnow() - 30d advanced every run, so the entries it
populated never matched what the dashboard requested.

Truncate ISO timestamps to the minute (YYYY-MM-DDTHH:MM) before hashing,
so two requests in the same wall-clock minute share an entry. Correctness
still holds because the 60s TTL bounds staleness regardless of bucket
size.

After the fix, two same-minute dashboard loads both produce 8 keys (no
growth), and the 2nd load's slow endpoints serve from cache:

                                       before    after
  /v1/sessions/summary                 2314ms ->  411ms
  /v1/connections/setup-time-summary   1117ms ->  229ms
  /v1/conferences/summary               994ms ->   48ms

Two regression tests added covering the bucket and the minute boundary.
Count only active non-SFU participants with a session on the conference,
excluding peer stubs without sessions and SFU endpoints. Shared annotation
in conference_query.py used by conferences list and participant-count summary.

Co-authored-by: Cursor <cursoragent@cursor.com>
@agonza1
Copy link
Copy Markdown
Contributor Author

agonza1 commented May 5, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: f2c7aef4ce

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread app/conference_query.py Outdated
agonza1 and others added 2 commits May 5, 2026 19:55
Use a correlated Subquery instead of Count on the outer participants join.
Filtering by participantId narrowed that join to one person, so the
aggregate incorrectly showed 1 for multi-participant calls. The subquery
counts independently. Add regression test.

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
@agonza1 agonza1 merged commit 64df5eb into master May 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants