We have moved our forum to GitHub Discussions. For questions about Phalcon v3/v4/v5 you can visit here and for Phalcon v6 here.

Two processes cause mail to be sent twice in loop

Hi,

I'm having trouble in an application that is used as an mailing tool. The situation is that I retrieve a mailqueue from database, send an individual mail to each entry via swiftmail and mark every queue entry as sent. Pretty simple.

The problem is, that some of the mails are being sent twice. It doesn't seem to have any logic to it.

foreach($mailqueue as $mailqueueElement){
     $message = \Swift_Message::newInstance($mailing->subject)
    ->setSender(array($configuration->sendermail => $configuration->sendername))
    ->setFrom(array($configuration->sendermail => $configuration->sendername))
    ->setReplyTo($configuration->answermail)
    ->setReturnPath($configuration->returnpath)
    ->setBody($bodyFinal, 'text/html');
    $address=$mailqueueElement->getAddress();
    $to=array($address->email => $address->first_name.' '.$address->last_name);
    $message->setTo($to);

    if($mailqueueElement->sent==0){
     $mailqueueElement->assign(
       array(
        "sent"=>1
     ));                            
    $mailqueueElement->update();
    if(!$this->config['application']['dontSendReally']){
            try{
                    $numSent+=$mailer->send($message, $failures);
            }catch(\Swift_TransportException $e){
                    echo($e->getMessage());
            }

    }               
    //file_put_contents('../app/logs/debuggerSend.csv',getmypid().' <--PID '.PHP_EOL,FILE_APPEND);
}

As you can see, I was logging the process ids. And this is the only thing, which baffles me. The mails, which are sent twice always have two different process ids. All other mails have the same process ids. I tried it on three completely different servers. So at some point phalcon seems to spawn a new process and this causes the mail to be sent twice, but I just can't figure out why it does that.

Here's a simplified example of my debug output for a looprun on 11 DB entries:

7503 <--PID <-> loopcounter: 0 <-> {"addressUid":"542"}
7503 <--PID <-> loopcounter: 1 <-> {"addressUid":"543"}
7503 <--PID <-> loopcounter: 2 <-> {"addressUid":"544"}
7503 <--PID <-> loopcounter: 3 <-> {"addressUid":"545"}
7503 <--PID <-> loopcounter: 4 <-> {"addressUid":"546"}
7503 <--PID <-> loopcounter: 5 <-> {"addressUid":"547"}
7503 <--PID <-> loopcounter: 6 <-> {"addressUid":"548"}
7503 <--PID <-> loopcounter: 7 <-> {"addressUid":"549"}
7503 <--PID <-> loopcounter: 8 <-> {"addressUid":"550"}
7503 <--PID <-> loopcounter: 9 <-> {"addressUid":"551"}
7560 <--PID <-> loopcounter: 0 <-> {"addressUid":"551"}
7503 <--PID <-> loopcounter: 10 <-> {"addressUid":"552"}
7560 <--PID <-> loopcounter: 1 <-> {"addressUid":"552"}

Obviously the mails to the addresses 551 and 552 get sent twice. That's it, process 7560 does not run through the whole loop. I actually think it has something to do with updating the models within the loop.

Has anybody experienced a similar issue or knows how to help?

Thanks for your time.

EDIT FYI: I'm completely working around the issue now by not updating the model objects within the loop at all. I'm using a lock file to prevent any parallel processes to intefere.

You need to synchronise things in some way, and there is more than one way to do it

For example: 1) lock table row containing message to send 2) send message 3) Change message status (sent = 1) 4) release the row lock

thank you. I'm certainly gonna do that. however, I'm still wondering how the second process comes into play. because it's absolutely certain that there's only one single request. any ideas on that?

You need to synchronise things in some way, and there is more than one way to do it

For example: 1) lock table row containing message to send 2) send message 3) Change message status (sent = 1) 4) release the row lock