Search code examples
pythonmongodbmongodb-replica-set

MongoDB error on Transaction w/ ReadPreference Secondary on a test replica set


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.


Solution

  • 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.