Transactions
Wrapping execute() in a database transaction ensures all database operations either succeed together or are rolled back. This works for both sync and queued execution.
Attribute
Use the #[ExecuteInTransaction] attribute:
php
use Havn\Executable\Attributes\ExecuteInTransaction;
#[ExecuteInTransaction]
class TransferFunds
{
use QueueableExecutable;
public function execute(Account $from, Account $to, int $amount): void
{
$from->update([
"balance" => $from->balance - $amount,
]);
$to->update([
"balance" => $to->balance + $amount,
]);
}
}No need to manually wrap in DB::transaction().
To control how many times the transaction is retried on deadlock, pass attempts (defaults to 1, a single attempt with no retries on deadlock, matching Laravel's default):
php
#[ExecuteInTransaction(attempts: 3)]
class TransferFunds
{
use QueueableExecutable;
public function execute(Account $from, Account $to, int $amount): void
{
/* ... */
}
}Interface
Alternatively, implement ShouldExecuteInTransaction:
php
use Havn\Executable\Contracts\ShouldExecuteInTransaction;
class TransferFunds implements ShouldExecuteInTransaction
{
use QueueableExecutable;
public int $transactionAttempts = 3;
public function execute(Account $from, Account $to, int $amount): void
{
/* ... */
}
}When both the attribute and interface are present, the attribute takes priority.
