After working with commercetools (that uses MongoDB internally, but it shows in their APIs) and presentation at SyliusCon I wanted to give MongoDB another try. Since I do like working with ReactPHP for some things, and I had the opportunity now to prototype a new app, I looked through ways of properly using MongoDB and ReactPHP. As You may have already figured out ReactPHP is not a fully multithreaded environment. It is still one single thread used for multiple and acts like multithreaded only by leveraging non-blocking I/O (and Fibers in PHP 8.2 does not change that, it is just another interface to hide that fact). Unfortunately, MongoDB Driver for PHP is relying on an extension that internally uses libmongoc for all I/O operations—this means that it cannot be easily used with ReactPHP (and based on discussions of the MongoDB PHP Driver creators on their issue tracker there is no plan to change it since there is no plan in PHP to provide a common user-land way to leverage event loops—there is one in HHVM, so maybe something cool will emerge in a driver for HHVM, but I am not following what is going on in there)
GitHub Repositories
The Obvious first step is to look for some repositories on GitHub as there may have already been some excellent packages posted that solve our problems.
MongoDB Wire Protocol
A direct question about ReactPHP and MongoDB yields two quite similar and abandoned repositories jmikola/react-mongodb and mahmutbayri/reactphp-mongodb-async both of them attempt to use libbson (Binary JSON) that is what MongoDB Wire Protocol is based on. Both end on simple queries, so I can only assume that it proved to be not worth the time to continue. (Also, the internals of MongoDB have some cool stuff like data encryption before sending it to the database—keeping up with such features will be hard in the long run.)
SQLite
While looking at repositories posted by creators of ReactPHP I have found components for communication with SQLite clue/reactphp-sqlite. While it is not about MongoDB it is another way that we can attempt to handle big blocking tasks. SQLite is a funny database because it does not have its own daemon or server - it is just a library linking to Your current executable and working just like any other method call. And again it is a C library with PHP extensions exposing those C methods to PHP without an option for non-blocking I/O. The solution presented in this repository is just to spawn another process that does block I/O and communicate with it using non-blocking I/O in the first process. The main process is communicating with the secondary process via shared I/O streams sending messages encoded as JSON-RPC.
Two main problems are:
- MongoDB driver has a much more complicated API to mock for JSON-RPC than SQLite (here we had basically 4 messages to cover: connect, query, execute and close).
- It will be a bottleneck for higher traffic, as all queries in an application will be processed by a single queue worker.
HTTP APIs for MongoDB
So, implementing drivers for MongoDB that would be compatible with ReactPHP looks like a big and boring task—maybe there are already solutions that expose HTTP APIs that
ReactPHP is awesome at working with?
MongoDB Atlas
Yes, MongoDB has some Cloud Native solution that allows publishing HTTP APIs directly MongoDB Atlas. But that's a paid cloud solution—we don't want to invest in that.
RESTHeart
Another service I found is RESTHeart and this is a service I will try to use with my newest prototype. It is a Java-based service that exposes MongoDB as HTTP API. At some points claims that in specific scenarios can be even faster than native MongoDB Drivers (as it provides some HTTP layer caching). It also looks like it can be used to host some static content and applications written in modern JVM-compatible languages like Kotlin.