3
\$\begingroup\$

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;
            }
        }
    }
\$\endgroup\$
3
\$\begingroup\$

First off, you're code looks nice, but it can be improved in places:

  1. I don't see why:

            $totSmsToSend = count($smsToSend);
    

Is indented so far, you should fix that. There's quite a few elements that have been over indented.

  1. Your constant use of the word Sms like so, seems a bit silly, as it as an acronym, you should stick to SMS or sms but don't mix cases.

  2. $tot, You shouldn't leave out two characters, just for the purpose of slimming when it makes it much less readable.

  3. Your code seems really forced, so I think it could be improved in the method it goes about doing.

Your solution really just sounds like basic division:

  1. Y / X, rounded down to a whole number
  2. For leftover positions in Y queue, transfer X(1), X(2), ... X(X) and go through until you fill up the queue.
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.