Tengo una función en la nube de Google que envía notificaciones a un tema de Firebase. La función funcionaba bien hasta que, de repente, comenzó a enviar más de una notificación 2 o 3 al mismo tiempo. Después de contactar al equipo de soporte de Firebase, me dijeron que debería hacer la función Idempotent , pero no sé cómo, ya que es una función invocable. para más detalles, esta es una pregunta de referencia que contiene más detalles sobre el caso . a continuación se muestra el código de la función.
const functions = require("firebase-functions"); // The Firebase Admin SDK to access Firestore. const admin = require("firebase-admin"); const {getMessaging} = require("firebase-admin/messaging"); const serviceAccount = require("./serviceAccountKey.json"); admin.initializeApp({ credential: admin.credential.cert(serviceAccount), databaseURL: "https://mylinktodatabase.firebaseio.com", }); exports.callNotification = functions.https.onCall( (data) => { // Grab the text parameter. const indicator = data.indicator; const mTitle = data.title; const mBody = data.body; // topic to send to const topic = "mytopic"; const options = { "priority": "high", "timeToLive": 3600, }; let message; if (indicator != null ) { message = { data: { ind: indicator, }, }; } else { message = { data: { title: mTitle, body: mBody, }, }; } // Send a message to devices subscribed to the provided topic. return getMessaging().sendToTopic(topic, message, options) .then(() => { if (indicator != null ) { console.log("Successfully sent message"); return { result: "Successfully sent message", status: 200}; } else { console.log("Successfully sent custom"); return { result: "Successfully sent custom", status: 200}; } }) .catch((error) => { if (indicator != null ) { console.log("Error sending message:", error); return {result: `Error sending message: ${error}`, status: 500}; } else { console.log("Error sending custom:", error); return {result: `Error sending custom: ${error}`, status: 500}; } }); });En este blog, Cloud Functions pro tips: Building idempotent functions , muestra cómo hacer una función idempotente usando dos enfoques:
Usa tus ID de evento
Una forma de solucionar esto es utilizar el Id. de evento, un número que identifica de forma única un evento que activa una función en segundo plano y, esto es importante, permanece sin cambios entre los reintentos de función para el mismo evento.
Para usar un ID de evento para resolver el problema de los duplicados, lo primero es extraerlo del contexto del evento al que se accede a través de los parámetros de la función . Luego, utilizamos el ID de evento como ID de documento y escribimos el contenido del documento en Cloud Firestore. De esta manera, la ejecución de una función reintentada no crea un nuevo documento, simplemente anula el existente con el mismo contenido. De manera similar, algunas API externas (por ejemplo, Stripe ) aceptan una clave de idempotencia para evitar la duplicación de datos o trabajo. Si depende de una API de este tipo, simplemente proporcione el ID del evento como su clave de idempotencia.
Una nueva concesión en los reintentos
Si bien este enfoque elimina la gran mayoría de las llamadas duplicadas en los reintentos de función, existe una pequeña posibilidad de que dos reintentos de ejecución en paralelo puedan ejecutar la sección crítica más de una vez. Para casi eliminar este problema, puede usar un mecanismo de concesión, que le permite ejecutar exclusivamente la sección no idempotente de la función durante un período de tiempo específico. En este ejemplo, el primer intento de ejecución obtiene la concesión, pero el segundo intento se rechaza porque la concesión todavía está en manos del primer intento. Finalmente, un tercer intento después de que falle el primero vuelve a tomar la concesión y procesa el evento con éxito.
Para aplicar este enfoque a su código, simplemente ejecute una transacción de Cloud Firestore antes de enviar su correo electrónico, verificando si el evento se ha manejado, pero también almacenando el tiempo hasta el cual el intento de ejecución actual tiene derechos exclusivos para enviar el correo electrónico. Se rechazarán otros intentos de ejecución concurrentes hasta que expire el contrato de arrendamiento, eliminando todos los duplicados a todos los efectos.
Además, como se indica en esta otra pregunta :
P: ¿Es necesario hacer que estas funciones onCall sean idempotentes o nunca realizarán reintentos?
R: Las llamadas a las funciones
onCallno se reintentan automáticamente. Depende del código del lado del cliente y del lado del servidor de su aplicación acordar una estrategia de reintento.
Ver también: