En algunas skills, como mi Baúl de Noticias, se utiliza almacenamiento intermedio que no necesita estar en Base de datos.

Baúl de Noticias lee artículos de varios RSS, que se generan en https://blaya.club/NewsChest utilizando WordPress. Os voy a contar cómo la solución ha evolucionado desde la más básica hasta la actual con la que estoy bastante contento.

Solución inicial:

Cada vez que un usuario solicita leer un artículo, se hace una llamada GET a la URL donde se encuentra la RSS. El problema es que el rendimiento no es bueno (el tiempo de respuesta estaba entre 1 y 2 segundos) y el tráfico de datos puede ser significativo (el RSS generado por WordPress tiene unos 25Kb)

Solución mejorada:

Dentro de una misma sesión, el usuario puede leer varios artículos, así que la primer mejora fue leer la RSS sólo una vez al principio de la sesión y guardarla como parte de la estructura session.attributes. Ver este post en donde se explica cómo hacerlo.

El problema aquí era que los 25Kb, aunque se leían solo una vez de la RSS externa, viajaban mucho entre AWS y el servidor de las skills, haciendo que el rendimiento no fuese bueno y que además saltase la alarma del free-tier  (Amazon iba a empezar a cobrarme por el tráfico de datos)

Solución optimizada:

El contenido de la RSS se almacena en AWS S3 y se refresca cada hora. Cómo?

La función Lambda accede a S3 y comprueba la hora de actualización

Si fué actualizada hace más de una hora, se lee la RSS externa y se remplaza

Si fué hace menos de una hora, se lee el contenido del objeto S3.

Esto hace que solamente se acceda a la RSS externa una vez por hora como mucho (esa sigue tardando entre 1 y dos segundos). Además no se tiene por qué guardar la RSS en session.attributes con lo que disminuye el consumo de memoria y los accesos a DynamoDB.

El tiempo de respuesta que tengo así es de entre 200 y 500 msegs.

Os paso el código que está funcionando – perdón por la indentación.


var objectID = (host+path).replace(/\//g,'-') + '.xml';
s3.headObject( {Bucket: bucket, Key: objectID}, function(err, data) {
var body='';
if( (err && err.code === 'NotFound')
|| (data && (((Date.now()-    Date.parse(data.LastModified))/(60*1000)) > 60) ) )
{
feed.get( {'host': host, 'path': path}, function(res) {
res.on( 'data', function (chunk) {
body += chunk;
});
res.on( 'end', function () {
s3.upload({Bucket: bucket, Key: objectID, Body: body},  function(err, data) {
if (err)
console.log("Error uploading data: ", err);
else
console.log("Uploaded: " + body.length + " bytes");
});
});
});
}
else {
s3.getObject( {Bucket: newschestBucket, Key: objectID}, function(err,data) {
if( err )
console.log( "Error: " + err );
if( data )
body = data.Body.toString('utf-8');
});
}
});