Created
December 5, 2019 02:24
-
-
Save CodingDoug/83bdd8c00dc64b22472f618e26fe5ca3 to your computer and use it in GitHub Desktop.
Revisions
-
CodingDoug created this gist
Dec 5, 2019 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,2 @@ This is the full Cloud Functions code explained in my blog post: [How to schedule a Cloud Function to run in the future (in order to build a Firestore document TTL)](https://medium.com/@CodingDoug/754f9bf3214a?source=friends_link&sk=8abac7a34db444023e84787c4cc62ee8) This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,99 @@ import * as functions from 'firebase-functions' import * as admin from 'firebase-admin' const { CloudTasksClient } = require('@google-cloud/tasks') admin.initializeApp() // Payload of JSON data to send to Cloud Tasks, will be received by the HTTP callback interface ExpirationTaskPayload { docPath: string } // Description of document data that contains optional fields for expiration interface ExpiringDocumentData extends admin.firestore.DocumentData { expiresIn?: number expiresAt?: admin.firestore.Timestamp expirationTask?: string } export const onCreatePost = functions.firestore.document('/posts/{id}').onCreate(async snapshot => { const data = snapshot.data()! as ExpiringDocumentData const { expiresIn, expiresAt } = data let expirationAtSeconds: number | undefined if (expiresIn && expiresIn > 0) { expirationAtSeconds = Date.now() / 1000 + expiresIn } else if (expiresAt) { expirationAtSeconds = expiresAt.seconds } if (!expirationAtSeconds) { // No expiration set on this document, nothing to do return } // Get the project ID from the FIREBASE_CONFIG env var const project = JSON.parse(process.env.FIREBASE_CONFIG!).projectId const location = 'us-central1' const queue = 'firestore-ttl' const tasksClient = new CloudTasksClient() const queuePath: string = tasksClient.queuePath(project, location, queue) const url = `https://${location}-${project}.cloudfunctions.net/firestoreTtlCallback` const docPath = snapshot.ref.path const payload: ExpirationTaskPayload = { docPath } const task = { httpRequest: { httpMethod: 'POST', url, body: Buffer.from(JSON.stringify(payload)).toString('base64'), headers: { 'Content-Type': 'application/json', }, }, scheduleTime: { seconds: expirationAtSeconds } } const [ response ] = await tasksClient.createTask({ parent: queuePath, task }) const expirationTask = response.name const update: ExpiringDocumentData = { expirationTask } await snapshot.ref.update(update) }) export const firestoreTtlCallback = functions.https.onRequest(async (req, res) => { const payload = req.body as ExpirationTaskPayload try { await admin.firestore().doc(payload.docPath).delete() res.send(200) } catch (error) { console.error(error) res.status(500).send(error) } }) export const onUpdatePostCancelExpirationTask = functions.firestore.document('/posts/{id}').onUpdate(async change => { const before = change.before.data() as ExpiringDocumentData const after = change.after.data() as ExpiringDocumentData // Did the document lose its expiration? const expirationTask = after.expirationTask const removedExpiresAt = before.expiresAt && !after.expiresAt const removedExpiresIn = before.expiresIn && !after.expiresIn if (expirationTask && (removedExpiresAt || removedExpiresIn)) { const tasksClient = new CloudTasksClient() await tasksClient.deleteTask({ name: expirationTask }) await change.after.ref.update({ expirationTask: admin.firestore.FieldValue.delete() }) } })