functions/garbageCollector.js (44 lines of code) (raw):

/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at https://mozilla.org/MPL/2.0/. */ const functions = require('firebase-functions'); const admin = require('firebase-admin'); async function deleteQueryBatch(db, query, numDeletedAcc = 0) { try { const snapshot = await query.get(); if (snapshot.size === 0) { // When there are no documents left, we are done return numDeletedAcc; } // Delete documents in a batch const batch = db.batch(); snapshot.docs.forEach((doc) => { batch.delete(doc.ref); }); await batch.commit(); return await deleteQueryBatch(db, query, numDeletedAcc + snapshot.size); } catch (error) { console.log(error); return numDeletedAcc; } } /* * Deletes pings and clients older than `dateTo` in batches to allow for some progress in case of function timeout */ async function deleteOldPings(batchSize, dateTo) { const db = admin.firestore(); const pingsQuery = db.collection('pings') .where('addedAt', '<', dateTo) .limit(batchSize); const clientsQuery = db.collection('clients') .where('lastActive', '<', dateTo) .limit(batchSize); const numDeletedPings = await deleteQueryBatch(db, pingsQuery); console.log("Deleted pings: " + numDeletedPings); const numDeletedClients = await deleteQueryBatch(db, clientsQuery); console.log("Deleted clients: " + numDeletedClients); } const runtimeOpts = { timeoutSeconds: 540, } /** * Removes old pings and inactive clients. * * Deletes pings and client entries updated earlier than 21 days before the calling event was scheduled. * Runs every day at 8:00 UTC */ exports.removeOutdatedPings = functions.runWith(runtimeOpts).pubsub.schedule('0 8 * * *') .timeZone('UTC') .onRun((context) => { let scheduleDate = new Date(context.timestamp); scheduleDate.setDate(scheduleDate.getDate() - 21); const deletionThresholdDate = scheduleDate.toISOString(); console.log(`Triggered on: ${context.timestamp}, deleting documents older than: ${deletionThresholdDate}`); return deleteOldPings(100, deletionThresholdDate); });