Skip to content

Instantly share code, notes, and snippets.

@j05u3
Last active February 25, 2023 23:14
Show Gist options
  • Save j05u3/c4a21e73f212ae1f6e411486ccace8fd to your computer and use it in GitHub Desktop.
Save j05u3/c4a21e73f212ae1f6e411486ccace8fd to your computer and use it in GitHub Desktop.
import { fdb } from "../firestore-init";
export interface ExternalResourceLockDocument {
isLocked: boolean;
}
export class ExternalResourceLock {
constructor(public readonly collection: string, public readonly docId: string) {
}
async acquireLock() {
const ALREADY_LOCKED = "ALREADY_LOCKED";
const docRef = fdb.collection(this.collection).doc(this.docId);
try {
return await fdb.runTransaction(async t => {
const doc = await t.get(docRef);
const data = (doc.data() as ExternalResourceLockDocument | undefined) ?? {
isLocked: false,
};
if (data.isLocked ?? false) { // we have a fallback here because the document might not
// have had a lock before
throw ALREADY_LOCKED;
} else {
data.isLocked = true;
t.set(docRef, data);
}
return data;
}, { maxAttempts: 10 });
} catch (e) {
if (e === ALREADY_LOCKED) {
console.log(`ExternalResourceLock: already locked: ${this.collection}/${this.docId}`);
} else {
console.error(e);
throw e;
}
}
return null;
}
async releaseLock() {
const docRef = fdb.collection(this.collection).doc(this.docId);
const newDoc : ExternalResourceLockDocument = { isLocked: false };
await docRef.set(newDoc);
}
async isLocked() {
const doc = await fdb.collection(this.collection).doc(this.docId).get();
return (doc.data() as ExternalResourceLockDocument | undefined)?.isLocked ?? false;
}
/**
* Just for testing purposes, you should not need to use this.
* Deletes the document.
*/
async deleteDoc() {
await fdb.collection(this.collection).doc(this.docId).delete();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment