Node.js and Redis: Handling Expired Keys Without Blocking Calls in Express
I'm sure I'm missing something obvious here, but I've tried everything I can think of but I'm trying to figure out I'm working on a personal project and I'm using Node.js with Express and Redis to cache API responses....... The problem arises when I try to check if a cached key has expired before sending a response to the client. When the key is expired, my logic attempts to fetch fresh data and cache it again. However, I've noticed that my server hangs occasionally when many requests try to access the same key simultaneously. This happens with the following code: ```javascript const express = require('express'); const redis = require('redis'); const { promisify } = require('util'); const app = express(); const client = redis.createClient(); const getAsync = promisify(client.get).bind(client); app.get('/data/:id', async (req, res) => { const cacheKey = `data:${req.params.id}`; try { const cachedData = await getAsync(cacheKey); if (cachedData) { return res.json(JSON.parse(cachedData)); } // Simulate fetching fresh data const freshData = await fetchDataFromDatabase(req.params.id); client.setex(cacheKey, 3600, JSON.stringify(freshData)); return res.json(freshData); } catch (error) { console.error('Error fetching data:', error); return res.status(500).send('Internal Server Error'); } }); const fetchDataFromDatabase = async (id) => { // Simulating a database fetch that might take time return new Promise((resolve) => setTimeout(() => resolve({ id, data: 'Some data' }), 2000)); }; app.listen(3000, () => { console.log('Server is running on port 3000'); }); ``` I tried using a mutex pattern to ensure that only one request processes the cache miss at a time, but it seemed overly complicated and introduced more latency. Additionally, I noticed that if many requests hit the endpoint while the first one is fetching fresh data, they all hang until the first request is completed. Is there a more efficient way to handle this, perhaps with a queue or using `Promise.allSettled` to avoid blocking? How can I improve this implementation to handle high concurrency without the server hanging? I'm developing on CentOS with Javascript. How would you solve this? I recently upgraded to Javascript latest. What's the correct way to implement this? I'm on macOS using the latest version of Javascript. The project is a CLI tool built with Javascript. What am I doing wrong?