✨(backend) add 10-digit PIN codes on rooms for telephony
Enable users to join rooms via SIP telephony by: - Dialing the SIP trunk number - Entering the room's PIN followed by '#' The PIN code needs to be generated before the LiveKit room is created, allowing the owner to send invites to participants in advance. With 10-digit PINs (10^10 combinations) and a large number of rooms (e.g., 1M), collisions become statistically inevitable. A retry mechanism helps reduce the chance of repeated collisions but doesn't eliminate the overall risk. With 100K generated PINs, the probability of at least one collision exceeds 39%, due to the birthday paradox. To scale safely, we’ll later propose using multiple trunks. Each trunk will handle a separate PIN namespace, and the combination of trunk_id and PIN will ensure uniqueness. Room assignment will be evenly distributed across trunks to balance load and minimize collisions. Following XP principles, we’ll ship the simplest working version of this feature. The goal is to deliver value quickly without over-engineering. We’re not solving scaling challenges we don’t currently face. Our production load is around 10,000 rooms — well within safe limits for the initial implementation. Discussion points: - The `while` loop should be reviewed. Should we add rate limiting for failed attempts? - A systematic existence check before `INSERT` is more costly for a rare event and doesn't prevent race conditions, whereas retrying on integrity errors is more efficient overall. - Should we add logging or monitoring to track and analyze collisions? I tried to balance performance and simplicity while ensuring the robustness of the PIN generation process.
This commit is contained in:
committed by
aleb_the_flash
parent
d70dc41643
commit
3e93f5924c
45
src/backend/core/migrations/0014_room_pin_code.py
Normal file
45
src/backend/core/migrations/0014_room_pin_code.py
Normal file
@@ -0,0 +1,45 @@
|
||||
# Generated by Django 5.1.9 on 2025-05-13 08:22
|
||||
|
||||
import secrets
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
def generate_pin_for_rooms(apps, schema_editor):
|
||||
"""Generate unique 10-digit PIN codes for existing rooms.
|
||||
The PIN code is required for SIP telephony features.
|
||||
"""
|
||||
Room = apps.get_model('core', 'Room')
|
||||
rooms_without_pin_code = Room.objects.filter(pin_code__isnull=True)
|
||||
existing_pins = set(Room.objects.values_list('pin_code', flat=True))
|
||||
|
||||
length = 10
|
||||
|
||||
def generate_pin_code():
|
||||
while True:
|
||||
pin_code = str(secrets.randbelow(10 ** length)).zfill(length)
|
||||
if not pin_code in existing_pins:
|
||||
return pin_code
|
||||
|
||||
for room in rooms_without_pin_code:
|
||||
room.pin_code = generate_pin_code()
|
||||
room.save()
|
||||
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0013_alter_user_language'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='room',
|
||||
name='pin_code',
|
||||
field=models.CharField(blank=True, help_text='Unique n-digit code that identifies this room in telephony mode.', max_length=None, null=True, unique=True, verbose_name='Room PIN code'),
|
||||
),
|
||||
migrations.RunPython(
|
||||
generate_pin_for_rooms,
|
||||
reverse_code=migrations.RunPython.noop
|
||||
),
|
||||
]
|
||||
Reference in New Issue
Block a user