Real-Time Code Execution Architecture: Redis & WebSockets vs Polling

Som palkarSom palkar
3 min read

In modern coding challenge platforms, users expect instant feedback on their submissions. The traditional polling model—where the browser repeatedly asks “are you done yet?”—simply can’t keep up with this demand. Polling means extra HTTP requests and delays; every request usually says “still running” until it’s done. Instead, we can move to a push-based system using Redis and WebSockets for real-time updates.

  • Polling is inefficient: In a polling system, the client might send a status request every second. That can mean thousands of needless requests if code takes time to finish. This wastes bandwidth and server CPU. If the polling interval is too long, the user sees lag (maybe seconds) before getting the final result. If it’s too short, the server is flooded with frequent checks. In either case, the system doesn’t scale well under heavy use.

  • Redis Pub/Sub + WebSockets = real-time push: In our architecture, the backend and worker processes use Redis Pub/Sub channels to broadcast status updates, and the browser uses a WebSocket connection to listen. When you submit code, the job is queued in Redis. The worker pulls the job and starts execution. As soon as the worker has any status (started, running, or a result like TLE), it publishes a message on Redis. The server, which has an open WebSocket to your browser, immediately receives it and pushes it through the WebSocket. This way, updates flow in real time without the client having to poll.

  • Instant status updates (e.g. TLE): Suppose a code run exceeds its time limit. The worker detects the TLE and instantly publishes a “TLE” status on the Redis channel for that job ID. Because the server is subscribed to this channel, it immediately receives the message and sends a WebSocket event to the browser. The user interface can show “Time Limit Exceeded” right away. Similarly, if the code completes successfully, the worker publishes a “success” message, and the client gets it at once. The result: feedback appears the moment it’s available.

  • Worker threads and job queue: The workflow is: browser → primary backend → Redis queue → worker → Redis Pub/Sub → browser. The primary backend enqueues your code execution request into a Redis list or stream. Worker processes (W1, W2, …) block on this queue and pop a job when it’s available. Each worker runs the code in a sandbox, then uses Redis Pub/Sub to publish status updates and final results. Since Redis decouples the queue from the pub/sub channels, we can horizontally scale by adding more workers without changing the client logic.

  • Benefits: reliability, real-time feedback, cleaner architecture: This design greatly improves user experience and system performance. Users see progress or final results instantly, without waiting for a poll. The client-side code is simpler (just one WebSocket listener) and doesn’t waste CPU/time on polling timers. The server handles far fewer redundant HTTP calls. Redis ensures jobs aren’t lost if a worker crashes, and pub/sub means any number of services can listen for updates. Overall, it delivers a snappier, more reliable code-running experience.

Key takeaways: By replacing polling with Redis Pub/Sub and WebSockets, we get instant feedback and better scalability. The result is a more responsive and reliable code execution platform that developers love.

0
Subscribe to my newsletter

Read articles from Som palkar directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Som palkar
Som palkar