如何执行功能直到成功为止?

时间:2010-05-18 07:13:33

标签: php email

我正在编写一个向特定用户发送邮件的功能?

我想要做的是,如果发生错误,我希望继续发送邮件,直到邮件发送完毕。

    function sendmail() {
        $name = mysql_escape_string($name);
        $email = mysql_escape_string($email);
        $phone = mysql_escape_string($phone);
        $content = nl2br(mysql_escape_string($content));
        $subject = "mail from ".$name." (".$email.", Ph: ".$phone.")";
        $mail = @mail($feedback,$subject,$content,$headers);
        if($mail) { echo "Your mailis send"; }
        else { echo "We are sorry for the inconvienience, but we could not send your mailnow."; }
}   

上面的函数显示错误消息,但我想尝试发送邮件,直到最后发送邮件为止。

6 个答案:

答案 0 :(得分:18)

错误处理设计:

如果页面无法发送怎么办?守护进程停止,用户输入格式错误的数据,连接丢失,可能写入磁盘,数据库已关闭以进行维护等等。您希望服务器对用户请求做什么?我建议在以后重试失败时设置队列。那里有很多好的队列系统。 Cron如果必须重试(这样就不会挂在客户端请求上)。记录尝试,如果出现某些错误情况,则通知管理员。

这是运营/基础架构团队的基础,但您可以从一些好的工具和精心设计的错误和异常处理策略开始。继承您代码的人会感谢您。

我一直在阅读实用程序员,我必须强烈推荐它专门处理这个问题。它为您考虑错误/异常处理的方式设定了一个标准,对于我来说,绝对清除了关于错误是什么,异常,断言条件(或不可能条件)的迷雾。特别是第4章语用偏执狂:

“当每个人真的出去找你时,偏执狂只是好思考” - 伍迪艾伦

答案 1 :(得分:4)

那么,如果mail()失败可能会出错?

  • 如果您的系统配置为将邮件发送到本地守护程序,则该守护程序可能已死或配置错误。
  • 如果您直接与SMTP服务器通信,则服务器很可能已经死机,或者配置错误。

在这两种情况下,您如何知道责任方何时再次响应?你想多久重试一次?
本地邮件守护程序不应该死,或者至少应该由系统立即复活。如果没有发生这种情况,您应该修复服务器,而不是在代码中处理这种情况 如果您正在与SMTP服务器通信,那么稍后重试大约一秒钟的唯一合法情况可能是服务器过载或DDoS,并且您很幸运能够通过。那个案子可能很少见,不用担心。

无论哪种方式,如果mail()返回false,那么在你修复其他问题之前通常没有必要再次尝试。因此,只需优雅地失败,使用未发送邮件的副本保存完整的事物日志,然后再手动发送。

超出此范围的任何内容均超出您的控制范围,即使mail()成功,电子邮件可能会或可能不会到达目的地。这是你的服务器管理员的工作,以捕获退回或错误的邮件,并手动操作/尝试找出错误。

答案 2 :(得分:2)

你意识到,如果你的邮件服务器停业超过30秒,它会耗尽它所用的时间(通常是30秒)吗?

错误是一种更好的方式,它不会等待重新发送它只会发送一遍又一遍,可能是782428424次,然后这些30秒结束,浪费带宽和probabl让处理器中的某些人烦恼。

你最好做的是在失败时将内容写入你刷新的数据库并尝试每隔5分钟发送一次,直到成功为止。

答案 3 :(得分:0)

function sendmail() {
        $name = mysql_escape_string($name);
        $email = mysql_escape_string($email);
        $phone = mysql_escape_string($phone);
        $content = nl2br(mysql_escape_string($content));
        $subject = "mail from ".$name." (".$email.", Ph: ".$phone.")";

        $retries = 0;
        while (!@mail($feedback,$subject,$content,$headers))
        {
            $retries++;

            if ($retries >= MAX_RETRIES)
            {
                break;
            }

            sleep(WAITING_PERIOD);
        }

        if ($retries < MAX_RETRIES) { echo "Your mail has been sent."; }
        else { echo "We are sorry for the inconvienience, but we could not send your mail now." ; }
}

将WAITING_PERIOD和MAX_RETRIES设置为适合你的东西,只是不要将MAX_RETRIES设置得太长,否则你可能会等待很长时间,也不会将WAITING_PERIOD设置得太低,或者你可能会淹没你的邮件代理。

答案 4 :(得分:0)

我建议加入一个计数器和/或睡眠声明。

计数器是为了确保脚本最终退出,而不是只是四处闲停并继续执行失败的语句。

睡眠声明用于“处理”瞬间负载问题。

类似的东西:

$remainingTries = 5;
while ($remainingTries > 0 && !sendmail())
{
  $remainingTries--; // we used a try, decrement
  sleep(5);          // wait five seconds before next try
}

答案 5 :(得分:0)

尝试这样的事情:

function doSomething($arg1, $arg2, $retry = 10)
{
    $result = false;

    /* do stuff */

    if ($result === false)
    {
        static $original = null;

        if (is_null($original))
        {
            set_time_limit(0);
            $original = $retry;
        }

        sleep(pow(2, $original - $retry));

        while (--$retry > 0)
        {
            return doSomething($arg1, $arg2, $retry);
        }
    }

    return $result;
}

如果失败,则重试$retry次并等待:

1 second before the 1st retry
2 seconds before the 2nd retry
4 seconds before the 3rd retry
8 seconds before the 4th retry
16 seconds before the 5th retry
32 seconds before the 6th retry
64 seconds before the 7th retry
128 seconds before the 8th retry
256 seconds before the 9th retry
512 seconds before the 10th retry
...
2 ^ ($retry - 1) seconds before the ($retry)th retry

通过这样做,您可以确保不会使服务器过载。