I need to implement a system of queueing that extracts elements equally from x
queues to one single queue with y
positions.
Let's say I have 5 queues, each with a number of elements and I need to extract elements from each of the 5 queues to build a new queue containing the extracted elements until the new queue is full.
For example:
5 queues to a queue with 100 positions. I need to extract 20 elements from each queue. Ok, but if some of the 5 input queues have less than 20 elements, the resulting queue will have some empty elements.
51 queues to a queue with 100 positions. I need to extract 1 element from each queue. The input queues have for sure at least 1 element. But the resulting queue will have 49 empty positions. So I'll need to iterate the input queues to extract 1 element from each one, until I reach the max 100 positions of the resulting queue.
I need this to implement a system of sending queues to send massive SMSs form web for our customers. In those example, the 51 queues are 51 different SMS, inside each of these queues there are all the mobile numbers to send the sms to.
I can send only $this->QueueMax
sms every 2 minutes, so I have a script that takes a number of mobile phones from all sms to send and send all sms in parallel.
I've implemented this PHP script to manage the final queue: at the end, $smsToSend
will tell me how many mobile numbers to extract for each SMS in the 'limit' field.
Is that alright? Will the script work fine?
But most of all, is there a less-complex method of doing this?
$query = 'SELECT sms_id, COUNT(DISTINCT mobile) AS tot_mobile ';
$query.= 'FROM sms_queue ';
$query.= 'GROUP BY sms_id ';
$this->Dbh->query($query);
$smsToSend = array();
while($this->Dbh->next()) {
$smsToSend[$this->Dbh->Record['sms_id']] = array(
'tot' => $this->Dbh->Record['tot_mobile'],
'limit' => 0,
);
}
/* The queue to send is empty */
if( empty($smsToSend) ) {
$this->IsSending = false;
return false;
}
/* Total phone numbers to take from each sms queue */
$totSmsToSend = count($smsToSend);
/* There are more sms to send than empty positions in the send queue; send only the firsts "QueueMax" sms */
if( $totSmsToSend > $this->QueueMax ) {
$smsToSend = array_slice($smsToSend, 0, $this->QueueMax, true);
$totSmsToSend = $this->QueueMax;
}
$totMobilesFromEachSms = (int)floor($this->QueueMax / $totSmsToSend);
foreach( $smsToSend as $smsID => $info ) {
$smsToSend[$smsID]['limit'] = ($totMobilesFromEachSms >= $info['tot']) ? $info['tot'] : $totMobilesFromEachSms;
}
/* If there are some empty positions, iterate $smsToSend and take 1 mobile number foreach sms 'till covering all empty positions */
if( ($totMobilesFromEachSms * $totSmsToSend) < $this->QueueMax ) {
$i = $totSmsToSend + 1;
while(true) {
$check = false;
foreach($smsToSend as $smsID => $info) {
if( $info['limit'] >= $info['tot'] ) {
continue;
}
$check = true;
$smsToSend[$smsID]['limit']++;
$i++;
if( $i >= $this->QueueMax ) {
break 2;
}
}
/* Each sms has all its phone numbers correctly placed inside the send queue*/
if( !$check ) {
break;
}
}
}