Batch updates

This commit is contained in:
Milan Paunovic
2024-11-22 09:21:12 +01:00
parent 06a3a2dc8f
commit d091aaa0ee

View File

@ -293,47 +293,152 @@ exports.sendNotificationOnEventCreation = functions.firestore
}
});
// Store batches in Firestore instead of memory
async function addToUpdateBatch(eventData, eventId) {
const batchId = `${eventData.familyId}_${eventData.lastModifiedBy}`;
const batchRef = admin.firestore().collection('UpdateBatches').doc(batchId);
try {
await admin.firestore().runTransaction(async (transaction) => {
const batchDoc = await transaction.get(batchRef);
if (!batchDoc.exists) {
// Create new batch
transaction.set(batchRef, {
familyId: eventData.familyId,
lastModifiedBy: eventData.lastModifiedBy,
externalOrigin: eventData.externalOrigin,
events: [{
id: eventId,
title: eventData.title,
startDate: eventData.startDate
}],
createdAt: admin.firestore.FieldValue.serverTimestamp(),
processed: false
});
} else {
// Update existing batch
const existingEvents = batchDoc.data().events || [];
transaction.update(batchRef, {
events: [...existingEvents, {
id: eventId,
title: eventData.title,
startDate: eventData.startDate
}]
});
}
});
} catch (error) {
console.error('Error adding to update batch:', error);
throw error;
}
}
exports.onEventUpdate = functions.firestore
.document('Events/{eventId}')
.onUpdate(async (change, context) => {
const beforeData = change.before.data();
const afterData = change.after.data();
const {familyId, title, lastModifiedBy} = afterData;
const {familyId, title, lastModifiedBy, externalOrigin, startDate} = afterData;
// Skip if no meaningful changes
if (JSON.stringify(beforeData) === JSON.stringify(afterData)) {
return null;
}
try {
// Get push tokens excluding the user who made the change
const pushTokens = await getPushTokensForFamily(familyId, lastModifiedBy);
const message = `Event "${title}" has been updated`;
await sendNotifications(pushTokens, {
title: "Event Updated",
body: message,
data: {
type: 'event_update',
eventId: context.params.eventId
}
});
// Store notification in Firestore
await storeNotification({
type: 'event_update',
await addToUpdateBatch({
familyId,
content: message,
eventId: context.params.eventId,
excludedUser: lastModifiedBy,
timestamp: admin.firestore.FieldValue.serverTimestamp(),
date: eventData.startDate
});
title,
lastModifiedBy,
externalOrigin,
startDate
}, context.params.eventId);
} catch (error) {
console.error('Error sending event update notification:', error);
console.error('Error in onEventUpdate:', error);
}
});
// Separate function to process batches
exports.processUpdateBatches = functions.pubsub
.schedule('every 1 minutes')
.onRun(async (context) => {
const batchesRef = admin.firestore().collection('UpdateBatches');
// Find unprocessed batches older than 5 seconds
const cutoff = new Date(Date.now() - 5000);
const snapshot = await batchesRef
.where('processed', '==', false)
.where('createdAt', '<=', cutoff)
.get();
const processPromises = snapshot.docs.map(async (doc) => {
const batchData = doc.data();
try {
const pushTokens = await getPushTokensForFamily(
batchData.familyId,
batchData.lastModifiedBy
);
if (pushTokens.length) {
let message;
if (batchData.externalOrigin) {
message = `Calendar sync completed: ${batchData.events.length} events have been updated`;
} else {
message = batchData.events.length === 1
? `Event "${batchData.events[0].title}" has been updated`
: `${batchData.events.length} events have been updated`;
}
await sendNotifications(pushTokens, {
title: batchData.externalOrigin ? "Calendar Sync Complete" : "Events Updated",
body: message,
data: {
type: 'event_update',
count: batchData.events.length
}
});
await storeNotification({
type: 'event_update',
familyId: batchData.familyId,
content: message,
excludedUser: batchData.lastModifiedBy,
timestamp: admin.firestore.FieldValue.serverTimestamp(),
count: batchData.events.length,
date: batchData.events[0].startDate
});
}
// Mark batch as processed
await doc.ref.update({
processed: true,
processedAt: admin.firestore.FieldValue.serverTimestamp()
});
} catch (error) {
console.error(`Error processing batch ${doc.id}:`, error);
}
});
await Promise.all(processPromises);
});
// Cleanup old batches
exports.cleanupUpdateBatches = functions.pubsub
.schedule('every 24 hours')
.onRun(async (context) => {
const batchesRef = admin.firestore().collection('UpdateBatches');
const dayAgo = new Date(Date.now() - 24 * 60 * 60 * 1000);
const oldBatches = await batchesRef
.where('processedAt', '<=', dayAgo)
.get();
const deletePromises = oldBatches.docs.map(doc => doc.ref.delete());
await Promise.all(deletePromises);
});
// Upcoming Event Reminders
exports.checkUpcomingEvents = functions.pubsub
.schedule('every 5 minutes')