2009-06-12 6 views
3

新しいユーザーが自分のサイトにサインアップするときはいつでも、後で検索を短縮するためにいくつかの前処理を行いたいと思います。これには、30分から2分の処理時間が必要です。明らかに、サインアップ時に送信ボタンをクリックしたとき、または訪問したPHPページでこれを行うことはできません。しかし、私は5分以内にサインアップする(またはそれ以下)ことを願っています。PHP - ユーザ登録時のバックサイト処理のためのcronが必要です...(またはフォークプロセス)

クロンルート 私は、これはcronジョブであることが必要であると思うし、もしそうなら、どのように私はセットアップcronジョブをすべきか?もしそうなら、私のcronラインは2分おきに走るように見えますが、私は同じcronジョブが次のものと重なっていないことをどのように保証できますか?

イベント/フォークルート - 優先 私はおそらく私のユーザー体験を中断することなく、自分のサーバーにいくつかのイベントを投げたり(代わりにcronジョブの)ユーザーのサインアップのオフプロセスをフォークすることができた場合はどのように私はこれを行うことができますか?

答えて

5

どちらの解決法も推奨しません。

代わりに、message queueからジョブを取得する長時間実行しているプロセス(デーモン)を使用することをお勧めします。それが望ましい方法であれば、メッセージキュー自体がデータベースから外れる可能性があります。

ジョブの識別子をデータベースにポストし、長時間実行されているプロセスはそれらをしばらくのうちに繰り返し実行し、それらのプロセスを実行します。

これは同じくらい簡単です:

<?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 
} 
?> 

そして、ちょうどコマンドラインからそのスクリプトを実行します。

これ以上のクーロンジョブの利点は、競合状態に陥ることがないことです。

ジョブの実際の処理をフォークオフして、順番に処理するのではなく、並列処理できるようにすることもできます。

+0

どのように私は、これが実行されていることを保証し、それがクラッシュした場合、それを回復し、再起動だろうか? – MichaelICE

+0

シェルスクリプト内でループ内でラップすることができます。そうすることで、クラッシュなどで終了すると、シェルスクリプトがそれを再起動します。 – Matt

+0

Shadowlこれを毎時cronで生成します(実行していない場合のみ実行します) – MichaelICE

-1

これは私の考えです。すべてのユーザーのために1つのcronを用意してください。この方法で、キューのように動作するテーブルにそれらを置くことによって、重複がないことを保証することができます。 1時間ごとにcronを実行しますが、キューが空でない場合は最初にキューをチェックしてください。それが時間のためのcronの仕事を飛ばしていないなら次をもう一度試みてください。

+0

OPの場合、プロセスは完了するまでに最大30分かかります。そのため、3人のメンバーがサイトにサインアップした場合、1時間ごとに実行すれば競合状態に遭遇します。さらに、彼はサインアップの5分以内にプロセスを実行したいと思っていますが、あなたの提案は1時間ごとに実行されるだけで、プロセスは55分遅れてスケジュールされます。 – Matt

2

次のクラスを使用して、背景の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

私はdownvoteを理解していません。それはうまく動作します。それはエレガントであり、何よりも上で提案された他のソリューションと比較して手動入力を必要としません。 –

+0

これは確かに素晴らしいソリューションです。私はそれをアップアップします。この特定のセットアップの主な関心事は、生成されたプロセスの量を制御できないことです。従業員のプールを集中管理する方法がない場合は、膨大な数のジョブが並行して実行されることになり、パフォーマンスに重大な影響を与え、システムリソースが枯渇する可能性があります。 – Matt

+0

それはそれを実装するためのポスターまでです。生成されたプロセスは、別のプロセスがバックグラウンドで実行されているかどうかを容易に確認し、そのプロセスが自分のユーザーを処理するようにすることもできます。 –

関連する問題