in projects/deliberation_at_scale/packages/orchestrator/src/tasks/handleQueuedParticipants.ts [156:271]
async function performDynamicGroupSlicing(helpers: Helpers) {
const queuedParticipantsResult = await supabaseClient
.from('participants')
.select()
.eq('active', true)
.eq('status', 'queued')
.order('created_at', { ascending: false });
const allQueuedParticipants = queuedParticipantsResult.data ?? [];
const queuedParticipants = unique(allQueuedParticipants, (participant) => {
return participant.user_id ?? '';
});
const queuedParticipantIds = queuedParticipants.map((participant) => participant.id);
const skippedParticipantIds = queuedParticipants.filter((participant) => {
return !queuedParticipantIds.includes(participant.id);
}).map((participant) => participant.id);
const queuedParticipantsAmount = queuedParticipants?.length ?? 0;
// guard: see if we need to deactive some participants
if (skippedParticipantIds.length > 0) {
const { data: deactivatedParticipants } = await supabaseClient
.from("participants")
.update({ active: false })
.in('id', skippedParticipantIds)
.select();
helpers.logger.info(`Deactivated ${deactivatedParticipants?.length} skipped participants.`);
}
helpers.logger.info(`There are currently ${queuedParticipantsAmount} queued participants waiting for a room...`);
// guard: check if there are enough participants to assign to a room
if (queuedParticipantsAmount < PARTICIPANTS_PER_ROOM) {
helpers.logger.info(`Not enough participants to assign to a room, waiting for more participants...`);
return;
}
// will sort the participants randomly for now and assign four of them per room
const shuffledParticipants = shuffle(queuedParticipants);
// get all current topics and put them in an array so the participants can be randomly assigned
const topicsResult = await supabaseClient.from('topics').select().eq('active', true);
const topics = topicsResult.data ?? [];
const topicIds = topics.map((topic) => {
return topic.id;
});
// guard we cannot do anything if we do not have topics
if (!topics) {
helpers.logger.error('No valid topics could be found to assign to a room with participants.');
return;
}
// group queued participants in different rooms
// TODO: this is where we can add the logic for the dynamic group slicing algorithm
const assignRoomPromises: Promise<boolean>[] = [];
while (shuffledParticipants.length >= PARTICIPANTS_PER_ROOM && assignRoomPromises.length < MAX_ROOM_AMOUNT_PER_JOB) {
const newRoomParticipantIds: string[] = [];
for (let i = 0; i < PARTICIPANTS_PER_ROOM; i++) {
const participantCandidate = shuffledParticipants.pop();
const participantCandidateId = participantCandidate?.id;
if (!participantCandidateId) {
helpers.logger.error(`An invalid participant candidate was found when slicing groups: ${JSON.stringify(participantCandidate)}`);
continue;
}
// add to the room
newRoomParticipantIds.push(participantCandidateId);
}
// guard: make sure there are enough participants
if (newRoomParticipantIds.length < PARTICIPANTS_PER_ROOM) {
helpers.logger.info(`Not enough participants were found to assign to a room: ${JSON.stringify(newRoomParticipantIds)}`);
continue;
}
// guard: check if these three participants were already in a room together
// TODO: check if two people are already in a room together
// const newRoomParticipants = allQueuedParticipants.filter((participant) => {
// return newRoomParticipantIds.includes(participant.id);
// });
// const newRoomUserIds = newRoomParticipants.map((participant) => {
// return participant.user_id;
// });
// store all the promises in an array so we can wait for them to finish
assignRoomPromises.push(assignParticipantsToRoom({
helpers,
participantIds: newRoomParticipantIds,
topicIds,
}));
}
try {
const assignResults = await Promise.allSettled(assignRoomPromises);
// check if all promises were successful
const successfulAssignments = assignResults.filter((result) => {
return result.status === 'fulfilled';
});
const failedAssignments = assignResults.filter((result) => {
return result.status === 'rejected';
});
helpers.logger.info(`Successfully assigned ${successfulAssignments.length} rooms.`);
helpers.logger.error(`Failed to assign ${failedAssignments.length} rooms.`);
// debug all failed reasons
failedAssignments.forEach((failedAssignment) => {
helpers.logger.error(`Failed to assign room:`);
helpers.logger.error(JSON.stringify(failedAssignment));
});
} catch (error) {
helpers.logger.error(`An error occured when assigning all participants to rooms: ${error}`);
}
}