Armen
Armen

Reputation: 4192

Simultaneous running cron jobs records processing mix

I'm struggling with multiple same time lunched cronjobes same record process issue

Intro

The problem is when that 10 cronjobes starts at the same time randomly happens that 2 cronjobes selected same customer from database to process

So it mean 2 crons are start at alsmost same time (micro seconds diffarance) both are select at same time last unprocessed row (e.g. id:17) from database then update same id17 in database 3-dth lunched cronjobe already took id:18. But i need that each coronjobe will take unique next record from database not same

As a workaround i tried to add random sleep(rand(1,10)) delay at beginning of cron.php but don't help mutch, random duplication still happens cause cron continuously selects last unprocessed next customer which sometime matches with another cornjobe next customer select at same time

Is there any solutions present for this situation ???

Upvotes: 0

Views: 556

Answers (1)

LSerni
LSerni

Reputation: 57418

The solution you seek is collaborative locking. The customer must be marked "locked" by some job, and no script must choose a customer that is locked by another script.

Also, you must do this in such a way that no two jobs choose the same customer to acquire.

In MySQL you can do:

$me = getmypid();
$conn->execute("SELECT GET_LOCK('choosing', 5) AS okay");
// Check the returned value of okay. If it is not 1, exit() immediately.
// choose some customer in some way. The smallest Id with OwnedByPid=0 for example. The query should be fast enough to run in under 5 seconds.
$conn->execute("UPDATE customers SET OwnedByPid={$me} WHERE id={$custId};");
$conn->execute("SELECT RELEASE_LOCK('choosing'");
//

// Do your work

$conn->execute("SELECT GET_LOCK('choosing', 5)");
$conn->execute("UPDATE customers SET OwnedByPid=0 WHERE OwnedByPid={$me};");
$conn->execute("SELECT RELEASE_LOCK('choosing')");

Then, periodically - when no scripts are running - release the customers that might be marked by a script that crashed:

$conn->execute("UPDATE customers SET OwnedByPid=0;");

Or you can add another column, OwningStart, set it to NOW() when you take ownership, so you can check when OwningStart is older than 30 seconds and clear it. Or mark it as free:

SELECT MIN(Id) FROM customers WHERE OwnedByPid=0 OR OwningStart < NOW() - INTERVAL 2 MINUTE;

Upvotes: 1

Related Questions