doodle
Val Town is a collaborative website to build and scale JavaScript apps.
Deploy APIs, crons, & store data – all from the browser, and deployed in milliseconds.
Viewing readonly version of main branch: v53View latest version
- 1.8k reads/hour during development (higher than optimal)
- Main causes: Auto-refresh intervals + No caching + Inefficient queries
- Admin page: Refreshes every 5 seconds
- Answer page: Refreshes every 10 seconds
- Each refresh triggers multiple Redis operations
GET /events/:id
recalculates stats on every request- Uses
redis.keys()
pattern matching (expensive operation) - Fetches all answers for the event every time
- No caching of computed results
- Multiple endpoints read the same event data without caching
- Event validation happens on every answer submission
// Admin page (admin.http.ts)
setInterval(loadEvent, 30000); // Change from 5000 to 30000
// Answer page (answer.http.ts)
setInterval(loadEvent, 30000); // Change from 10000 to 30000
setInterval(() => {
if (document.visibilityState === 'visible') {
loadEvent();
}
}, 30000);
Store pre-calculated stats with TTL:
// After calculating stats in GET /events/:id
await redis.setex(`event:${id}:stats`, 300, JSON.stringify({
name: event.name,
options: event.options,
stats,
answers_by_option: answersByOption,
total_participants: participants.size,
}));
// When creating/updating answer
await redis.sadd(`event:${id}:participants`, person_name);
// When fetching (instead of redis.keys)
const participants = await redis.smembers(`event:${id}:participants`);
Update statistics when answers change rather than recalculating:
// When answer is submitted/updated
await redis.hincrby(`event:${id}:stats`, option, 1);
await redis.hincrby(`event:${id}:stats`, `${oldOption}`, -1);
Cache frequently accessed data with short TTL in the API layer.
- 60-80% reduction in Redis reads
- From ~1,800 reads/hour to ~300-500 reads/hour
- Improved response times for stats-heavy endpoints
- Better scalability for events with many participants
- ✅ Reduce auto-refresh intervals (5 min work)
- ✅ Add visibility-based polling (10 min work)
- ⏳ Cache computed statistics (30 min work)
- ⏳ Replace redis.keys() with Sets (1 hour work)
- ⏳ Implement incremental stats (2 hours work)
After implementing optimizations, monitor:
- Redis read/write operations per hour
- Response times for GET /events/:id
- User experience impact (any delays in updates?)