generated from jric11/baseProject
20 lines
925 B
PHP
20 lines
925 B
PHP
<?php
|
|
/** Retry only complete, rollback-safe database work; never put email delivery here. */
|
|
final class DatabaseTransaction {
|
|
public static function run(PDO $db,callable $work): mixed {
|
|
if($db->inTransaction())throw new LogicException('Retryable work must own its transaction.');
|
|
for($attempt=1;$attempt<=3;$attempt++){
|
|
$db->beginTransaction();
|
|
try{
|
|
$result=$work($db);$db->commit();return $result;
|
|
}catch(Throwable $error){
|
|
if($db->inTransaction())$db->rollBack();
|
|
$retryable=$error instanceof PDOException && (in_array((int)($error->errorInfo[1]??0),[1205,1213],true)||$error->getCode()==='40001');
|
|
if(!$retryable||$attempt===3)throw $error;
|
|
usleep(random_int(10000,30000)*$attempt);
|
|
}
|
|
}
|
|
throw new LogicException('Transaction attempts exhausted.');
|
|
}
|
|
}
|