Proyecto final: un cliente que aguanta un backend lento
Junta lo del bloque en un solo cliente: caché LRU, timeout con AbortController y reintentos con espera creciente.
Combina los 6 ejercicios del bloque Fiabilidad. Se desbloquea al terminarlos, pero puedes intentarlo ya.
Escribe createClient({ fetchImpl, retries, baseMs, timeoutMs, cacheSize }), que devuelve un objeto con get(key). Es el envoltorio que pondrías delante de cualquier servicio lento, un modelo local incluido.
1. Si key está en la caché, devuelve su valor sin llamar a fetchImpl y márcala como usada ahora.
2. Si no, llama a fetchImpl(key, { signal }) con un AbortController que aborta a los timeoutMs. Un corte por tiempo se convierte en un Error con name igual a 'TimeoutError'.
3. Ante cualquier fallo (también un timeout), espera sleep(baseMs * 2 ** intento) y repite, como mucho retries veces; después lanza el último error.
4. Guarda el valor. Si la caché pasa de cacheSize claves, descarta la usada hace más tiempo. Los errores no se guardan.
fakeBackend({ failures, ms, slowKeys }) imita el servicio y cuenta llamadas en window.__calls y cortes en window.__aborted; sleep(ms) anota cada espera.
Retos 0/6
- Devuelve el valor del backend
- La segunda petición de la misma clave sale de la caché
- Reintenta los fallos esperando 100 y 200 ms
- Corta lo que tarda demasiado con un TimeoutError, también al reintentar
- Con cacheSize 2 descarta la clave usada hace más tiempo
- No guarda los errores en la caché
function createClient({ fetchImpl, retries = 2, baseMs = 100, timeoutMs = 1000, cacheSize = 50 }) {
const cache = new Map(); // un Map conserva el orden de inserción: su primera clave es la usada hace más tiempo
return {
async get(key) {
// 1. acierto de caché: lleva la clave al final y devuelve su valor sin llamar a fetchImpl
// 2. llama a fetchImpl(key, { signal }) con un AbortController que aborta a los timeoutMs (un Error con name 'TimeoutError')
// 3. reintenta cualquier fallo con sleep(baseMs * 2 ** intento), como mucho `retries` veces, y después lanza el último error
// 4. guarda el valor y descarta la clave más antigua si hay más de cacheSize
return null;
},
};
}
const client = createClient({ fetchImpl: fakeBackend({ failures: 1 }), baseMs: 10 });
client.get('llama3.1:8b').then(console.log, (e) => console.error(e.message));Para profundizar: la referencia de AWS (en inglés) →
¿Esto en producción, con tus datos? Hablemos 15 minutos →