Short Polling
The simplest approach
Short polling is a loop: the client sends a request, processes the response, waits, and repeats. No special server support needed — any REST endpoint works.
The polling endpoint
Add a since parameter so the client only gets tasks updated after its last check:
route.get("/boards/:boardId/updates", {
resolve: (c) => {
const since = new URL(c.request.url).searchParams.get("since");
let tasks;
if (since) {
tasks = db
.prepare(
"SELECT t.* FROM tasks t JOIN lists l ON t.list_id = l.id WHERE l.board_id = ? AND t.updated_at > ? ORDER BY t.updated_at",
)
.all(c.params.boardId, since);
} else {
tasks = db
.prepare(
"SELECT t.* FROM tasks t JOIN lists l ON t.list_id = l.id WHERE l.board_id = ? ORDER BY l.position, t.position",
)
.all(c.params.boardId);
}
return Response.json({
data: tasks,
timestamp: new Date().toISOString(),
});
},
}); The response includes a timestamp the client uses for the next poll.
The client
// Client-side
let lastTimestamp: string | null = null;
async function poll() {
const url = lastTimestamp
? `/boards/board-1/updates?since=${encodeURIComponent(lastTimestamp)}`
: `/boards/board-1/updates`;
const res = await fetch(url);
const { data, timestamp } = await res.json();
lastTimestamp = timestamp;
if (data.length > 0) {
updateUI(data);
}
}
// Poll every 5 seconds
setInterval(poll, 5000);
poll(); // Initial fetch The waste problem
With 50 users polling every 5 seconds, the server handles 600 requests per minute. If nothing changed in the last hour, all 36,000 responses were empty.
# Simulate polling — most responses will be empty
for i in {1..10}; do
curl -s "http://localhost:3000/boards/board-1/updates?since=2099-01-01T00:00:00Z" | jq '.data | length'
sleep 1
done
# Output: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 Ten requests. Zero useful results. This is the fundamental waste of polling.
When short polling is acceptable
Low-frequency updates. Checking for new email every 60 seconds. Refreshing a dashboard every 5 minutes. The update frequency matches the data change rate.
Few clients. An internal tool with 5 users polling every 10 seconds is 30 requests per minute. Negligible.
No persistent connection support. Some environments (serverless, restrictive proxies) cannot hold long-lived connections. Polling is the only option.
As a fallback. When SSE and WebSockets fail, polling always works.
Exercises
Exercise 1: Implement the polling endpoint. Start the server. Open two terminals: one polls, the other creates tasks. Verify the polling terminal picks up new tasks.
Exercise 2: Measure how many empty responses you get over 60 seconds of polling at 3-second intervals with no changes.
Exercise 3: Adjust the polling interval to 30 seconds. How does the experience change? (Answer: updates feel delayed. There is always a tradeoff between latency and resource usage with polling.)
What determines the right polling interval?