Reputation: 1097
I am running a transaction in firestore like this:
final DocumentReference deleteRef = db.collection("ABC").document("XYZ");
db.runTransaction(new Transaction.Function<Void>() {
@Override
public Void apply(Transaction transaction) throws FirebaseFirestoreException {
DocumentSnapshot documentSnapshot = transaction.get(deleteRef);
if(documentSnapshot.exists())
{
transaction.delete(deleteRef);
Log.d("MyActivity", "inside documentSnapshot.exists()");
Log.d("MyActivity",deleteRef.getPath());
}
return null;
}
}).addOnSuccessListener(new OnSuccessListener<Void>() {
@Override
public void onSuccess(Void aVoid) {
// implement logic
Log.d("MyActivity","onSuccess");
}
}).addOnFailureListener(new OnFailureListener() {
@Override
public void onFailure(@NonNull Exception e) {
Log.d("MyActivity","onFailure");
Log.e("MyActivity", "transaction failure", e);
}
});
Logs of Client A:
2019-10-21 20:28:45.134 15866-16240/someapp D/MyActivity: inside documentSnapshot.exists()
2019-10-21 20:28:45.134 15866-16240/someapp D/MyActivity: ABC/XYZ
2019-10-21 20:28:45.488 15866-15866/someapp D/MyActivity: onSuccess
Logs of Client B:
2019-10-21 20:28:46.041 30293-31123/someapp D/MyActivity: inside documentSnapshot.exists()
2019-10-21 20:28:46.041 30293-31123/someapp D/MyActivity: ABC/XYZ
2019-10-21 20:28:47.900 30293-30293/someapp D/MyActivity: onFailure
2019-10-21 20:58:04.137 6537-6537/someapp E/MyActivity: transaction failure com.google.firebase.firestore.FirebaseFirestoreException: Transaction failed all retries. at com.google.firebase.firestore.core.SyncEngine.lambda$transaction$0(com.google.firebase:firebase-firestore@@19.0.1:283) at com.google.firebase.firestore.core.SyncEngine$$Lambda$2.then(com.google.firebase:firebase-firestore@@19.0.1) at com.google.android.gms.tasks.zzf.run(Unknown Source) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:428) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607) at com.google.firebase.firestore.util.AsyncQueue$DelayedStartFactory.run(com.google.firebase:firebase-firestore@@19.0.1:205) at java.lang.Thread.run(Thread.java:761) Caused by: com.google.firebase.firestore.FirebaseFirestoreException: Every document read in a transaction must also be written. at com.google.firebase.firestore.core.Transaction.commit(com.google.firebase:firebase-firestore@@19.0.1:182) at com.google.firebase.firestore.core.SyncEngine.lambda$transaction$1(com.google.firebase:firebase-firestore@@19.0.1:270) at com.google.firebase.firestore.core.SyncEngine$$Lambda$1.then(com.google.firebase:firebase-firestore@@19.0.1) at com.google.android.gms.tasks.zzf.run(Unknown Source) at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:428) at java.util.concurrent.FutureTask.run(FutureTask.java:237) at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:272) at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1133) at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:607) at com.google.firebase.firestore.util.AsyncQueue$DelayedStartFactory.run(com.google.firebase:firebase-firestore@@19.0.1:205) at java.lang.Thread.run(Thread.java:761)
Now, 2 clients A and B are near simultaneously running this transaction. As one would expect, if Client A lands up in onSuccess, Client B lands up in onFailure.
But, unexpectedly, both the clients are deleting the document.
In other words, even if the transaction lands in onFailure for Client B, it deletes the document, which should not be case.
Please help me understand this.
Upvotes: 0
Views: 156
Reputation: 317372
Only the first client is actually deleting the document. The second client would see a non-existent document.
You might also want to know that deletes in Cloud Firestore don't generate an error. Also, gets on documents also do not generate errors for documents that don't exist.
So actually, with the code you're showing, the second client would see documentSnapshot.exists()
return false, and nothing would happen in the transaction, because exists()
also doesn't generate any errors.
If you're seeing a client end up in a failure, try logging the exception to see what's really going on.
Upvotes: 2