Sugerencias y trucos

Este documento describe las recomendaciones para diseñar, implementar y probar Cloud Functions.

Precisión

Esta sección describe las recomendaciones generales para diseñar y también implementar Cloud Functions.

Escribir funciones idempotentes

Tus funciones deben producir el mismo resultado, incluso si se llaman varias veces. Esto te permite volver a intentar una invocación si la anterior falla a mitad de camino en el código. Para obtener más información, consulta cómo volver a intentar ejecutar funciones en segundo plano.

Borra los archivos temporales siempre

El almacenamiento en el directorio temporal del disco local es un sistema de archivos en la memoria. Todos los archivos que escribes consumen memoria disponible en tu función. Por lo general, los archivos que escribes están disponibles en invocaciones consecutivas y, por lo tanto, no borrar estos archivos podría generar un error por falta de memoria y un posterior inicio en frío.

Para ver la memoria que usa una función individual, selecciónala en la lista de funciones de la Consola de API y elige el gráfico "Uso de memoria".

No intentes escribir fuera del directorio temporal. Además, usa métodos que no dependan de la plataforma, como os.tmpdir() y path.join(), para construir la ruta de archivos temporal, de manera que tus funciones también se ejecuten correctamente en el emulador en cualquier plataforma.

Para evitar el problema de crear archivos temporales, puedes usar la canalización. Por ejemplo, para procesar un archivo en Cloud Storage, puedes crear un flujo de lectura, pasarlo a través de una canalización con ajuste de escala de sharp y escribir directamente de vuelta en Cloud Storage con un flujo de escritura. Para ver detalles, consulta cómo cambiar el tamaño de una imagen con Node.js Stream y Sharp.

Herramientas

Esta sección proporciona lineamientos sobre cómo usar herramientas para implementar, probar y también interactuar con Cloud Functions.

Usar herramientas existentes

La implementación de funciones tarda un momento, por lo que suele ser más rápido probar el código de tu función de manera local con el Emulador de Cloud Functions de código abierto.

Por último, prueba usar módulos populares existentes en lugar de crear unos propios.

Usa Sendgrid para enviar correos electrónicos

Cloud Functions no permite conexiones salientes en el puerto 25, por lo que no puedes establecer conexiones no seguras a un servidor SMTP. Para enviar correos electrónicos, se recomienda usar SendGrid. Puedes encontrar un ejemplo completo en el Instructivo de SendGrid y otras opciones para enviar correos electrónicos en el documento de Google Compute Engine Cómo enviar correos electrónicos desde una instancia.

Rendimiento

Esta sección describe las recomendaciones para optimizar el rendimiento.

Minimizar las dependencias

Debido a que las funciones no tienen estado y el entorno de ejecución suele inicializarse desde cero (durante lo que se conoce como inicio en frío), el contexto global de la función se evalúa.

Si tus funciones especifican paquetes independientes con require(), el tiempo de carga de esos paquetes se suma a la latencia de invocación durante un inicio en frío. Para reducir esta latencia y el tiempo de implementación de la función, minimiza la cantidad de dependencias que carga tu función.

Usa variables globales para volver a usar objetos en invocaciones futuras

No se garantiza que el estado de una función de Cloud Functions se conserve para las invocaciones futuras. Sin embargo, Cloud Functions suele reciclar el entorno de ejecución de una invocación previa. Si declaras una variable en alcance global, su valor se puede volver a usar en invocaciones posteriores sin tener que volver a procesarse.

De esta manera, puedes almacenar objetos en la caché, ya que volver a crearlos en cada invocación de la función puede ser costoso. Mover estos objetos desde el cuerpo de la función al alcance global puede generar importantes mejoras en el rendimiento. El siguiente ejemplo crea un objeto pesado solo una vez por instancia de la función y lo comparte en todas las invocaciones de la función que alcanzan la instancia determinada:

console.log('Global scope');
const perInstance = heavyComputation();
const functions = require('firebase-functions');

exports.function = functions.https.onRequest((req, res) => {
    console.log('Function invocation');
    const perFunction = lightweightComputation();

    res.send(`Per instance: ${perInstance}, per function: ${perFunction}`);
});

Es especialmente importante almacenar en caché las conexiones de red, las referencias de la biblioteca y los clientes de la API en alcance global. Consulta cómo optimizar las herramientas de redes para ver ejemplos.

Haz una inicialización diferida de las variables globales

Si inicializas variables en alcance global, el código de inicialización se ejecutará siempre a través de una invocación de inicio en frío, lo que aumenta su latencia. Si algunos objetos no se usan en todas las rutas del código, te recomendamos inicializarlas de forma diferida según demanda:

const functions = require('firebase-functions');
let myCostlyVariable;

exports.function = functions.https.onRequest((req, res) => {
    doUsualWork();
    if(unlikelyCondition()){
        myCostlyVariable = myCostlyVariable || buildCostlyVariable();
    }
    res.status(200).send('OK');
});

Esto es especialmente importante si defines varias funciones en un solo archivo y si varias funciones usan variables diferentes. A menos que uses la inicialización diferida, puedes perder recursos si inicializas variables que luego nunca se usarán.

Enviar comentarios sobre…

¿Necesitas ayuda? Visita nuestra página de asistencia.