Problem
The library supports sessions and transactions, but it does not implement MongoDB retryable writes for CRUD operations outside a transaction.
Client::query() adds txnNumber only when the session is in a transaction. retryableWriteNumber is tracked in the session state, but it is not used to build or retry a write command. As a result, insert, update, and delete issue a single command and applications cannot safely enable retryWrites=true.
Retrying an ambiguous network or primary step-down failure in application code can duplicate a write that MongoDB already applied.
Expected behavior
When retryable writes are enabled, the client should:
- create and manage an implicit server session for each eligible write;
- attach
lsid and a monotonically increasing txnNumber to the command;
- retry eligible single-document writes once for retryable network and server errors, using the same session and transaction number;
- preserve the at-most-once semantics provided by MongoDB;
- keep multi-document writes and unsupported commands out of the retry path;
- cover the behavior with the MongoDB retryable writes specification tests.
The existing session and transaction support looks like a good foundation, but retryable writes need a separate path from multi-document transactions.
Related observations from our integration
We are evaluating Utopia Mongo in a PHP/Hyperf service and built a provider adapter beside FastMongo, which uses the MongoDB Go driver. The following points are related to production use, but they are not prerequisites for this issue. Maintainers may prefer to track them separately.
Connection strings and topology discovery
Client is configured with one resolved host and port. To use a standard mongodb+srv URI, our adapter had to resolve SRV and TXT records, apply the TLS default, validate the SRV domain, discover a writable primary with hello, cache the result, and invalidate it after a connection or primary-change failure.
First-class support for MongoDB connection strings, including mongodb+srv, seed lists, relevant URI options, and topology refresh, would remove this application-specific infrastructure. FastMongo gets this behavior from the Go driver when it receives the URI.
Connection pool lifecycle
One Utopia Client owns one socket. In a coroutine application we needed a bounded pool with checkout timeout, disposal of failed clients, and invalidation when the resolved topology changed. A reusable pool utility, or documented guidance for this pattern, would make the library easier to adopt in long-running services.
This does not need to be a hidden global pool. An explicit pool with clear ownership would fit the current API well.
Scope and priority
We do not expect all of these capabilities to land together. Retryable writes are the immediate compatibility gap because a manual retry cannot reproduce their safety guarantees. The connection-string and pool observations are shared as integration feedback in case they help shape future work.
Context
MongoDB specification: https://specifications.readthedocs.io/en/latest/retryable-writes/retryable-writes/
FastMongo reference: https://github.com/Reasno/fastmongo
Problem
The library supports sessions and transactions, but it does not implement MongoDB retryable writes for CRUD operations outside a transaction.
Client::query()addstxnNumberonly when the session is in a transaction.retryableWriteNumberis tracked in the session state, but it is not used to build or retry a write command. As a result,insert,update, anddeleteissue a single command and applications cannot safely enableretryWrites=true.Retrying an ambiguous network or primary step-down failure in application code can duplicate a write that MongoDB already applied.
Expected behavior
When retryable writes are enabled, the client should:
lsidand a monotonically increasingtxnNumberto the command;The existing session and transaction support looks like a good foundation, but retryable writes need a separate path from multi-document transactions.
Related observations from our integration
We are evaluating Utopia Mongo in a PHP/Hyperf service and built a provider adapter beside FastMongo, which uses the MongoDB Go driver. The following points are related to production use, but they are not prerequisites for this issue. Maintainers may prefer to track them separately.
Connection strings and topology discovery
Clientis configured with one resolved host and port. To use a standardmongodb+srvURI, our adapter had to resolve SRV and TXT records, apply the TLS default, validate the SRV domain, discover a writable primary withhello, cache the result, and invalidate it after a connection or primary-change failure.First-class support for MongoDB connection strings, including
mongodb+srv, seed lists, relevant URI options, and topology refresh, would remove this application-specific infrastructure. FastMongo gets this behavior from the Go driver when it receives the URI.Connection pool lifecycle
One Utopia
Clientowns one socket. In a coroutine application we needed a bounded pool with checkout timeout, disposal of failed clients, and invalidation when the resolved topology changed. A reusable pool utility, or documented guidance for this pattern, would make the library easier to adopt in long-running services.This does not need to be a hidden global pool. An explicit pool with clear ownership would fit the current API well.
Scope and priority
We do not expect all of these capabilities to land together. Retryable writes are the immediate compatibility gap because a manual retry cannot reproduce their safety guarantees. The connection-string and pool observations are shared as integration feedback in case they help shape future work.
Context
MongoDB specification: https://specifications.readthedocs.io/en/latest/retryable-writes/retryable-writes/
FastMongo reference: https://github.com/Reasno/fastmongo