Symfony already supports MongoDB for storing sessions and managing locks. In Symfony 8.2, you can also use it to cache data and queue messages with Messenger.
MongoDB Cache Adapters
If your application already uses MongoDB, you can now use it for your cache
pools too. The Cache component adds two adapters, MongoDbAdapter and
MongoDbTagAwareAdapter, which store each cache item as a document. The
tag-aware one stores the tags inside that document, so invalidating a tag runs
a single delete query.
Both need the mongodb/mongodb library. In Symfony applications, use a
mongodb:// (or mongodb+srv://) DSN as the provider of your pools:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
# config/packages/cache.yaml
framework:
cache:
# the database is read from the DSN path; the collection defaults to "cache_items"
default_mongodb_provider: '%env(MONGODB_URL)%'
pools:
product.cache:
adapter: cache.adapter.mongodb_tag_aware
# when a pool defines a MongoDB DSN as its provider, Symfony
# uses the MongoDB adapter automatically
report.cache:
provider: 'mongodb://localhost:27017/app?collection_name=reports'
Outside Symfony applications, create the adapter with a DSN or with the
MongoDB\Client, Database or Collection object you already use, and
call setup() once to create a TTL index so MongoDB removes expired items
by itself:
1 2 3 4 5 6
use MongoDB\Client;
use Symfony\Component\Cache\Adapter\MongoDbAdapter;
$client = new Client('mongodb://localhost:27017');
$cache = new MongoDbAdapter($client->getCollection('app', 'cache_items'), defaultLifetime: 3600);
$cache->setup();
MongoDB Messenger Transport
Symfony 8.2 adds a MongoDB transport for Messenger, based on the facile-it/mongodb-messenger-transport package. First, install it:
1
$ composer require symfony/mongodb-messenger
Then, use a mongodb:// (or mongodb+srv://) DSN in your transport:
1 2
# .env
MESSENGER_TRANSPORT_DSN=mongodb://user:pass@localhost:27017/app?collection_name=messenger_messages&queue_name=default
The transport stores messages as documents in a MongoDB collection. Consumers
claim messages atomically, so two workers never get the same message. If a worker
crashes, its message is delivered again after redeliver_timeout (one hour by
default). Run messenger:setup-transports to create the index used by workers
to find the pending messages.
You can also dispatch messages inside a MongoDB transaction, so that an order
and its OrderPlaced message are saved together or not at all. Pass the
transaction's session to Messenger with MongoDbSessionStamp:
1 2 3 4 5 6 7 8 9
use MongoDB\Driver\Session;
use Symfony\Component\Messenger\Bridge\MongoDb\Stamp\MongoDbSessionStamp;
use function MongoDB\with_transaction;
$session = $this->client->startSession();
with_transaction($session, function (Session $session) use ($order): void {
$this->orders->insertOne($order, ['session' => $session]);
$this->bus->dispatch(new OrderPlaced($order['_id']), [new MongoDbSessionStamp($session)]);
});
Listening to Multiple MongoDB Queues
The MongoDB transport stores all queues in the same collection, so a worker can consume several of them with a single request to the server, instead of one request per queue. First, define one transport per queue to route messages to each of them:
1 2 3 4 5 6 7 8 9 10
# config/packages/messenger.yaml
framework:
messenger:
transports:
emails: 'mongodb://localhost:27017/app?queue_name=emails'
invoices: 'mongodb://localhost:27017/app?queue_name=invoices'
routing:
App\Message\SendWelcomeEmail: emails
App\Message\GenerateInvoice: invoices
Both transports use the same collection (messenger_messages by default), and
each message document stores the name of its queue. So, a worker connected through
any of these transports can read the messages of both queues. Pass the transport
name to the messenger:consume command and the queues to its --queues option:
1
$ php bin/console messenger:consume emails --queues=emails --queues=invoices
Messages are consumed in the order they became available, with no priority between queues. All queues must live in the same collection, and failed messages are retried in the queue they came from.