Одновременное использование асинхронных задач и пакетных обновленийJavascript

Форум по Javascript
Ответить
Anonymous
 Одновременное использование асинхронных задач и пакетных обновлений

Сообщение Anonymous »

У меня есть нативное приложение React, подключенное к Firestore. Я также использую облачные функции для отправки уведомлений каждому пользователю. Следующий код работает, но недавно я столкнулся с ошибками тайм-аута (даже при тайм-ауте 540 секунд и памяти 512 МБ):

Код: Выделить всё

async function sendNotifications() {
console.log("Sending notifications for recommended events...");

// Fetch all events once
const eventsRef = admin.firestore().collection("Events");
const eventsSnapshot = await eventsRef
.where('Start', '>=', new Date())
.get();

if (eventsSnapshot.empty) {
console.log("No upcoming events found.");
return;
}
const allEvents = eventsSnapshot.docs.map(doc => ({ ...doc.data(), docId: doc.id }));

// Fetch all users
const usersRef = admin.firestore().collection("Users");
const usersSnapshot = await usersRef.get();

let reset = false;

for (const userDoc of usersSnapshot.docs) {
try {
const userData = userDoc.data();
const { fcmToken, preferences, language = "en", sentNotifications = [] } = userData;

if (!fcmToken) continue; // Skip users without FCM token
const userPreferredTags = preferences ? preferences : [];
let eventToSend = findEventForUser(allEvents, userPreferredTags, sentNotifications);

// Fallback logic: No matching events, or user has no preferences
if (!eventToSend) {
eventToSend = findBangerEvent(allEvents, sentNotifications);
}
if (!eventToSend && sentNotifications.length > 0) {
console.log(`No new events to suggest, resetting`);
eventToSend = sentNotifications[sentNotifications.length - 1];
reset = true;
}

if (!eventToSend) {
console.log(`No events to send for user ${userDoc.id}.  Skipping.`);
continue;
}

const notificationPayload = createNotificationPayload(
eventToSend,
fcmToken,
language
);
await admin.messaging().send(notificationPayload);
console.log(`Successfully sent message to user ${userDoc.id}, ${notificationPayload.notification.title}`);

const updatedNotifications = updateSentNotifications(eventToSend, reset ? [] : sentNotifications);
await userDoc.ref.update({ sentNotifications: updatedNotifications });

} catch (error) {
console.error(`Error processing user ${userDoc.id}:`, error);
}
}

console.log("Notifications sent successfully.");
}
Поэтому я перешел на асинхронные функции, чтобы иметь возможность обрабатывать пользователей одновременно, но, если я правильно понял, также рекомендуется группировать обновления userDoc в Firestore и сообщения FCM с помощью sendEach( ).
Я попробовал это на эмуляторе Firebase, используя следующий код:

Код: Выделить всё

async function sendNotifications() {
console.log("Sending notifications for recommended events...");

// Fetch all events once
const eventsRef = admin.firestore().collection("Events");
const eventsSnapshot = await eventsRef
.where('Start', '>=', new Date())
.get();

if (eventsSnapshot.empty) {
console.log("No upcoming events found.");
return;
}
const allEvents = eventsSnapshot.docs.map(doc => ({ ...doc.data(), docId: doc.id }));

// Fetch all users
const usersRef = admin.firestore().collection("Users");
const usersSnapshot = await usersRef.get();

const usersToProcess = usersSnapshot.docs.filter(userDoc => {
const userData = userDoc.data();
return true; // Include all users with an FCM token (set to true in emulator)
});

console.log(`Processing ${usersToProcess.length} users...`);

const notifications = [];
let batch = admin.firestore().batch();
let batchUserCount = 0; // Track the number of users in the current batch

const userPromises = usersToProcess.map(async (userDoc) => {
const userData = userDoc.data();
const { fcmToken, preferences, language = "en", sentNotifications = [] } = userData;

const userPreferredTags = preferences || [];
let eventToSend = findEventForUser(allEvents, userPreferredTags, sentNotifications);

// Fallback logic: No matching events
if (!eventToSend) {
eventToSend = findBangerEvent(allEvents, sentNotifications) ||
sentNotifications[sentNotifications.length - 1];
}

if (!eventToSend) {
console.log(`No events to send for user ${userDoc.id}.  Skipping.`);
return;
}

const notificationPayload = createNotificationPayload(eventToSend, fcmToken ? fcmToken : "ezeazea", language);
notifications.push(notificationPayload);

const updatedNotifications = updateSentNotifications(eventToSend, sentNotifications);
const dataSize = JSON.stringify({ sentNotifications: updatedNotifications }).length;
console.log(`Estimated size of update: ${dataSize} bytes`);

batch.update(userDoc.ref, { sentNotifications: updatedNotifications });
batchUserCount++;

// If the batch has 100 operations, commit the batch and start a new one
if (batchUserCount === 100) {
console.log("Committing Firestore batch...");
await batch.commit(); // Commit the batch
batch = admin.firestore().batch(); // Create a new batch
batchUserCount = 0; // Reset the batch user count
}
});

await Promise.all(userPromises);

// Commit remaining updates if any users were left in the batch
if (batchUserCount > 0) {
console.log("Committing remaining Firestore batch...");
await batch.commit();
}

// Send notifications in bulk (in batches of 100)
console.log("Sending notifications in bulk...");
while (notifications.length) {
const batchNotifications = notifications.splice(0, 100); // Firebase max batch size for FCM
try {
await admin.messaging().sendEach(batchNotifications);
} catch (error) {
console.error("Error sending notifications:", error);
// Handle the error as necessary
}
}

console.log("Notifications sent successfully.");
}
Но похоже, что асинхронная обработка пользователей конфликтует с пакетной обработкой, поскольку при втором вызове фиксации я получаю следующую ошибку:

⚠ функции: Ошибка: невозможно изменить зафиксированный WriteBatch.


Подробнее здесь: https://stackoverflow.com/questions/793 ... -same-time
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «Javascript»