How can I manage to place an overflow of participants in optimally created dynamic Rooms?

As a follow up to my other question regarding random pairings, I've hit another interesting engineering problem. At the moment, I have my group room set to the max limit of 50 participants. However, I expect to have 1000+ participants arrive when this campaign launches. It is not important that all 1000 of these participants are placed in the same room but it is important that there is a room available for them. And it would be best, if this room had several other participants in it. So, can you recommend a way of placing users into rooms at scale?

In the past, I've handled this in a rather hacky way based on thrown join errors. If the user was not allowed in Room 1, I'd try to place them in Room 2. And so on, or err.. as many errors as it took. Using this sad logic, if the first 10 rooms were full, the user would have to wait through 10 errors in order to get placed accordingly.

I thought about using the REST API to check how many participants were in each room in order to recommend an available room but I suspect this will still cause issues if multiple users were all recommended the same room at once.

Another idea is to estimate the amount of participants we might receive, create X number of rooms, and place those visitors into a random room rather than placing them in a linear fashion. A more distributed approach but would need to finesse room quantity manually.

I realize this is less of a Twilio question and more of an engineering problem but I was wondering how you would approach it. Any help is much appreciated!

Answers

  • shelbyz
    shelbyz ✭✭✭

    You may still be able to use the room join error logic but with a twist. Have an endpoint that attempts a conditional update (using revision property with ifMatch) on the sync doc with the room name. If it succeeds create a new room using that name, if it fails read the sync doc for the latest room name. In either case return that latest room for the client to join.

    When a client logs in, read the sync doc for the latest room and attempt joining. If failure, call that endpoint and have it return the room to join.

    I could not find a good example of using revision property but it would be fairly similar to this (just add revision values on the sync doc to ifMatch property to the update request - https://www.twilio.com/docs/sync/api/document-resource?code-sample=code-update-a-document-using-the-rest-api&code-language=Node.js&code-sdk-version=3.x

  • leemartin
    leemartin ✭✭✭
    edited July 21

    Hey @shelbyz, is this suggestion assuming I'm using Twilio Sync (I'm not) or is sync docs part of Twilio Video somehow? Regardless, this solution certainly flew over my head. 😅

    For additional context, my followers and I are discussing general system design solutions here:

  • leemartin
    leemartin ✭✭✭

    Here's a little function which gets all rooms and then gets all participants in those room. From here, I can figure out which rooms still have available spots and return those room names as an array to the client before connect() (The client chooses at random) If there isn't an available room, I simply create a brand new one with a random id.

    const client = require('twilio')(process.env.TWILIO_ACCOUNT_SID, process.env.TWILIO_AUTH_TOKEN)
    const { v4: uuidv4 } = require('uuid')
    
    exports.handler = async (event, context) => {
      try {
        // get all rooms
        let rooms = await client.video.rooms.list()
    
        // get all participants from all rooms
        await Promise.all(rooms.map(async (room) => {
          let participants = await client.video.rooms(room.sid).participants.list()
    
          room.participantCount = participants.length
        }))
    
        // get available rooms
        let availableRooms = rooms.filter(room => {
          return room.maxParticipants != room.participantCount
        })
    
        let names
    
        if (availableRooms.length) {
          // available room names
          names = availableRooms.map(room => {
            return room.uniqueName
          })
    
        } else {
          // new room name
          names = [`leemartin-${uuidv4()}`]
    
        }
    
        return {
          statusCode: 200,
          body: JSON.stringify(names)
        }
    
      } catch (error) {
        return {
          statusCode: 500,
          body: error.toString()
        }
      }
    }
    
    

    I'm not a huge fan of this solution but I'm trying to be proactive on this client project. Questions

    • Does client.video.rooms.list() return ALL rooms?
    • Can I get the participant count when calling rooms.list() vs calling participants.list()?
  • shelbyz
    shelbyz ✭✭✭

    Yeah I was suggesting making use of Twilio Sync (Docs specifically), as you may run into unexpected problems having each users make a query to list all available rooms and find ones with capacity. It would work for small numbers but as the system scales returning a large list of rooms and then iterating over every room will take an increasing large amount of time.

  • leemartin
    leemartin ✭✭✭

    Cheers @shelbyz. I'm not very familiar with Twilio Sync. Any chance you could provide a simple explanation of the service and how your solution solves the problem?

  • @leemartin A little birdie told me you had a call with the support team to get this sorted.😃🐦

    Do you mind sharing your findings here to help out future community members? I would greatly appreciate it!

  • leemartin
    leemartin ✭✭✭

    Yes! I had a great call with Brian about potentially using Sync to manage a sort of realtime inventory. Don't worry, I will share my solution once I cobble it together. Both here and on the blog: https://leemartin.dev So inspired by this platform!

  • Amazing, happy to hear it! Thank you, @leemartin. ✨

  • shelbyz
    shelbyz ✭✭✭

    @leemartin - sorry the notifications never reached an inbox, it sounds like you got sorted on Sync. Let me know where it all lands.

Sign In or Register to comment.