Skip to content

Commit de092bd

Browse files
committed
fix: gate inline cleanup behind ENABLE_INLINE_CONFERENCE_CLEANUP flag
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.
1 parent 776c933 commit de092bd

2 files changed

Lines changed: 31 additions & 0 deletions

File tree

README.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,28 @@ The table below lists all environment variables used by the API. Variables marke
109109
| `GOOGLE_TASK_QUEUE_NAME` | No | - | Name of the Cloud Tasks queue (e.g. `queue-1`). Required when `USE_GOOGLE_TASK_QUEUE` is `True`. |
110110
| `APP_ENGINE_LOCATION` | No | - | App Engine location (e.g. `us-east1`). Required when `USE_GOOGLE_TASK_QUEUE` is `True`. |
111111
| `TASK_QUEUE_DOMAIN` | No | - | Domain for task queue callbacks (e.g. `https://api.example.com/`). Required when `USE_GOOGLE_TASK_QUEUE` is `True`. |
112+
| **Conference Cleanup** | | | |
113+
| `CONFERENCE_TIMEOUT_HOURS` | No | `4` | Close ongoing conferences with no activity for this many hours. |
114+
| `ENABLE_INLINE_CONFERENCE_CLEANUP` | No | `false` | Set to `true` to run cleanup in a background thread (dev/single-process only). |
115+
| `CONFERENCE_CLEANUP_INTERVAL_SECONDS` | No | `3600` | How often the inline cleanup runs in seconds. Set to `0` to disable. Only applies when `ENABLE_INLINE_CONFERENCE_CLEANUP` is `true`. |
116+
117+
### Stale Conference Cleanup
118+
119+
Conferences can get stuck as "Ongoing" if the client fails to send the end signal (browser tab closed, network drop). The `cleanup_stale_conferences` management command closes conferences with no activity for a configurable period.
120+
121+
```bash
122+
python manage.py cleanup_stale_conferences # default 4 hour threshold
123+
python manage.py cleanup_stale_conferences --hours 2 # custom threshold
124+
python manage.py cleanup_stale_conferences --dry-run # preview without changes
125+
```
126+
127+
**Development:** Set `ENABLE_INLINE_CONFERENCE_CLEANUP=true` to run the cleanup automatically in a background thread inside the API process.
128+
129+
**Production (multi-worker):** Do not use the inline loop with multiple gunicorn workers as each worker runs its own cleanup loop. Instead, use an external scheduler:
130+
131+
- **Kubernetes:** CronJob running `python manage.py cleanup_stale_conferences`
132+
- **Docker Compose:** Host cron or a sidecar container on a timer
133+
- **ECS:** Scheduled task via EventBridge
112134

113135
**Example `.env` file for local development:**
114136

app/apps.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,15 @@ class UsersConfig(AppConfig):
1717
def ready(self):
1818
global _cleanup_started
1919

20+
# The inline cleanup loop is for dev/single-process only.
21+
# In production with multiple gunicorn workers, each worker forks
22+
# a separate process so the threading lock cannot prevent duplicate
23+
# loops. Use an external scheduler instead:
24+
# python manage.py cleanup_stale_conferences
25+
# Set ENABLE_INLINE_CONFERENCE_CLEANUP=true to enable the loop.
26+
if os.getenv('ENABLE_INLINE_CONFERENCE_CLEANUP', '').lower() != 'true':
27+
return
28+
2029
interval = int(os.getenv('CONFERENCE_CLEANUP_INTERVAL_SECONDS', 3600))
2130
if interval <= 0:
2231
return

0 commit comments

Comments
 (0)