1

これが私の問題です:

私のデータベースには、status フィールドを持つ requests テーブルがあります。cronjob は毎分実行され、「保留中」ステータスのすべてのリクエストを探します。リクエストの処理が完了すると、ステータスが「終了」に設定されます。

場合によっては、この cron ジョブの実行に 1 分以上かかることがあるため、同じ cron ジョブが 2 つ実行されています。彼らが同じリクエストを処理しないようにする必要があります。

今、私はこれをやっています:

$requests = db_all($this->db->query('SELECT * FROM x__mx_request WHERE status="pending"'));
//few lines of code later
$this->db->query('UPDATE x__mx_request SET status="processing" WHERE id IN('.implode(',', $ids).')');

選択した後にステータスを処理中に設定すると、他のスクリプトも処理を停止しますが、1 つのスクリプトがすべてのリクエストを選択し、2 つ目のスクリプトがすべてのリクエストを選択してから、1 つ目のスクリプトがそれらを処理中に設定することはありませんか?

これを行うためのより安全な方法が欲しいです!

編集:素晴らしい答えをありがとう、私は実際にそれらを試してみる必要がありますが、正しいものとしてマークする前に.

4

3 に答える 3

2

ロック/ロック解除ファイルを作成して、ジョブがまだ実行されているかどうかをcronjobsが「知る」ことができるようにすることができます。また、プロセス pid は、何かが失敗した場合や応答しない場合などにプロセスのステータスを識別するために使用できます。

于 2012-05-07T18:53:28.030 に答える
2

ステータスを一意の値に設定し、その一意の値ですべてを処理します。処理が途中で失敗した場合は、タイムアウトまたは何らかのフォールバックを用意してください (ただし、現在の状況ではそれが必要です)。

次のようなものです(特に言語を知らないので、PHPを作成しているだけです):

 $guid = new_guid();

 $this->db->query(
    'UPDATE x__mx_request SET status = ? WHERE status = "pending";', 
    $guid
 );
 $requests = db_all(
    $this->db->query('SELECT * FROM x__mx_request WHERE status = ?;', $guid)
 );

もう 1 つのオプションはトランザクションです。ただし、SERIALIZABLE が必要になると思います。つまり、基本的に 1 つのジョブ処理だけにとどまっているということです。これを行いたい場合は、cron ジョブのロック ファイルを使用すると、コードを変更せずに簡単に実行できます。

于 2012-05-07T18:56:23.257 に答える
0

トランザクションはあなたが望むものです。したがって、データを読み取り、保留ステータスを処理中などの中間値に変更し、データを返す単一のトランザクションがあります。

これにより、2 つのクエリが同じデータを返すことを防ぎます。

おおよそ、この擬似SQLのようなものが必要です

begin transaction 

select into tmp table * from blah where status = "pending"

update status = "being processed" where id in tmp 

end transaction 

return select * from tmp table
于 2012-05-07T18:48:50.107 に答える