📝 Feature Summary
Implement a 30-minute strict timeout limit for client SSE (Server-Sent Events) connections. Upon reaching the 30-minute threshold, the connection should be safely terminated. Additionally, the system and client must support seamless reconnection to resume the event stream exactly where it left off, utilizing the Last-Event-ID to prevent any loss of monitored events.
🎯 Motivation / Use Case
Currently, SseEmitter instances in WikiStreamService are configured with an infinite timeout (Long.MAX_VALUE). Allowing indefinite connections can lead to stale connections, memory leaks, and excessive resource consumption on the server. Enforcing a 30-minute rotation ensures that "zombie" connections are cleared out. However, to maintain a seamless monitoring experience, users must not lose edits/events during the brief reconnection window.
📋 Implementation Plan
- Update Emitter Timeout: Modify WikiStreamService.subscribe(Principal) to instantiate SseEmitter with a 30-minute timeout (30 * 60 * 1000L) instead of Long.MAX_VALUE.
- Handle Client Disconnect: Ensure the client-side JavaScript listens for the connection closure/timeout event and automatically triggers a reconnection attempt.
- Capture Last Event ID: The client must capture the ID of the last successfully processed RecentChange event.
- Resumption Logic:
- Modify the client's reconnection request to include the Last-Event-ID header.
- Architectural Note: Since the server currently maintains a single global EventSource connection to Wikimedia and broadcasts to all SseEmitter clients, handling individual client catch-ups requires either caching recent events in memory/Redis or allowing clients to fetch missed events via a separate REST endpoint before joining the live stream again.
🛠️ Technical Details
- File to modify: src/main/java/org/qrdlife/wikiconnect/wikimonitor/service/WikiStreamService.java
- Current Code: SseEmitter emitter = new SseEmitter(Long.MAX_VALUE);
- Proposed Code: SseEmitter emitter = new SseEmitter(1800000L); // 30 minutes
- Challenges: Implementing per-user event resumption. The backend must reconcile the global lastEventId with the user's specific Last-Event-ID to replay missed flagged events specifically for that user's active filters.