Long Polling & Server-Sent Events (SSE)
debt(d7/e5/b5/t5)
Closest to 'only careful code review or runtime testing' (d7). The detection_hints indicate no automated detection is available — the code pattern (JavaScript polling every second with Ajax, PHP holding connections open) requires a human reviewer to recognize the architectural anti-pattern, or profiling under load to see connection exhaustion. No tools in detection_hints.tools catch this automatically.
Closest to 'touches multiple files / significant refactor in one component' (e5). The quick_fix points to replacing long polling with SSE, but this is not a one-line swap — it requires changing both the server-side PHP to emit SSE headers and the client-side JavaScript reconnect loop, plus addressing timeout handling and duplicate-event tracking across both layers. Multiple files and paradigm shift within the realtime component.
Closest to 'persistent productivity tax' (b5). Long polling applies to web contexts and any realtime feature built on it carries ongoing maintenance cost: every developer touching the connection management, timeout logic, reconnect loop, and deduplication pays a tax. It doesn't define the entire system's shape (not b7) but it persistently complicates any feature that uses it.
Closest to 'notable trap (a documented gotcha most devs eventually learn)' (t5). The misconception field explicitly states that developers treat long polling and WebSockets as equivalent for real-time data, not realizing each long-poll message incurs full connection overhead and requires client-side reconnection. Common mistakes reinforce this — forgetting server-side timeouts and the reconnect loop are well-known but frequently hit pitfalls.
Also Known As
TL;DR
Explanation
Long polling: the client makes a request, the server holds it open (sleeping/waiting) until new data is available or a timeout occurs, then responds and the client immediately reconnects. Simple to implement in PHP but holds a PHP-FPM worker for the duration — inefficient under load. Server-Sent Events (SSE): the server sends a text/event-stream response and pushes data: payloads down over a persistent connection using ob_flush() and flush(). SSE is one-directional (server to client) and reconnects automatically. Both approaches consume a PHP worker per open connection — for high concurrency, a Node.js/Go push service with Redis Pub/Sub as the backend is more scalable.
Diagram
sequenceDiagram
participant C as Client
participant S as Server
Note over C,S: Long Polling
C->>S: GET /events (holds connection)
Note over S: Waits for event...
S-->>C: Response when event ready
C->>S: Immediately reconnect
Note over C,S: Server-Sent Events (SSE)
C->>S: GET /stream (persistent)
S-->>C: data: event1
S-->>C: data: event2
Note over C,S: WebSocket - full duplex
C->>S: WS upgrade
S-->>C: push anytime
C->>S: send anytime
Common Misconception
Why It Matters
Common Mistakes
- Not setting a server-side timeout — a connection held indefinitely exhausts worker threads.
- Not handling the client reconnect loop — when the server responds, the client must immediately re-poll.
- Using long polling when WebSockets or SSE are available and more efficient for the use case.
- Not tracking which clients are waiting and what data they have already seen — sending duplicate events.
Code Examples
// Long poll without timeout — holds worker indefinitely:
set_time_limit(0); // Dangerous — worker never freed
while (true) {
$events = getNewEvents($lastId);
if (!empty($events)) { echo json_encode($events); exit; }
sleep(1);
}
// Fix: set_time_limit(30); respond with empty after timeout so client reconnects
// SSE in PHP
header('Content-Type: text/event-stream');
header('Cache-Control: no-cache');
while (true) {
echo 'data: ' . json_encode(getUpdate()) . "\n\n";
ob_flush(); flush();
sleep(1);
}