PHP - нужен cron для обратной обработки сайта при регистрации пользователя ... (или процесс fork) - PullRequest
3 голосов
/ 12 июня 2009

Всякий раз, когда новый пользователь регистрируется на моем сайте, я хочу выполнить некоторую предварительную обработку, чтобы сократить его поиски в будущем. Это занимает от 30 до 2 минут времени обработки. Очевидно, что я не могу сделать это, когда они нажимают кнопку отправки при регистрации ... или на любой странице PHP, которую они посещают. Однако я бы хотел, чтобы это было сделано в течение 5 минут после их регистрации (или менее).

Cron Route Я думаю, это должно быть в работе cron, и если да, то как мне настроить работу cron? Если да, то как должна выглядеть моя линия cron каждые 2 минуты, и как я могу убедиться, что у меня нет той же задачи cron, перекрывающей следующую?

Событие / Вилочный маршрут - Предпочтительный Если я могу перебросить какое-либо событие на свой сервер, не нарушая работу пользователей, или отключить процесс регистрации пользователей (вместо задания cron), как я могу это сделать?

Ответы [ 3 ]

5 голосов
/ 12 июня 2009

Я бы не рекомендовал ни одно из решений.

Вместо этого вам лучше всего использовать длительный процесс (демон), который получает задания из очереди сообщений . Сама очередь сообщений может быть вне базы данных, если это ваш предпочтительный метод.

Вы опубликуете идентификатор задания в своей базе данных, а затем длительный процесс будет время от времени повторять их и действовать в соответствии с ними.

Это так же просто, как:

<?php
while(true) {
   jobs = getListOfJobsFromDatabase();  // get the jobs from the databbase
   foreach (jobs as job) {
      processAJob(job); // do whatever needs to be done for the job
      deleteJobFromDatabase(job); //remember to delete the job once its done!
   }
   sleep(60); // sleep for a while so it doesnt thrash your database when theres nothing to do
}
?>

И просто запустите этот скрипт из командной строки.

Преимущества этого по сравнению с заданием cron в том, что вы не получите условия гонки.

Вы также можете отключить фактическую обработку заданий, поэтому многие из них могут выполняться параллельно, а не последовательно.

2 голосов
/ 12 июня 2009

Вы можете использовать следующий класс для вызова фоновой задачи PHP.

class BackgroundProcess {
    static function open($exec, $cwd = null) {
        if (!is_string($cwd)) {
            $cwd = @getcwd();
        }

        @chdir($cwd);

        if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
            $WshShell = new COM("WScript.Shell");
            $WshShell->CurrentDirectory = str_replace('/', '\\', $cwd);
            $WshShell->Run($exec, 0, false);
        } else {
            exec($exec . " > /dev/null 2>&1 &");
        }
    }

    static function fork($phpScript, $phpExec = null) {
        $cwd = dirname($phpScript);

        if (!is_string($phpExec) || !file_exists($phpExec)) {
            if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
                $phpExec = str_replace('/', '\\', dirname(ini_get('extension_dir'))) . '\php.exe';

                if (@file_exists($phpExec)) {
                    BackgroundProcess::open(escapeshellarg($phpExec) . " " . escapeshellarg($phpScript), $cwd);
                }
            } else {
                $phpExec = exec("which php-cli");

                if ($phpExec[0] != '/') {
                    $phpExec = exec("which php");
                }

                if ($phpExec[0] == '/') {
                    BackgroundProcess::open(escapeshellarg($phpExec) . " " . escapeshellarg($phpScript), $cwd);
                }
            }
        } else {
            if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {
                $phpExec = str_replace('/', '\\', $phpExec);
            }

            BackgroundProcess::open(escapeshellarg($phpExec) . " " . escapeshellarg($phpScript), $cwd);
        }
    }
}

Используйте как таковое:

BackgroundProcess::fork('process_user.php');
0 голосов
/ 12 июня 2009

Вот что я думаю. Иметь единый крон для всех ваших пользователей. Таким образом, вы можете гарантировать отсутствие перекрытия, поместив их в таблицу, которая работает как очередь. Запускайте cron каждый час, но сначала проверяйте очередь, если очередь не пуста. Если это не пропустить работу cron в течение часа, попробуйте снова следующий.

...