tl;dr How can I enable read preference SECONDARY on a single-operation read transaction, on a testing replica set?
I have created a MongoDB replica set from MongoDB deploy replica set for testing.
Then tried to make a simple, single-document transaction from MongoDB Transactions where I only change a few things such as read preference to secondary.
# Step 1: Define the callback that specifies the sequence of operations to perform inside the transactions. def callback(session): collection_one = session.client.mydb1.foo # Important:: You must pass the session to the operations. collection_one.find_one({'id': 0}, session=session) # Step 2: Start a client session. with client.start_session() as session: # Step 3: Use with_transaction to start a transaction, execute the callback, and commit (or abort on error). session.with_transaction( callback, read_concern=ReadConcern('snapshot'), # <- changed from 'local' to 'snapshot' write_concern=wc_majority, read_preference=ReadPreference.SECONDARY) # <- changed from PRIMARY to SECONDARY
I get the following error
... pymongo.errors.InvalidOperation: read preference in a transaction must be primary, not: Secondary(tag_sets=None, max_staleness=-1, hedge=None)
It works correctly if I change to read preference PRIMARY. If the read preference must be primary, it does not make any sense to have this option at all …
What am I doing wrong or understanding incorrectly? This seems something so basic yet the documentation IMO does not explain this.
Advertisement
Answer
Secondary reads in transactions do not make sense.
Transactions are running on the current primary. Hence, reads will be fulfilled by the primary. Requesting a secondary read is incompatible with transactions.
A secondary read may be fulfilled by any of the secondaries. The secondaries may have different data. This makes simple secondary reads non-repeatable, not causally consistent, etc.
If you want a simple secondary read, do not issue it under a transaction.