Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cloud Firestore document locking

To ensure exclusive use of a Cloud Firestore document in a shared setting, is it sufficient to read, then write to a field (eg 'lockedBy') within a transaction?

like image 428
pwray Avatar asked Oct 31 '17 00:10

pwray


People also ask

Can two documents have the same ID in Firestore?

You cannot have several documents with the same ID in one Collection: a document ID must be unique across a collection.

Can I use Firestore without authentication?

To be honest, without Firebase Authentication, it's not possible to accept writes to a database without Authentication and also avoid abuse, since anyone could write anything from anywhere on the internet. This could also cost you large amounts of money if someone discovers your "open" database.


1 Answers

Pessimistic vs Optimistic

There is no native exclusive locking in Cloud Firestore. As the system is designed to run in large distributed systems (e.g, 1000's of mobile phone users or a Kubernetes cluster), it is based around optimistic locking patterns.

This means that when you do a read-write transaction, if the document you read is written to before you can commit the transaction, the transaction will fail so the client can rollback.

Building your own - Mobile SDKs & Security Rules

I'm going to assume you're coming in from a mobile SDK to start with, and will address server clients in the next section.

You can build an exclusive lock on top of this by using a separate document. For example, say you want to implement exclusive locking on documents in collection critical_data.

For this, we're going to use a separate collection called mutex_critical_data, with the documents inside being mutexes for documents with the same id in collection critical_data.

Before you can access a document called doc_id in critical_data you'll want to perform a write transaction to set the mutex field owner to you. I'll assume you're using Firebase Auth so you == the user's auth id auth_id. This can be any id that uniquely identifies the user or process though.

Once you are finished with the document, delete the mutex document so others can use it.

To ensure it's exclusive and other people cannot steal it, you'll want to add some checks in your security rules definition.

// In the match section that sets the document id to 'doc_id'
function mutex_exists ()
{
    return exists(/databases/$(database)/documents/mutex_critical_data/$(doc_id));
}

function mutex_owner ()
{
    return get(/databases/$(database)/documents/mutex_critical_data/$(doc_id)).data;
}

function user_owns_mutex () {
    return mutex_owner().owner == request.auth.uid;
}

allow write: if not(mutex_exists()) || user_owns_mutex;

You can also use rules to enforce the mutex as well, by predicating writing to the resource by also owning the mutex.

Building your own - Server Clients

Keep in mind that security rules are for Mobile/Web SDK access and aren't used for server clients. As server clients are considered a trusted environment, rather than having the exclusivity logic enforced by rules, you'll want to do the check in the read-write transaction on the mutex.

Leases not Locks

Last point if you build this, is I'd highly recommend looking into exclusive leases rather than exclusive locks.

A lease is like a lock, but it automatically expires if the leasee doesn't (or isn't allowed) to renew the lease before a set time. This means if the client doesn't come back (e.g, client crashes), someone else will eventually be able to obtain the lease without administrator action.

The concept is the same, but rather than setting just the owner, you also set the lease time in a field. If the lease is greater than x old, where x is the time length of the lease, it is consider to no longer be held by the owner. Before the lease expires, you can optionally allow the owner to renew the lease by setting a new lease time.

like image 185
Dan McGrath Avatar answered Sep 23 '22 18:09

Dan McGrath