homotopy-io / homotopy-webclient

https://homotopy.io
26 stars 5 forks source link

Potential race conditions in making projects public #84

Open NickHu opened 5 years ago

NickHu commented 5 years ago

Currently, the metadata regarding a project (its authorship, abstract, ... but importantly whether or not it is public) is duplicated across two Firebase products: Cloud Firestore, which is a real-time database service, and Cloud Storage, which is a bucket storage service. The official documentation suggests that these two products can be used in tandem, but does provide decent tools for integration. At the moment, such metadata is stored in a Firestore record pertaining to a project, and also in addition in the customMetadata field of the corresponding proof blob in Cloud Storage (the proof blobs are too large to store in Firestore). When a user elects to make a project public, this change needs to be made in both places; previously, this was done like so https://github.com/homotopy-io/webclient/blob/68e063ed9a489fc5e7c1050f678dad875d9bf962/client/src/components/ProjectListing.js#L63-L67

Somehow, sometimes one update can go through but not the other, in which case from the UI it appears that a project is public (because the state of Firestore says so), but silently it will not be so (because a permissions error occurs when someone tries to access the proof blob, as Cloud Storage thinks it is not public). I haven't been able to reproduce this issue, as both calls are asynchronous, so it is likely caused by user intervention (closing the window) or an unstable network connection causing only one request to go through.

In the latest commit, https://github.com/homotopy-io/webclient/commit/a41aca71d788e007a029b76c0891df2731d94b60, I removed the line which updates Firestore and instead supplied a 'Firebase Function' (a third product for small in-cloud processing tasks) which will watch for metadata changes in Cloud Firestore and then update the state of the Firestore accordingly. This seems quite heavy handed, but seems to be the 'official' solution.

There are other instances in the codebase where I am updating both states, which should probably be replaced with Firebase Functions when I have time.

NickHu commented 5 years ago

As a workaround for a "public" project seemingly never loading when accessed while not logged in (because in reality, Cloud Storage does not think the project is public), try un-marking the project as public and then re-marking it as public.

jamievicary commented 5 years ago

Thanks Nick. What is your source for saying this is an "official" solution?

NickHu commented 5 years ago

https://github.com/firebase/functions-samples/tree/Node-8/exif-images was the closest example I could find in the Firebase examples regarding keeping Firestore and Cloud Storage consistent. I also found a couple of stackoverflow answers which seemed to suggest this is how people typically do this too.

jamievicary commented 5 years ago

Thanks. Also, can you remind me of the difference between Firestore and Cloud Storage, and why we need to use both?

On Wed, 13 Mar 2019, 22:02 Nick Hu, notifications@github.com wrote:

https://github.com/firebase/functions-samples/tree/Node-8/exif-images was the closest example I could find in the Firebase examples regarding keeping Firestore and Cloud Storage consistent. I also found a couple of stackoverflow answers which seemed to suggest this is how people typically do this too.

— You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/homotopy-io/webclient/issues/84#issuecomment-472623632, or mute the thread https://github.com/notifications/unsubscribe-auth/AKHHHkdw8uiRXnC5uHE-gBiNuPNOlTjTks5vWXV5gaJpZM4bwIou .

NickHu commented 5 years ago

Effectively, we need Cloud Storage because Firestore does not store anything larger than 1MB (so proof blobs go to Cloud Storage). We need Firestore because it exposes a database interface, which we want for running queries over metadata.