Topic Overview
Keep-alive vs Long Polling
Compare HTTP keep-alive and long polling techniques for maintaining connections and real-time communication.
HTTP Keep-alive
Keep-alive reuses the same TCP connection for multiple HTTP requests.
Without Keep-alive
Request 1: TCP connection → Request → Response → Close
Request 2: TCP connection → Request → Response → Close
Request 3: TCP connection → Request → Response → Close
Overhead: 3-way handshake for each request
With Keep-alive
TCP connection (established once)
Request 1 → Response 1
Request 2 → Response 2
Request 3 → Response 3
Connection stays open
Benefits: Reuse connection, reduce overhead
Long Polling
Long polling holds HTTP request open until server has data to send.
How Long Polling Works
1. Client sends request
2. Server holds request (doesn't respond immediately)
3. When data available: Server responds
4. Client immediately sends new request
5. Repeat
Use case: Real-time updates when WebSockets not available
Comparison
| Feature | Keep-alive | Long Polling |
|---|---|---|
| Purpose | Reuse connection | Real-time updates |
| Connection | Stays open | Held open until data |
| Overhead | Reduced (reuse) | Higher (held connections) |
| Use case | Multiple requests | Real-time notifications |
| Latency | Request-response | Lower (server push) |
Examples
HTTP Keep-alive
import requests
# Session with keep-alive
session = requests.Session()
# Multiple requests reuse connection
response1 = session.get('https://api.example.com/data1')
response2 = session.get('https://api.example.com/data2')
response3 = session.get('https://api.example.com/data3')
# Connection reused (no new handshake)
Long Polling
import requests
import time
def long_poll(url, timeout=30):
"""Long polling request"""
while True:
try:
# Server holds request until data available
response = requests.get(url, timeout=timeout)
if response.status_code == 200:
data = response.json()
process_data(data)
# Immediately send new request
time.sleep(0.1)
except requests.Timeout:
# Timeout: Send new request
continue
Long Polling Server
from flask import Flask, jsonify
import time
app = Flask(__name__)
@app.route('/poll')
def poll():
"""Long polling endpoint"""
# Wait for data (max 30 seconds)
start_time = time.time()
timeout = 30
while time.time() - start_time < timeout:
# Check if data available
data = check_for_updates()
if data:
return jsonify(data)
time.sleep(0.5) # Check every 0.5 seconds
# Timeout: Return empty response
return jsonify({'status': 'timeout'}), 200
Common Pitfalls
- Keep-alive timeout: Connection closed prematurely. Fix: Configure appropriate timeout
- Long polling connections: Too many held connections. Fix: Limit connections, use timeouts
- Not using keep-alive: Wasting resources. Fix: Enable keep-alive for multiple requests
- Long polling overhead: High server load. Fix: Use WebSockets for better performance
Interview Questions
Beginner
Q: What is HTTP keep-alive and how does it differ from long polling?
A:
HTTP Keep-alive:
Reuses TCP connection for multiple requests:
TCP connection (established once)
Request 1 → Response 1
Request 2 → Response 2
Request 3 → Response 3
Connection stays open
Benefits:
- Reduced overhead: No new handshake per request
- Faster: Reuse existing connection
- Efficient: Multiple requests on one connection
Long Polling:
Holds HTTP request open until data available:
1. Client sends request
2. Server holds request (doesn't respond)
3. When data available: Server responds
4. Client immediately sends new request
Use case: Real-time updates (when WebSockets not available)
Differences:
| Feature | Keep-alive | Long Polling |
|---|---|---|
| Purpose | Reuse connection | Real-time updates |
| Connection | Open for requests | Held until data |
| Overhead | Reduced | Higher |
Intermediate
Q: Explain how long polling works and when you would use it vs WebSockets.
A:
Long Polling Process:
-
Client sends request
GET /updates -
Server holds request
Server doesn't respond immediately Waits for data (up to timeout) -
Data available
Server responds with data -
Client immediately requests again
GET /updates (new request)
Example:
# Client
while True:
response = requests.get('/updates', timeout=30)
if response.status_code == 200:
process(response.data)
# Immediately send new request
Long Polling vs WebSockets:
| Feature | Long Polling | WebSockets |
|---|---|---|
| Protocol | HTTP | WebSocket |
| Connection | HTTP request held | Persistent connection |
| Overhead | Higher (new request each time) | Lower (one connection) |
| Latency | Higher | Lower |
| Complexity | Simpler | More complex |
| Browser support | Universal | Modern browsers |
When to use:
- Long polling: Simple, works everywhere, WebSockets not available
- WebSockets: Real-time, low latency, bidirectional
Senior
Q: Design a system that uses both keep-alive and long polling efficiently. How do you manage connections, handle timeouts, and optimize for performance?
A:
class HybridConnectionSystem {
private keepAliveManager: KeepAliveManager;
private longPollManager: LongPollManager;
constructor() {
this.keepAliveManager = new KeepAliveManager();
this.longPollManager = new LongPollManager();
}
// 1. Keep-alive for Regular Requests
class KeepAliveManager {
private connections: Map<string, Connection>;
async getConnection(host: string): Promise<Connection> {
// Reuse existing connection
if (this.connections.has(host)) {
const conn = this.connections.get(host);
if (conn.isAlive()) {
return conn;
}
}
// Create new connection
const conn = await this.createConnection(host);
this.connections.set(host, conn);
return conn;
}
async request(url: string, options: RequestOptions): Promise<Response> {
const host = this.extractHost(url);
const conn = await this.getConnection(host);
return await conn.request(url, options);
}
}
// 2. Long Polling for Real-time
class LongPollManager {
private polls: Map<string, Poll>;
async poll(endpoint: string, callback: Function): Promise<void> {
while (true) {
try {
const response = await this.longPollRequest(endpoint, {
timeout: 30
});
if (response.data) {
callback(response.data);
}
// Immediately poll again
} catch (error) {
if (error instanceof TimeoutError) {
// Timeout: Poll again
continue;
} else {
// Error: Retry with backoff
await this.retryWithBackoff(endpoint, callback);
}
}
}
}
async longPollRequest(endpoint: string, options: RequestOptions): Promise<Response> {
// Server holds request until data available
return await fetch(endpoint, {
...options,
headers: {
'Connection': 'keep-alive'
}
});
}
}
// 3. Connection Management
optimizeConnections(): void {
// Keep-alive: Reuse connections
// Long polling: Limit concurrent polls
// Timeout management: Close idle connections
}
}
Features:
- Keep-alive: Reuse connections for regular requests
- Long polling: Real-time updates
- Connection management: Optimize, limit, timeout
Key Takeaways
- Keep-alive: Reuse TCP connection for multiple HTTP requests
- Long polling: Hold HTTP request open until data available
- Keep-alive benefits: Reduced overhead, faster, efficient
- Long polling use: Real-time updates when WebSockets not available
- Comparison: Keep-alive for efficiency, long polling for real-time
- Best practices: Use keep-alive for multiple requests, long polling for real-time, consider WebSockets