dualmedia/savepoint-prevent-crash-bundle
composer require dualmedia/savepoint-prevent-crash-bundle
config/bundles.php:
DualMedia\DoctrineRetryBundle\DoctrineRetryBundle::class => ['all' => true],
$entityManager->beginTransaction();
try {
// Your logic here
$entityManager->rollback(); // Now handled safely
} catch (\Exception $e) {
$entityManager->rollback(); // Still safe
}
Transaction Management
$entityManager->beginTransaction();
$entityManager->getConnection()->beginTransaction('savepoint_name');
try {
// Step 1: Save data
$entityManager->flush();
$entityManager->getConnection()->commit('savepoint_name');
// Step 2: Save more data (may fail)
$entityManager->getConnection()->beginTransaction('savepoint_name_2');
// ... logic ...
$entityManager->getConnection()->commit('savepoint_name_2');
} catch (\Exception $e) {
$entityManager->getConnection()->rollback('savepoint_name_2'); // Safe rollback
$entityManager->rollback(); // Outer transaction
}
dualmedia/doctrine-retry-bundle for automatic retries on savepoint failures.Symfony Event Listeners
kernel.exception or doctrine.orm.post_flush to log/handle rollback crashes.
// src/EventListener/RollbackCrashListener.php
use DualMedia\DoctrineRetryBundle\Event\RollbackCrashEvent;
public function onRollbackCrash(RollbackCrashEvent $event) {
$this->logger->warning('Rollback crash detected', [
'savepoint' => $event->getSavepointName(),
'exception' => $event->getException(),
]);
}
services.yaml:
services:
App\EventListener\RollbackCrashListener:
tags:
- { name: 'kernel.event_listener', event: 'dualmedia.doctrine_retry.rollback_crash' }
Doctrine Event Subscribers
postFlush or onFlush to inject custom savepoint logic.
use Doctrine\ORM\Event\OnFlushEventArgs;
public function onFlush(OnFlushEventArgs $args) {
$entityManager = $args->getEntityManager();
if ($entityManager->isTransactionActive()) {
$entityManager->getConnection()->beginTransaction('custom_savepoint');
}
}
config/packages/dualmedia_doctrine_retry.yaml:
doctrine_retry:
enabled: true
retry_on_savepoint_failure: true
$this->logger->debug('Savepoint committed', ['savepoint' => 'savepoint_name']);
$this->entityManager->getConnection()->setRollbackCrashMock(true);
MariaDB-Specific Behavior
Nested Savepoints
max_nested_savepoints in your MariaDB config.Transaction Isolation
READ COMMITTED isolation level for savepoints:
$connection->setTransactionIsolation(\PDO::TRANSACTION_READ_COMMITTED);
Middleware Conflicts
TransactionMiddleware) may interfere.FrameworkBundle but before custom middleware in config/bundles.php.config/packages/monolog.yaml:
handlers:
dualmedia:
type: stream
path: "%kernel.logs_dir%/doctrine_retry.log"
level: debug
channels: ["dualmedia"]
[DualMedia\DoctrineRetryBundle] Rollback crash detected for savepoint "name"
Custom Rollback Handlers
dualmedia.doctrine_retry.rollback_handler:
services:
App\Service\CustomRollbackHandler:
tags:
- { name: 'dualmedia.doctrine_retry.rollback_handler' }
DualMedia\DoctrineRetryBundle\Handler\RollbackHandlerInterface.Savepoint Naming Strategy
sp_12345. Customize via a service:
// src/Service/CustomSavepointNamer.php
use DualMedia\DoctrineRetryBundle\Namer\SavepointNamerInterface;
class CustomSavepointNamer implements SavepointNamerInterface {
public function generateName(): string {
return 'app_' . uniqid();
}
}
services.yaml:
DualMedia\DoctrineRetryBundle\:
arguments:
$savepointNamer: '@App\Service\CustomSavepointNamer'
Database-Specific Tweaks
innodb_nested_rollback_depth in my.cnf:
[mysqld]
innodb_nested_rollback_depth = 10
How can I help you explore Laravel packages today?