Skip to content

feat: add management command to close stale ongoing conferences#9

Merged
Mupati merged 5 commits into
peermetrics:masterfrom
Boanerges1996:feat/cleanup-stale-conferences
Apr 1, 2026
Merged

feat: add management command to close stale ongoing conferences#9
Mupati merged 5 commits into
peermetrics:masterfrom
Boanerges1996:feat/cleanup-stale-conferences

Conversation

@Boanerges1996
Copy link
Copy Markdown
Contributor

Summary

Add a Django management command to automatically close conferences stuck as "Ongoing" when there has been no event activity for a configurable threshold.

Problem

Conferences show as "Ongoing" indefinitely when the client fails to call endCall() (browser tab closed, network drop, SDK not initialized). There is no server-side mechanism to clean these up.

Solution

New management command cleanup_stale_conferences that:

  • Finds all conferences with ongoing=True
  • Checks the most recent GenericEvent timestamp for each
  • Closes conferences where the last activity exceeds the threshold (default: 4 hours)
  • Properly ends all open connections, sessions, and the conference itself

Uses last event activity instead of conference creation time, so long-running active sessions (e.g., a 6-hour meeting still sending stats) are not affected.

Usage

# Preview what would be closed
python manage.py cleanup_stale_conferences --dry-run

# Close conferences with no activity for 4+ hours (default)
python manage.py cleanup_stale_conferences

# Custom threshold
python manage.py cleanup_stale_conferences --hours 2

Can be scheduled as a cron job to run hourly.

Test plan

  • Start a test conference, don't end it
  • Run with --dry-run -- verify it shows the stale conference
  • Run without --dry-run -- verify conference is closed
  • Verify active conferences with recent events are not affected

Adds cleanup_stale_conferences command that finds conferences with no
event activity for longer than a threshold (default 4 hours) and
closes them. Uses last GenericEvent timestamp, not conference creation
time, so long-running active sessions are not affected.

Usage:
  python manage.py cleanup_stale_conferences
  python manage.py cleanup_stale_conferences --hours 2
  python manage.py cleanup_stale_conferences --dry-run
- Wrap each conference close in transaction.atomic() to match
  StopConferenceView and avoid partial updates
- Isolate errors per conference with try/except so one bad row
  doesn't abort the rest
- Use annotated query with Subquery to avoid N+1 queries
- Add last_connection_at as fallback activity signal for conferences
  with no events
- Read default hours from CONFERENCE_TIMEOUT_HOURS env var
- Use consistent datetime.utcnow() throughout
Start a daemon thread in AppConfig.ready() that runs the cleanup
periodically. No cron or external scheduler needed.

Configurable via env vars:
  CONFERENCE_CLEANUP_INTERVAL_SECONDS (default: 3600)
  CONFERENCE_TIMEOUT_HOURS (default: 4)

Set CONFERENCE_CLEANUP_INTERVAL_SECONDS=0 to disable.
- Add default_app_config in __init__.py so Django picks up the AppConfig
- Use a module-level lock to ensure only one cleanup thread starts
  (gunicorn calls ready() multiple times for master + workers)
- Remove debug print statements
The background thread in AppConfig.ready() only dedupes within one
process (threading lock). With multiple gunicorn workers, each worker
forks a separate process and runs its own cleanup loop.

Gate the inline loop behind ENABLE_INLINE_CONFERENCE_CLEANUP=true so
it's opt-in for dev/single-process. Production should use an external
scheduler to run the management command.

Also added cleanup documentation to README with dev vs production
guidance.
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