【问题标题】:Use cron job for background php为后台 php 使用 cron 作业
【发布时间】:2017-05-20 17:41:27
【问题描述】:

您好,我正在尝试使用 PhpMailer 发送多封电子邮件作为通知系统。为避免用户提交表单时出现时间延迟问题,我决定将所有电子邮件消息排队存储到 mysql 表中,然后使用 cron 作业运行后台脚本来发送队列。这是我使用 cron 作业运行的脚本

include('config/config.php');

require_once(ROOT_PATH.'/helper/phpmailer/PHPMailerAutoload.php');

    $mail = new PHPMailer;

    $mail->isSMTP(); 
    $mail->SMTPAuth = true; 
    $mail->isHTML(true);
    $mail->Host = SSE_HOST;  
    $mail->Username = SSE_USER;    
    $mail->Password = SSE_PASSWORD;  
    $mail->SMTPSecure = SSE_SECURE;  
    $mail->Port = 465;  
    $mail->SetFrom(SSE_FROM, SSE_FROM_NAME);
    $mail->addReplyTo(SSE_REPLY, 'Invia Risposta');

$result = mysqli_query($conn, "SELECT queue_emails_email, queue_emails_subject, queue_emails_body FROM queue_emails WHERE queue_emails_status = '1' " );

    foreach ($result as $row) {

        $mail->addAddress($row['queue_emails_email']);
        $subject = $row['queue_emails_subject'];
        $mail->Subject = $subject;
        $mail->MsgHTML($row['queue_emails_body']);


    if (!$mail->send()) {
        echo "Mailer Error (" . str_replace("@", "&#64;", $row["queue_emails_email"]) . ') ' . $mail->ErrorInfo . '<br />';
        break; //Abandon sending
    } else {
        echo "Message sent to :" . $row['queue_emails_email'] . ' (' . str_replace("@", "&#64;", $row['queue_emails_email']) . ')<br />';
        //Mark it as sent in the DB
        mysqli_query($conn, "UPDATE queue_emails SET queue_emails_status = '0' WHERE queue_emails_email = '" .
            mysqli_real_escape_string($conn, $row['queue_emails_email']) . "'");

    }
    // Clear all addresses and attachments for next loop
    $mail->clearAddresses();

    }

这是mysql表queue_emails结构:

queue_emails_id int(11) PRIMARY KEY NOT NULL AUTO_INCREMENT,
queue_emails_email varchar(255) NOT NULL,
queue_emails_status int(2) DEFAULT '1',
queue_emails_subject TEXT   NOT NULL,
queue_emails_body TEXT NOT NULL

现在我的问题是:如果我收到了不止一条正文不同但电子邮件地址相同的消息,如果 cron 作业进程中断会发生什么?我已经使用 mailtrap 在我的本地主机上进行了测试,它似乎工作正常,但我想知道这种方法在实时服务器上是否有效。我认为我的队列不会超过 200-300 封电子邮件。非常感谢您的帮助

【问题讨论】:

  • 为什么不直接在表中添加一个 ID 列并根据这个 ID 而不是电子邮件地址进行更新?
  • 嗨@TodorSimeonov 感谢您的快速回答。抱歉,我不明白您添加 id 是什么意思(是用户 id)吗?
  • 在您的 DB 表 queue_emails - 添加一个可以是 AUTO INCREMENT 的列,它将是您必须发送的每封电子邮件的唯一 ID。然后在此基础上,您可以使用 queue_emails_status = '0' 更新您刚刚发送的电子邮件消息的这一行,但发送给该用户(地址)的所有其他消息将留在队列中。如果所有表格都填写相同的电子邮件地址,则无关紧要。
  • 好的,我现在明白了,所以基本上我需要从 UPDATE queue_emails SET queue_emails_status = '0' 中删除 where 子句,我已经有了一个带有 auto_increment 的 queue_emails_id 表。因此,即使 cron 作业进程超时,它也应该从哪里开始,如果它是正确的吗?还有什么我可以实施的吗?我添加了 $mail->SMTPKeepAlive = true;按照这里的建议到 Phpmailer 配置 github.com/PHPMailer/PHPMailer/blob/master/examples/…
  • 不,在没有 WHERE 子句的情况下执行 UPDATE 不是一个好主意 :) 您将只发送一封电子邮件并更新整个表。我的意思是将 WHERE 子句更改为 UPDATE ... SET .... WHERE queue_email_id = '$last_email_id'; 比较您确定是唯一的东西,而不是可能不是的地址。例如,在在线商店中,您将向新用户发送 2 条后续消息 - 一条用于成功注册,一条用于下订单。很高兴他收到了他们两个:)

标签: php mysql


【解决方案1】:

您的表最好包含一个单独的唯一 ID,因此您不需要对数据库结构进行任何更改。您只需要获取您的 ID 值并使用它。像这样修改你的SELECT

$result = mysqli_query($conn, "SELECT queue_emails_id, queue_emails_email,  
    queue_emails_subject, queue_emails_body FROM queue_emails WHERE 
    queue_emails_status = '1' " );

然后当你让UPDATE 使用这个:

mysqli_query($conn, "UPDATE queue_emails SET queue_emails_status = '0' 
    WHERE queue_emails_id = '" . intval($row['queue_emails_id']) . "'");

就是这么简单。现在,您可以确保将正确的消息设置为零状态,无论有多少消息发送到您的队列中的同一地址,并且您不会丢失消息。

顺便说一句,如果队列中有多个邮件,您的代码会丢失同一电子邮件地址的邮件。无论cron 作业是完成还是中断,它都会将它们全部设置为已发送。假设您收到以下消息:

to: john@yahoo.com
to: john@yahoo.com
to: peter@hotmail.com
to: mike@gmail.com
to: john@yahoo.com

您的查询将返回此列表,您将开始发送消息并将第一条消息发送到 john@yahoo.com。如果$mail-&gt;send() 返回 OK,您将更新所有消息到 john@yahoo,status=0。所以 john 将只收到一条消息,而第 2 条和第 5 条消息将丢失(不发送给 john)。

在您的问题中,您说队列中可能有 200-300 条消息。我不知道你多久调用一次这个代码,我会在不超过 5 分钟的时间内调用它,所以我的用户会按时收到他们的邮件,但如果太频繁,那意味着你每天会收到很多电子邮件.想一想,您是否需要将它们全部保存在表中且 status=0,或者您可以删除它们以节省空间。

【讨论】:

  • 您好 Tudor 非常感谢您的帮助,稍后我将对其进行测试并通知您。关于你的考虑,我想我会每 15 分钟调用一次代码,也许是为了避免 cron 重叠(我也在谷歌上搜索更多关于它的信息)然后我的计划是运行另一个 cron 可能每天一次以删除所有状态=0的行并以这种方式保持数据库清洁
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-06-23
  • 1970-01-01
  • 1970-01-01
  • 2012-01-13
  • 1970-01-01
  • 1970-01-01
  • 2016-09-27
相关资源
最近更新 更多