bytespin/messenger-dedupe-bundle
composer require bytespin/messenger-dedupe-bundle
config/bundles.php:
ByteSpin\MessengerDedupeBundle\MessengerDedupeBundle::class => ['all' => true],
php bin/console doctrine:schema:update --force
config/packages/messenger.yaml:
framework:
messenger:
transports:
async: '%env(MESSENGER_TRANSPORT_DSN)%'
routing:
'App\Message\YourMessage': async
buses:
messenger.bus.default:
middleware:
- 'ByteSpin\MessengerDedupeBundle\Middleware\DedupeMiddleware'
Enable deduplication for a specific message class by:
messageId, payloadHash) to your message class.$this->messageBus->dispatch(new YourMessage($uniqueIdentifier));
The bundle will automatically check for duplicates before enqueuing.Middleware Integration:
DedupeMiddleware checks for existing messages in the messenger_messages table before enqueuing.messenger.yaml.Message Deduplication Logic:
config/packages/messenger_dedupe.yaml):
messenger_dedupe:
ttl: 3600 # 1 hour in seconds
Handling Duplicates:
messenger_dedupe:
log_duplicates: true
Custom Dedupe Keys:
Override the default deduplication key (hash of payload) by implementing DedupeInterface in your message:
use ByteSpin\MessengerDedupeBundle\Contract\DedupeInterface;
class YourMessage implements DedupeInterface {
public function getDedupeKey(): string {
return $this->uniqueField . '_' . $this->timestamp;
}
}
Bulk Processing: For ETL-like workflows, batch messages with the same deduplication key to avoid redundant processing:
$this->messageBus->dispatch(new BatchMessage([$msg1, $msg2]));
Async Transport Only:
The bundle only works with Doctrine transport. For other transports (e.g., symfony://), deduplication is manual.
Schema Mismatch:
dedupe_key and dedupe_ttl column to messenger_messages.doctrine:schema:update after installation. If already in production, use migrations.TTL Too Short:
3600 (1 hour) may cause legitimate retries to be dropped.ttl in config or implement dynamic TTL per message.No Retry for Duplicates:
messenger_dedupe:
on_duplicate: 'App\Handler\DuplicateMessageHandler'
Memory Usage:
serialize() or json_encode() for complex objects.Check for Duplicates: Query the database:
SELECT * FROM messenger_messages WHERE dedupe_key = 'your_hash_here';
Enable Logging:
messenger_dedupe:
log_duplicates: true
log_level: debug
Check logs for skipped messages.
Middleware Order:
Ensure DedupeMiddleware runs before DoctrineTransportMiddleware in messenger.yaml:
middleware:
- 'ByteSpin\MessengerDedupeBundle\Middleware\DedupeMiddleware'
- 'doctrine'
Custom Storage:
Override the default Doctrine storage by implementing DedupeStorageInterface:
class RedisDedupeStorage implements DedupeStorageInterface {
// Custom logic
}
Register it in services.yaml:
ByteSpin\MessengerDedupeBundle\Middleware\DedupeMiddleware:
arguments:
$storage: '@redis_dedupe_storage'
Dynamic TTL: Extend the middleware to set TTL per message:
class CustomDedupeMiddleware extends DedupeMiddleware {
protected function getTtl(MessageInterface $message): int {
return $message instanceof DynamicTtlMessage ? $message->getTtl() : parent::getTtl();
}
}
Testing: Mock the storage layer in tests:
$storage = $this->createMock(DedupeStorageInterface::class);
$storage->method('isDuplicate')->willReturn(true);
$middleware = new DedupeMiddleware($storage, $bus);
How can I help you explore Laravel packages today?