Search code examples
google-cloud-datastoreobjectify

Trying to catch concurrent modification exception in Firestore in Datastore mode


I am trying to catch a concurrent modification exception in Firestore in Datastore mode with Objectify. I created a method and ran it 50 times in 1 second to try and catch the exception. I found that I can only catch the exception if I use a transaction.

Is there a way to catch the CME without a transaction?

This does not catch the exception when ran 50 times in 1 second (even though I can see in the logs the entity is not always updated due to the 1/sec write limit):

try {
    Entity entity = ofy().load().type(Entity.class)
        .filter("username", "username1")
        .first()
        .now();
    entity.setName("username2")
    ofy().save().entity(newEntity).now();
} catch (com.google.cloud.datastore.DatastoreException datastoreException) {
    // Never catches anything
} catch (Exception e) {
    // Never catches anything
}

This catches the exception when ran 50 times in 1 second:

try {
    ofy().transact(new VoidWork() {
        public void vrun() {
                Entity entity = ofy().load().type(Entity.class)
                    .filter("username", "username1")
                    .first()
                    .now();
                entity.setName("username2")
                ofy().save().entity(newEntity).now();
                }
            }
    });
} catch (com.google.cloud.datastore.DatastoreException datastoreException) {
    // Catches this error: Aborted due to cross-transaction contention. This occurs when multiple transactions attempt to access the same data, requiring Firestore to abort at least one in order to enforce serializability.
} catch (Exception e) {
    
}

Solution

  • Without a transaction the write is concerned a blind write. A blind write writes the content of the write even if another write has happened between your read & your write.

    You should not expect a concurrent modification exception without a transaction.